Below are patches to zip and unzip that will allow administrators to restore extended attributes. I understand star already does this, but this gives administrators another option. Usage: zip Will store extended attributes in the archive file by default unless the existing option: "-X eXclude eXtra file attributes" is used. unzip Will NOT restore extended attributes by default. Will only restore extended attributes if used with the new option: "-E restore extended attributes". The new -E option can only be used in conjunction with the existing: "-X restore UID/GID info" option. Users can still choose to restore only the UID/GID info with the existing '-X' option. Please send me any feedback. Thanks, debora diff -urpN zip-2.3.orig/unix/Makefile zip-2.3/unix/Makefile --- zip-2.3.orig/unix/Makefile 2005-10-10 13:55:45.000000000 -0500 +++ zip-2.3/unix/Makefile 2005-10-24 15:38:44.000000000 -0500 @@ -59,7 +59,7 @@ OBJN = zipnote.o $(OBJU) OBJC = zipcloak.o $(OBJU) crctab.o crypt_.o ttyio.o OBJS = zipsplit.o $(OBJU) -ZIP_H = zip.h ziperr.h tailor.h unix/osdep.h +ZIP_H = zip.h ziperr.h tailor.h unix/osdep.h unix/xattr.h # suffix rules .SUFFIXES: diff -urpN zip-2.3.orig/unix/unix.c zip-2.3/unix/unix.c --- zip-2.3.orig/unix/unix.c 2005-10-10 13:55:45.000000000 -0500 +++ zip-2.3/unix/unix.c 2005-10-24 15:38:44.000000000 -0500 @@ -11,6 +11,7 @@ #ifndef UTIL /* the companion #endif is a bit of ways down ... */ #include <time.h> +#include "xattr.h" #if defined(MINIX) || defined(__mpexl) # ifdef S_IWRITE @@ -40,6 +41,8 @@ # endif #endif /* HAVE_DIRENT_H || _POSIX_VERSION */ +#include <attr/xattr.h> + #define PAD 0 #define PATH_END '/' @@ -436,19 +439,80 @@ int set_extra_field(z, z_utim) struct stat s; #endif +char * xa_list; +char * xa_name; +char * xa_value; +ssize_t xa_list_len=0; +ssize_t xa_name_len=0; +ssize_t xa_value_len=0; +int value_len=0; +int largest_value_len=0; +int ext_index=0; +int xa_pairs_found=0; +int value_index=1; +int i=0, j=0; + /* For the full sized UT local field including the UID/GID fields, we * have to stat the file again. */ if (LSSTAT(z->name, &s)) return ZE_OPEN; + #define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(2)) #define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1)) #define EB_L_UX2_SIZE (EB_HEADSIZE + EB_UX2_MINLEN) #define EB_C_UX2_SIZE EB_HEADSIZE -#define EF_L_UNIX_SIZE (EB_L_UT_SIZE + EB_L_UX2_SIZE) -#define EF_C_UNIX_SIZE (EB_C_UT_SIZE + EB_C_UX2_SIZE) +#define EB_L_XA_SIZE (EB_HEADSIZE + EB_XA_MINLEN) +#define EB_C_XA_SIZE EB_HEADSIZE - if ((z->extra = (char *)malloc(EF_L_UNIX_SIZE)) == NULL) + /* Get size of xattr name list */ + /* Calling listxattr with NULL and zero returns the size */ + xa_list_len = listxattr(z->name, NULL, 0); + + if (xa_list_len > 0) { + + /* now that we know the size, alloc space for list */ + if ((xa_list = malloc(xa_list_len+1)) == NULL) + return ZE_MEM; + + /* Get the list of xattr names */ + xa_list_len = listxattr(z->name, xa_list, xa_list_len); + if (xa_list_len < 0) + return ZE_XATTR; + xa_name = xa_list; + xa_name_len = xa_list_len; + + /* figure out how many xattr names there are in the list */ + xa_pairs_found=get_xattr_count(xa_list, xa_list_len); + if (xa_pairs_found < 1) + return ZE_XATTR; + + /* Need to figure out the largest value_len before calling malloc */ + /* also need the sum of all value_lens; store it in xa_value_len */ + for (value_index=1; value_index <= xa_pairs_found; value_index++) { + xa_name=get_xattr_name(xa_list, xa_list_len, value_index); + if (xa_name == (char *)NULL) + return ZE_XATTR; + value_len=getxattr(z->name, xa_name, xa_value, 0); + if (value_len < 0) + return ZE_XATTR; + if (value_len > largest_value_len) + largest_value_len = value_len; + xa_value_len=xa_value_len + value_len + 1; + } + if ((xa_value = malloc(largest_value_len+1)) == NULL) + return ZE_MEM; + } + +#define EB_L_XN_SIZE (EB_HEADSIZE + EB_XA_MINLEN + xa_name_len) +#define EB_C_XN_SIZE EB_HEADSIZE +#define EB_L_XV_SIZE (EB_HEADSIZE + EB_XA_MINLEN + xa_value_len) +#define EB_C_XV_SIZE EB_HEADSIZE +#define EF_L_UNIX_SIZE (EB_L_UT_SIZE + EB_L_UX2_SIZE + EB_L_XA_SIZE + EB_L_XN_SIZE + EB_L_XV_SIZE) +#define EF_C_UNIX_SIZE (EB_C_UT_SIZE + EB_C_UX2_SIZE + EB_C_XA_SIZE + EB_C_XN_SIZE + EB_C_XV_SIZE) + + z->ext = EF_L_UNIX_SIZE; + if ((z->extra = (char *)malloc(z->ext)) == NULL) return ZE_MEM; if ((z->cextra = (char *)malloc(EF_C_UNIX_SIZE)) == NULL) return ZE_MEM; @@ -474,7 +538,71 @@ int set_extra_field(z, z_utim) z->extra[18] = (char)(s.st_uid >> 8); z->extra[19] = (char)(s.st_gid); z->extra[20] = (char)(s.st_gid >> 8); - z->ext = EF_L_UNIX_SIZE; + z->extra[21] = 'X'; + z->extra[22] = 'A'; + z->extra[23] = (char) xa_pairs_found; /* Number of xattr attributes*/ + z->extra[24] = 0; + z->extra[25] = 'X'; + z->extra[26] = 'N'; + z->extra[27] = (char) xa_name_len; /* length of xattr name list*/ + z->extra[28] = 0; + + ext_index=29; + + if (xa_list_len > 0) { + +/* Put all the xattr names in extra field */ + for (i=1; i<=xa_pairs_found; i++) { + xa_name=get_xattr_name(xa_list, xa_list_len, i); + if (xa_name == (char *)NULL) + return ZE_XATTR; + xa_name_len=strlen(xa_name); + if (xa_name_len < 1) + return ZE_XATTR; + for (j=0; j<xa_name_len; j++) { + z->extra[ext_index+j]=(char) xa_name[j]; + } + ext_index = ext_index+j; + z->extra[ext_index] = '\0'; + ext_index++; + } + + z->extra[ext_index] = 'X'; + ext_index++; + z->extra[ext_index] = 'V'; + ext_index++; + z->extra[ext_index] = (char) xa_value_len; /* length of xattr value list*/ + ext_index++; + z->extra[ext_index] = 0; + ext_index++; + +/* Put all the xattr values in extra field */ + for (value_index=1; value_index <= xa_pairs_found; value_index++) { + xa_name=get_xattr_name(xa_list, xa_list_len, value_index); + if (xa_name == (char *)NULL) + return ZE_XATTR; + value_len=getxattr(z->name, xa_name, xa_value, 0); + if (value_len < 1) + return ZE_XATTR; + xa_value=memset(xa_value, 0, largest_value_len+1); + if (xa_value == (char *) NULL) + return ZE_MEM; + value_len=getxattr(z->name, xa_name, xa_value, value_len); + if (value_len < 1) + return ZE_XATTR; + + for (j=0; j<value_len; j++) { + z->extra[ext_index+j]=(char) xa_value[j]; + } + ext_index = ext_index+j; + z->extra[ext_index] = '\0'; + ext_index++; + } + + } /* if xa_list_len > 0 */ + + free(xa_list); + free(xa_value); memcpy(z->cextra, z->extra, EB_C_UT_SIZE); z->cextra[EB_LEN] = (char)EB_UT_LEN(1); diff -urpN zip-2.3.orig/unix/xattr.h zip-2.3/unix/xattr.h --- zip-2.3.orig/unix/xattr.h 1969-12-31 18:00:00.000000000 -0600 +++ zip-2.3/unix/xattr.h 2005-10-24 15:42:43.000000000 -0500 @@ -0,0 +1,67 @@ +/* + Copyright (C) 2005 IBM Corporation + Copyright (c) 1990-1999 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 1999-Oct-05 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, both of these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html +*/ + + +int get_xattr_count(char * xa_list, int xa_list_size) +{ +/* xattr names have the form name1.name2 */ +/* A file can have any number of xattr name pairs */ +/* This function returns the number of name pairs found */ +/* If list passed in is NULL or list size is less than 1 + function returns 0 */ + + int i=0; + int p=0; + + if ( (xa_list == (char *) NULL) || (xa_list_size < 1)) + return 0; + + while (i < xa_list_size) { + if ( xa_list[i] != '\0') { + i++; + } else { + i++; + p++; + } + } + return p; +} + +char * get_xattr_name(char * xa_list, int xa_list_size, int pair) +{ +/* xattr names have the form name1.name2 */ +/* A file can have any number of xattr name pairs */ +/* This function returns a pointer to the specified name pair */ +/* If list is NULL or size or pair are less than 1, then + function returns NULL */ + + int i=0; + int p=1; + char * tmp; + + tmp=NULL; + + if ( (xa_list == (char *) NULL) || (xa_list_size < 1) || (pair < 1) ) + return NULL; + + while ( (i < xa_list_size) && ( p != pair) ) { + if ( xa_list[i] != '\0') { + i++; + } else { + i++; + p++; + } + } + + if ( (p==pair) && (i < xa_list_size) ) + tmp=&xa_list[i]; + + return tmp; +} diff -urpN zip-2.3.orig/zip.c zip-2.3/zip.c --- zip-2.3.orig/zip.c 2005-10-10 14:11:49.000000000 -0500 +++ zip-2.3/zip.c 2005-10-24 15:38:44.000000000 -0500 @@ -980,7 +980,7 @@ char **argv; /* command line zp_tz_is_valid = VALID_TIMEZONE(p); #if (defined(AMIGA) || defined(DOS)) if (!zp_tz_is_valid) - extra_fields = 0; /* disable storing "UT" time stamps and xatter info*/ + extra_fields = 0; /* disable storing "UT" time stamps */ #endif /* AMIGA || DOS */ #endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */ diff -urpN zip-2.3.orig/ziperr.h zip-2.3/ziperr.h --- zip-2.3.orig/ziperr.h 2005-10-10 13:55:45.000000000 -0500 +++ zip-2.3/ziperr.h 2005-10-24 15:38:44.000000000 -0500 @@ -31,8 +31,9 @@ #define ZE_CREAT 15 /* couldn't open to write */ #define ZE_PARMS 16 /* bad command line */ #define ZE_OPEN 18 /* could not open a specified file to read */ +#define ZE_XATTR 19 /* xattr error occurred */ -#define ZE_MAXERR 18 /* the highest error number */ +#define ZE_MAXERR 19 /* the highest error number */ /* Macro to determine whether to call perror() or not */ #define PERR(e) (e==ZE_READ||e==ZE_WRITE||e==ZE_CREAT||e==ZE_TEMP||e==ZE_OPEN) @@ -58,6 +59,7 @@ char *errors[ZE_MAXERR] = { /* 16 */ "Invalid command arguments", /* 17 */ "", /* 18 */ "File not found or no read permission" +/* 19 */ "Extended attributes failure" # ifdef AZTEC_C , /* extremely lame compiler bug workaround */ # endif diff -urpN zip-2.3.orig/zip.h zip-2.3/zip.h --- zip-2.3.orig/zip.h 2005-10-10 13:55:45.000000000 -0500 +++ zip-2.3/zip.h 2005-10-24 15:38:44.000000000 -0500 @@ -171,6 +171,9 @@ struct plist { #define EF_SPARK 0x4341 /* David Pilling's Acorn/SparkFS ("AC") */ #define EF_THEOS 0x6854 /* THEOS ("Th") */ #define EF_TANDEM 0x4154 /* Tandem NSK ("TA") */ +#define EF_XATTR 0x4158 /* XATTR ("XA") */ +#define EF_XA_NAME 0x4e58 /* XATTR NAME ("XN") */ +#define EF_XA_VALUE 0x5658 /* XATTR VALUE ("XV") */ /* Definitions for extra field handling: */ #define EF_SIZE_MAX ((unsigned)0xFFFF) /* hard limit of total e.f. length */ @@ -199,6 +202,8 @@ struct plist { #define EB_UX2_GID 2 /* byte offset of GID in "Ux" field data */ #define EB_UX2_VALID (1 << 8) /* UID/GID present */ +#define EB_XA_MINLEN 4 /* minimal XA field contains count */ + /* ASCII definitions for line terminators in text files: */ #define LF 10 /* '\n' on ASCII machines; must be 10 due to EBCDIC */ #define CR 13 /* '\r' on ASCII machines; must be 13 due to EBCDIC */ diff -urpN zip-2.3.orig/zip.h.4gb zip-2.3/zip.h.4gb --- zip-2.3.orig/zip.h.4gb 2005-10-10 13:55:45.000000000 -0500 +++ zip-2.3/zip.h.4gb 2005-10-24 15:38:44.000000000 -0500 @@ -171,6 +171,9 @@ struct plist { #define EF_SPARK 0x4341 /* David Pilling's Acorn/SparkFS ("AC") */ #define EF_THEOS 0x6854 /* THEOS ("Th") */ #define EF_TANDEM 0x4154 /* Tandem NSK ("TA") */ +#define EF_XATTR 0x4158 /* XATTR ("XA") */ +#define EF_XA_NAME 0x4e58 /* XATTR NAME ("XN") */ +#define EF_XA_VALUE 0x5658 /* XATTR VALUE ("XV") */ /* Definitions for extra field handling: */ #define EF_SIZE_MAX ((unsigned)0xFFFF) /* hard limit of total e.f. length */ @@ -199,6 +202,8 @@ struct plist { #define EB_UX2_GID 2 /* byte offset of GID in "Ux" field data */ #define EB_UX2_VALID (1 << 8) /* UID/GID present */ +#define EB_XA_MINLEN 4 /* minimal XA field contains count */ + /* ASCII definitions for line terminators in text files: */ #define LF 10 /* '\n' on ASCII machines; must be 10 due to EBCDIC */ #define CR 13 /* '\r' on ASCII machines; must be 13 due to EBCDIC */ diff -urpN zip-2.3.orig/zip.h.zip zip-2.3/zip.h.zip --- zip-2.3.orig/zip.h.zip 2005-10-10 13:55:45.000000000 -0500 +++ zip-2.3/zip.h.zip 2005-10-24 15:38:44.000000000 -0500 @@ -170,6 +170,10 @@ struct plist { #define EF_SPARK 0x4341 /* David Pilling's Acorn/SparkFS ("AC") */ #define EF_THEOS 0x6854 /* THEOS ("Th") */ #define EF_TANDEM 0x4154 /* Tandem NSK ("TA") */ +#define EF_XATTR 0x4158 /* XATTR ("XA") */ +#define EF_XA_NAME 0x4e58 /* XATTR NAME ("XN") */ +#define EF_XA_VALUE 0x5658 /* XATTR VALUE ("XV") */ + /* Definitions for extra field handling: */ #define EF_SIZE_MAX ((unsigned)0xFFFF) /* hard limit of total e.f. length */ @@ -198,6 +202,8 @@ struct plist { #define EB_UX2_GID 2 /* byte offset of GID in "Ux" field data */ #define EB_UX2_VALID (1 << 8) /* UID/GID present */ +#define EB_XA_MINLEN 4 /* minimal XA field contains count */ + /* ASCII definitions for line terminators in text files: */ #define LF 10 /* '\n' on ASCII machines; must be 10 due to EBCDIC */ #define CR 13 /* '\r' on ASCII machines; must be 13 due to EBCDIC */ diff -urpN unzip-5.51.orig/extract.c unzip-5.51/extract.c --- unzip-5.51.orig/extract.c 2005-09-08 14:25:57.000000000 -0500 +++ unzip-5.51/extract.c 2005-10-24 16:09:09.000000000 -0500 @@ -1908,6 +1908,9 @@ static int TestExtraField(__G__ ef, ef_l case EF_ASIUNIX: case EF_IZVMS: case EF_IZUNIX: + case EF_XATTR: + case EF_XA_NAME: + case EF_XA_VALUE: case EF_VMCMS: case EF_MVS: case EF_SPARK: diff -urpN unzip-5.51.orig/fileio.c unzip-5.51/fileio.c --- unzip-5.51.orig/fileio.c 2005-09-08 14:25:57.000000000 -0500 +++ unzip-5.51/fileio.c 2005-10-24 16:09:09.000000000 -0500 @@ -1833,6 +1833,9 @@ int check_for_newer(__G__ filename) /* #ifdef USE_EF_UT_TIME iztimes z_utime; #endif +#ifdef USE_EF_XATTR + izxattr z_xattr; +#endif #ifdef AOS_VS long dyy, dmm, ddd, dhh, dmin, dss; @@ -1902,7 +1905,11 @@ int check_for_newer(__G__ filename) /* G.tz_is_valid && #endif (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0, +#ifdef USE_EF_XATTR + G.lrec.last_mod_dos_datetime, &z_utime, NULL, &z_xattr) +#else G.lrec.last_mod_dos_datetime, &z_utime, NULL) +#endif & EB_UT_FL_MTIME)) { TTrace((stderr, "check_for_newer: using Unix extra field mtime\n")); diff -urpN unzip-5.51.orig/list.c unzip-5.51/list.c --- unzip-5.51.orig/list.c 2005-09-08 14:25:57.000000000 -0500 +++ unzip-5.51/list.c 2005-10-24 16:09:09.000000000 -0500 @@ -104,6 +104,9 @@ int list_files(__G) /* return PK-type iztimes z_utime; struct tm *t; #endif +#ifdef USE_EF_XATTR + izxattr z_xattr; +#endif unsigned yr, mo, dy, hh, mm; ulg csiz; unsigned long long tot_csize=0, tot_ucsize=0; @@ -268,7 +271,12 @@ int list_files(__G) /* return PK-type G.tz_is_valid && #endif (ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1, - G.crec.last_mod_dos_datetime, &z_utime, NULL) + G.crec.last_mod_dos_datetime, &z_utime, +#ifdef USE_EF_XATTR + NULL, &z_xattr) +#else + NULL) +#endif & EB_UT_FL_MTIME)) { TIMET_TO_NATIVE(z_utime.mtime) /* NOP unless MSC 7.0, Mac */ @@ -509,6 +517,9 @@ int get_time_stamp(__G__ last_modtime, n #ifdef USE_EF_UT_TIME iztimes z_utime; #endif +#ifdef USE_EF_XATTR + iztimes z_xattr; +#endif min_info info; @@ -594,7 +605,12 @@ int get_time_stamp(__G__ last_modtime, n G.tz_is_valid && #endif (ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1, - G.crec.last_mod_dos_datetime, &z_utime, NULL) + G.crec.last_mod_dos_datetime, &z_utime, +#ifdef USE_EF_XATTR + NULL, &z_xattr) +#else + NULL) +#endif & EB_UT_FL_MTIME)) { if (*last_modtime < z_utime.mtime) diff -urpN unzip-5.51.orig/Makefile unzip-5.51/Makefile --- unzip-5.51.orig/Makefile 2005-09-08 14:25:57.000000000 -0500 +++ unzip-5.51/Makefile 2005-10-24 16:09:09.000000000 -0500 @@ -81,14 +81,14 @@ CRC32 = crc32 OSDEP_H = # object files -OBJS1 = unzip$O $(CRC32)$O crctab$O crypt$O envargs$O explode$O +OBJS1 = unzip$O $(CRC32)$O crctab$O crypt$O envargs$O explode$O xattr$O OBJS2 = extract$O fileio$O globals$O inflate$O list$O match$O OBJS3 = process$O ttyio$O unreduce$O unshrink$O zipinfo$O OBJS = $(OBJS1) $(OBJS2) $(OBJS3) $M$O LOBJS = $(OBJS) OBJSDLL = $(OBJS:.o=.pic.o) api.pic.o OBJX = unzipsfx$O $(CRC32)$O crctab_$O crypt_$O extract_$O fileio_$O \ - globals_$O inflate_$O match_$O process_$O ttyio_$O $M_$O + globals_$O inflate_$O match_$O process_$O ttyio_$O xattr_$O $M_$O LOBJX = $(OBJX) OBJF = funzip$O $(CRC32)$O cryptf$O globalsf$O inflatef$O ttyiof$O #OBJS_OS2 = $(OBJS1:.o=.obj) $(OBJS2:.o=.obj) os2.obj @@ -300,6 +300,7 @@ ttyio$O: ttyio.c $(UNZIP_H) zip.h crypt. unreduce$O: unreduce.c $(UNZIP_H) unshrink$O: unshrink.c $(UNZIP_H) unzip$O: unzip.c $(UNZIP_H) crypt.h unzvers.h consts.h +xattr$O: xattr.c $(UNZIP_H) zipinfo$O: zipinfo.c $(UNZIP_H) unzipsfx$O: unzip.c $(UNZIP_H) crypt.h unzvers.h consts.h # unzipsfx only @@ -342,6 +343,11 @@ match_$O: match.c $(UNZIP_H) # unzips $(CC) -c $(CF) -DSFX match_.c $(RM) match_.c +xattr_$O: xattr.c $(UNZIP_H) # unzipsfx only + -$(CP) xattr.c xattr_.c + $(CC) -c $(CF) -DSFX xattr_.c + $(RM) xattr_.c + process_$O: process.c $(UNZIP_H) # unzipsfx only -$(CP) process.c process_.c $(CC) -c $(CF) -DSFX process_.c diff -urpN unzip-5.51.orig/process.c unzip-5.51/process.c --- unzip-5.51.orig/process.c 2005-09-08 14:25:57.000000000 -0500 +++ unzip-5.51/process.c 2005-10-24 16:09:09.000000000 -0500 @@ -1300,15 +1300,22 @@ int process_local_file_hdr(__G) /* re /*******************************/ /* Function ef_scan_for_izux() */ /*******************************/ - +#ifdef USE_EF_XATTR +unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos_mdatetime, + z_utim, z_uidgid, z_xattr) +#else unsigned ef_scan_for_izux(ef_buf, ef_len, ef_is_c, dos_mdatetime, z_utim, z_uidgid) +#endif ZCONST uch *ef_buf; /* buffer containing extra field */ unsigned ef_len; /* total length of extra field */ int ef_is_c; /* flag indicating "is central extra field" */ ulg dos_mdatetime; /* last_mod_file_date_time in DOS format */ iztimes *z_utim; /* return storage: atime, mtime, ctime */ ush *z_uidgid; /* return storage: uid and gid */ +#ifdef USE_EF_XATTR + izxattr *z_xattr; /* return storage: xattr names, values, lens, count */ +#endif { unsigned flags = 0; unsigned eb_id; @@ -1342,6 +1349,12 @@ unsigned ef_scan_for_izux(ef_buf, ef_len if (ef_len == 0 || ef_buf == NULL || (z_utim == 0 && z_uidgid == NULL)) return 0; +#ifdef USE_EF_XATTR + if (z_xattr == NULL) + return 0; + z_xattr->count=0; +#endif + TTrace((stderr,"\nef_scan_for_izux: scanning extra field of length %u\n", ef_len)); @@ -1358,6 +1371,56 @@ unsigned ef_scan_for_izux(ef_buf, ef_len } switch (eb_id) { +#ifdef USE_EF_XATTR + case EF_XATTR: + z_xattr->count=eb_len; + if (z_xattr->count > 0) { + ef_buf += EB_HEADSIZE; + ef_len -= EB_HEADSIZE; + eb_id = makeword(EB_ID + ef_buf); + } else { + break; + } + case EF_XA_NAME: + if (z_xattr->count > 0) { + ef_buf += EB_HEADSIZE; + ef_len -= EB_HEADSIZE; + if ((z_xattr->xa_name=malloc(ef_len)) == (char *)NULL) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(CannotAllocateBuffers))); + return 0; + } + z_xattr->xa_name_len=copy_xattr(ef_buf, z_xattr->xa_name, z_xattr->count); + if (z_xattr->xa_name_len < 0) { + TTrace((stderr, + " XATTR name error; ignore e.f.!\n")); + break; /* stop scanning this field */ + } + ef_buf += z_xattr->xa_name_len; + ef_len -= z_xattr->xa_name_len; + } else { + break; + } + case EF_XA_VALUE: + if (z_xattr->count > 0) { + ef_buf += EB_HEADSIZE; + ef_len -= EB_HEADSIZE; + if ((z_xattr->xa_value=malloc(ef_len)) == (char *)NULL) { + Info(slide, 0x401, ((char *)slide, + LoadFarString(CannotAllocateBuffers))); + return 0; + } + z_xattr->xa_value_len=copy_xattr(ef_buf, z_xattr->xa_value, z_xattr->count); + if (z_xattr->xa_value_len <= 0) { + TTrace((stderr, + " XATTR value error; ignore e.f.!\n")); + break; /* stop scanning this field */ + } + ef_buf += z_xattr->xa_value_len; + ef_len -= z_xattr->xa_value_len; + } + break; +#endif case EF_TIME: flags &= ~0x0ff; /* ignore previous IZUNIX or EF_TIME fields */ have_new_type_eb = TRUE; diff -urpN unzip-5.51.orig/unix/Makefile unzip-5.51/unix/Makefile --- unzip-5.51.orig/unix/Makefile 2005-09-08 14:25:57.000000000 -0500 +++ unzip-5.51/unix/Makefile 2005-10-24 16:09:09.000000000 -0500 @@ -81,14 +81,14 @@ CRC32 = crc32 OSDEP_H = # object files -OBJS1 = unzip$O $(CRC32)$O crctab$O crypt$O envargs$O explode$O +OBJS1 = unzip$O $(CRC32)$O crctab$O crypt$O envargs$O explode$O xattr$O OBJS2 = extract$O fileio$O globals$O inflate$O list$O match$O OBJS3 = process$O ttyio$O unreduce$O unshrink$O zipinfo$O OBJS = $(OBJS1) $(OBJS2) $(OBJS3) $M$O LOBJS = $(OBJS) OBJSDLL = $(OBJS:.o=.pic.o) api.pic.o OBJX = unzipsfx$O $(CRC32)$O crctab_$O crypt_$O extract_$O fileio_$O \ - globals_$O inflate_$O match_$O process_$O ttyio_$O $M_$O + globals_$O inflate_$O match_$O process_$O ttyio_$O xattr_$O $M_$O LOBJX = $(OBJX) OBJF = funzip$O $(CRC32)$O cryptf$O globalsf$O inflatef$O ttyiof$O #OBJS_OS2 = $(OBJS1:.o=.obj) $(OBJS2:.o=.obj) os2.obj @@ -300,6 +300,7 @@ ttyio$O: ttyio.c $(UNZIP_H) zip.h crypt. unreduce$O: unreduce.c $(UNZIP_H) unshrink$O: unshrink.c $(UNZIP_H) unzip$O: unzip.c $(UNZIP_H) crypt.h unzvers.h consts.h +xattr$O: xattr.c $(UNZIP_H) zipinfo$O: zipinfo.c $(UNZIP_H) unzipsfx$O: unzip.c $(UNZIP_H) crypt.h unzvers.h consts.h # unzipsfx only @@ -342,6 +343,11 @@ match_$O: match.c $(UNZIP_H) # unzips $(CC) -c $(CF) -DSFX match_.c $(RM) match_.c +xattr_$O: xattr.c $(UNZIP_H) # unzipsfx only + -$(CP) xattr.c xattr_.c + $(CC) -c $(CF) -DSFX xattr_.c + $(RM) xattr_.c + process_$O: process.c $(UNZIP_H) # unzipsfx only -$(CP) process.c process_.c $(CC) -c $(CF) -DSFX process_.c diff -urpN unzip-5.51.orig/unix/unix.c unzip-5.51/unix/unix.c --- unzip-5.51.orig/unix/unix.c 2005-09-08 14:25:57.000000000 -0500 +++ unzip-5.51/unix/unix.c 2005-10-24 16:09:09.000000000 -0500 @@ -83,6 +83,7 @@ typedef struct uxdirattr { /* struc int have_uidgid; /* flag */ ush uidgid[2]; char fnbuf[1]; /* buffer stub for directory name */ + izxattr z_xattr; /* struct for xattr names and values */ } uxdirattr; #define UxAtt(d) ((uxdirattr *)d) /* typecast shortcut */ #endif /* SET_DIR_ATTRIB */ @@ -932,12 +933,13 @@ int mkdir(path, mode) #if (!defined(MTS) || defined(SET_DIR_ATTRIB)) -static int get_extattribs OF((__GPRO__ iztimes *pzt, ush z_uidgid[2])); +static int get_extattribs OF((__GPRO__ iztimes *pzt, ush z_uidgid[2], izxattr *pzxattr)); -static int get_extattribs(__G__ pzt, z_uidgid) +static int get_extattribs(__G__ pzt, z_uidgid, pzxattr) __GDEF iztimes *pzt; ush z_uidgid[2]; + izxattr *pzxattr; { /*--------------------------------------------------------------------------- Convert from MSDOS-format local time and date to Unix-format 32-bit GMT @@ -957,7 +959,13 @@ static int get_extattribs(__G__ pzt, z_u #else pzt, #endif - z_uidgid) : 0); + z_uidgid, +#ifdef USE_EF_XATTR + pzxattr) : 0); +#else + NULL) : 0); +#endif + if (eb_izux_flg & EB_UT_FL_MTIME) { TTrace((stderr, "\nget_extattribs: Unix e.f. modif. time = %ld\n", pzt->mtime)); @@ -1000,7 +1008,14 @@ void close_outfile(__G) /* GRR: chang ztimbuf t2; /* modtime, actime */ } zt; ush z_uidgid[2]; + izxattr z_xattr; int have_uidgid_flg; + int rc=0; + char *name; + char *value; + int i; + int value_len; + int largest_value_len=0; fchmod(fileno(G.outfile), 0400); @@ -1090,7 +1105,7 @@ void close_outfile(__G) /* GRR: chang } #endif - have_uidgid_flg = get_extattribs(__G__ &(zt.t3), z_uidgid); + have_uidgid_flg = get_extattribs(__G__ &(zt.t3), z_uidgid, &z_xattr); /* if -X option was specified and we have UID/GID info, restore it */ if (have_uidgid_flg) { @@ -1108,6 +1123,54 @@ void close_outfile(__G) /* GRR: chang } } +#ifdef USE_EF_XATTR +/* if -E option was specified attempt to restore extended attribute info */ + if (uO.E_flag && (!have_uidgid_flg)) { + Info(slide, 0x201, ((char *)slide, + " (warning) unable to restore extended attributes for %s\n", FnFilter1(G.filename))); + } + if (uO.E_flag && have_uidgid_flg) { + /* Restore extended attributes info */ + if (z_xattr.count > 0) { + /* Need to figure out the largest value_len before calling malloc */ + for (i=1; i<=z_xattr.count; i++) { + name = get_xattr_name(z_xattr.xa_name, z_xattr.xa_name_len, i); + value_len=getxattr(z_xattr.xa_name, name, value, 0); + if (value_len > largest_value_len) + largest_value_len = value_len; + } + if ((value = malloc(largest_value_len+1)) == (char *)NULL) { + Info(slide, 0x201, ((char *)slide, + "warning: xattr (%s) failed: no mem\n", + FnFilter1(G.filename))); + return; + } else { + /* Set all xattr name and value pairs */ + for (i=1; i<=z_xattr.count; i++) { + name = get_xattr_name(z_xattr.xa_name, z_xattr.xa_name_len, i); + if (name == (char *) NULL) { + Info(slide, 0x201, ((char *)slide, + " (warning) cannot restore extended attributes for %s\n", FnFilter1(G.filename))); + } + value = get_xattr_value(z_xattr.xa_value, z_xattr.xa_value_len, i); + if (value == (char *) NULL) { + Info(slide, 0x201, ((char *)slide, + " (warning) cannot restore extended attributes for %s\n", FnFilter1(G.filename))); + } + rc = setxattr(G.filename, name, value, strlen(value), 0); + if (rc != 0) { + Info(slide, 0x201, ((char *)slide, + " (warning) cannot restore extended attributes for %s\n", FnFilter1(G.filename))); + } + } + } + } else { + Info(slide, 0x201, ((char *)slide, + " (warning) cannot restore extended attributes for %s\n", FnFilter1(G.filename))); + } + } +#endif + /* set the file's access and modification times */ if (utime(G.filename, &(zt.t2))) { #ifdef AOS_VS @@ -1160,7 +1223,7 @@ int defer_dir_attribs(__G__ pd) d_entry->perms = G.pInfo->file_attr; d_entry->have_uidgid = get_extattribs(__G__ &(d_entry->u.t3), - d_entry->uidgid); + d_entry->uidgid, &(d_entry->z_xattr)); return PK_OK; } /* end function defer_dir_attribs() */ diff -urpN unzip-5.51.orig/unix/unxcfg.h unzip-5.51/unix/unxcfg.h --- unzip-5.51.orig/unix/unxcfg.h 2005-09-08 14:25:57.000000000 -0500 +++ unzip-5.51/unix/unxcfg.h 2005-10-24 16:09:09.000000000 -0500 @@ -122,6 +122,8 @@ #endif #define RESTORE_UIDGID +#define USE_EF_XATTR + /* Static variables that we have to add to Uz_Globs: */ #define SYSTEM_SPECIFIC_GLOBALS \ int created_dir, renamed_fullpath;\ diff -urpN unzip-5.51.orig/unzip.c unzip-5.51/unzip.c --- unzip-5.51.orig/unzip.c 2005-09-08 14:25:57.000000000 -0500 +++ unzip-5.51/unzip.c 2005-10-24 16:09:09.000000000 -0500 @@ -143,6 +143,8 @@ static ZCONST char Far InvalidOptionsMsg -fn or any combination of -c, -l, -p, -t, -u and -v options invalid\n"; static ZCONST char Far IgnoreOOptionMsg[] = "caution: both -n and -o specified; ignoring -o\n"; +static ZCONST char Far InvalidEModifierMsg[] = "error:\ + -E modifier cannot be used without -X modifier\n"; /* usage() strings */ #ifndef SFX @@ -238,12 +240,30 @@ M pipe through \"more\" pager #else /* !VMS */ #ifdef BEO_UNX static ZCONST char Far local2[] = " -X restore UID/GID info"; +#ifdef USE_EF_XATTR +#ifdef MORE + static ZCONST char Far local3[] = " \ +-E restore extended attributes -M pipe through \"more\" pager\n"; +#else /* !MORE */ + static ZCONST char Far local3[] = " \ +-E restore extended attributes\n"; +#endif +#else /* !USE_EF_XATTR */ +#ifdef MORE + static ZCONST char Far local3[] = "\ + -M pipe through \"more\" pager\n"; +#else /* !MORE */ + static ZCONST char Far local3[] = "\n"; +#endif +#endif +/* #ifdef MORE static ZCONST char Far local3[] = "\ -M pipe through \"more\" pager\n"; #else static ZCONST char Far local3[] = "\n"; #endif +*/ #else /* !BEO_UNX */ #ifdef TANDEM static ZCONST char Far local2[] = "\ @@ -1222,6 +1242,15 @@ int uz_opts(__G__ pargc, pargv) } break; #endif /* MACOS */ +#ifdef UNIX + case ('E'): /* -E [UNIX] restore extended attributes */ + if( negative ) { + uO.E_flag = FALSE, negative = 0; + } else { + uO.E_flag = TRUE; + } + break; +#endif /* MACOS */ case ('f'): /* "freshen" (extract only newer files) */ if (negative) uO.fflag = uO.uflag = FALSE, negative = 0; @@ -1521,6 +1550,13 @@ opts_done: /* yes, very ugly...but only Info(slide, 0x401, ((char *)slide, LoadFarString(InvalidOptionsMsg))); error = TRUE; } +#ifdef UNIX + if (uO.E_flag && (!uO.X_flag)) + { + Info(slide, 0x401, ((char *)slide, LoadFarString(InvalidEModifierMsg))); + error = TRUE; + } +#endif if (uO.aflag > 2) uO.aflag = 2; #ifdef VMS diff -urpN unzip-5.51.orig/unzip.h unzip-5.51/unzip.h --- unzip-5.51.orig/unzip.h 2005-09-08 14:25:57.000000000 -0500 +++ unzip-5.51/unzip.h 2005-10-24 16:09:09.000000000 -0500 @@ -438,6 +438,9 @@ typedef struct _UzpOpts { #ifdef MACOS int E_flag; /* -E: [MacOS] show Mac extra field during restoring */ #endif +#ifdef UNIX + int E_flag; /* -E: [Unix] restore extended attributes */ +#endif int fflag; /* -f: "freshen" (extract only newer files) */ #if (defined(RISCOS) || defined(ACORN_FTYPE_NFS)) int acorn_nfs_ext; /* -F: RISC OS types & NFS filetype extensions */ @@ -571,6 +574,7 @@ typedef struct central_directory_file_he #define PK_FIND 11 /* no files found */ #define PK_DISK 50 /* disk full */ #define PK_EOF 51 /* unexpected EOF */ +#define PK_XATTR 52 /* extended attributes error */ #define IZ_CTRLC 80 /* user hit ^C to terminate */ #define IZ_UNSUP 81 /* no files found: all unsup. compr/encrypt. */ diff -urpN unzip-5.51.orig/unzpriv.h unzip-5.51/unzpriv.h --- unzip-5.51.orig/unzpriv.h 2005-09-08 14:25:57.000000000 -0500 +++ unzip-5.51/unzpriv.h 2005-10-24 16:09:09.000000000 -0500 @@ -1433,6 +1433,9 @@ #define EF_THEOSO 0x4854 /* old Theos port */ #define EF_MD5 0x4b46 /* Fred Kantor's MD5 ("FK") */ #define EF_ASIUNIX 0x756e /* ASi's Unix ("nu") */ +#define EF_XATTR 0x4158 /* XATTR ("XA") */ +#define EF_XA_NAME 0x4e58 /* XATTR NAME ("XN") */ +#define EF_XA_VALUE 0x5658 /* XATTR VALUE ("XV") */ #define EB_HEADSIZE 4 /* length of extra field block header */ #define EB_ID 0 /* offset of block ID in header */ @@ -1459,6 +1462,8 @@ #define EB_UT_FL_ATIME (1 << 1) /* atime present */ #define EB_UT_FL_CTIME (1 << 2) /* ctime present */ +#define EB_XA_MINLEN 4 /* minimal XA size */ + #define EB_FLGS_OFFS 4 /* offset of flags area in generic compressed extra field blocks (BEOS, MAC, and others) */ #define EB_OS2_HLEN 4 /* size of OS2/ACL compressed data header */ @@ -1576,6 +1581,14 @@ typedef struct iztimes { time_t ctime; /* used for creation time; NOT same as st_ctime */ } iztimes; +typedef struct izxattr { + char *xa_name; /* xattr names list */ + char *xa_value; /* xattr values list */ + ssize_t xa_name_len; /* size of xa_names list */ + ssize_t xa_value_len; /* size of xa_value list */ + int count; /* number of xattr name and value pairs */ +} izxattr; + #ifdef SET_DIR_ATTRIB typedef struct direntry { /* head of system-specific struct holding */ struct direntry *next; /* defered directory attributes info */ @@ -1812,7 +1825,12 @@ int get_cdir_ent OF((__G int process_local_file_hdr OF((__GPRO)); unsigned ef_scan_for_izux OF((ZCONST uch *ef_buf, unsigned ef_len, int ef_is_c, ulg dos_mdatetime, +#ifdef USE_EF_XATTR + iztimes *z_utim, ush *z_uidgid, + izxattr *z_xattr)); +#else iztimes *z_utim, ush *z_uidgid)); +#endif #if (defined(RISCOS) || defined(ACORN_FTYPE_NFS)) zvoid *getRISCOSexfield OF((ZCONST uch *ef_buf, unsigned ef_len)); #endif @@ -1850,6 +1868,15 @@ void fnprint OF((__G #endif /* !SFX */ /*--------------------------------------------------------------------------- + Functions in xattr.c: + ---------------------------------------------------------------------------*/ + +int get_xattr_count(char *xa_list, int xa_list_size); +char * get_xattr_name(char *xa_list, int xa_list_size, int pair); +char * get_xattr_value(char *xa_list, int xa_list_size, int pair); +int copy_xattr(char *xa_list, char *new_list, int pair); + +/*--------------------------------------------------------------------------- Functions in fileio.c: ---------------------------------------------------------------------------*/ diff -urpN unzip-5.51.orig/xattr.c unzip-5.51/xattr.c --- unzip-5.51.orig/xattr.c 1969-12-31 18:00:00.000000000 -0600 +++ unzip-5.51/xattr.c 2005-10-24 16:12:01.000000000 -0500 @@ -0,0 +1,127 @@ +/* +*/ +/* xattr.c + * + * Author: Debora Velarde <dvelarde@xxxxxxxxxx> + * Created: Sept 14, 2005 + */ + + +#define __XATTR_C /* identifies this source module */ +#define UNZIP_INTERNAL +#include "unzip.h" + +int get_xattr_count(char *xa_list, int xa_list_size) +{ +/* xattr names have the form name1.name2 */ +/* A file can have any number of xattr name pairs */ +/* This function returns the number of name pairs found */ +/* If list passed in is NULL or list size is less than 1 + function retunrs 0 */ + + int i=0; + int p=0; + + if ( (xa_list == (char *) NULL) || (xa_list_size < 1)) + return 0; + + + while (i < xa_list_size) { + if ( xa_list[i] != '\0') { + i++; + } else { + i++; //move index to one past \0 + p++; + } + } + + return p; +} + +char * get_xattr_name(char *xa_list, int xa_list_size, int pair) +{ +/* xattr names have the form name1.name2 */ +/* A file can have any number of xattr name pairs */ +/* This function returns a pointer to the specified name pair */ +/* If list is NULL or size or pair are less than 1, then + function returns NULL */ + + int i=0; + int p=1; + char *tmp; + + tmp=NULL; + + if ( (xa_list == (char *) NULL) || (xa_list_size < 1) || (pair < 1) ) + return NULL; + + while ( (i < xa_list_size) && ( p != pair) ) { + if ( xa_list[i] != '\0') { + i++; + } else { + i++; //move index to one past \0 + p++; + } + } + + if ( (p==pair) && (i < xa_list_size) ) + tmp=&xa_list[i]; + + return tmp; +} + +char * get_xattr_value(char *xa_list, int xa_list_size, int pair) +{ +/* A file can have any number of xattr name and value pairs */ +/* This function returns a pointer to the specified value pair */ +/* If list is NULL or size or pair are less than 1, then + function returns NULL */ + + int i=0; + int p=1; + char *tmp; + + tmp=NULL; + + if ( (xa_list == (char *) NULL) || (xa_list_size < 1) || (pair < 1) ) + return NULL; + + while ( (i < xa_list_size) && ( p != pair) ) { + if ( xa_list[i] != '\0') { + i++; + } else { + i++; //move index to one past \0 + p++; + } + } + + if ( (p==pair) && (i < xa_list_size) ) + tmp=&xa_list[i]; + + return tmp; +} + +int copy_xattr(char *xa_list, char *new_list, int pair) +{ +/* A file can have any number of xattr name and value pairs */ +/* This function copies all the names or value from xa_list to new_list */ +/* This function returns the size of new_list */ +/* If either list being copied or new list is NULL, then retunrs -1 */ +/* If pair is less than 1 returns -1 */ + + int i=0; + int p=0; + + if ( (xa_list == (char *) NULL) || (new_list == (char *) NULL) || (pair < 1) ) + return -1; + + while ( p < pair ) { + new_list[i] = xa_list[i]; + if ( xa_list[i] == '\0') { + p++; + } + i++; + } + + return i; +} diff -urpN unzip-5.51.orig/zipinfo.c unzip-5.51/zipinfo.c --- unzip-5.51.orig/zipinfo.c 2005-09-08 14:25:57.000000000 -0500 +++ unzip-5.51/zipinfo.c 2005-10-24 16:09:09.000000000 -0500 @@ -330,6 +330,8 @@ static ZCONST char Far efMD5[] = "Fred K static ZCONST char Far efASiUnix[] = "ASi Unix"; static ZCONST char Far efTandem[] = "Tandem NSK"; static ZCONST char Far efTheos[] = "Theos"; +static ZCONST char Far efXAname[] = "xattr name"; +static ZCONST char Far efXAvalue[] = "xattr value"; static ZCONST char Far efUnknown[] = "unknown"; static ZCONST char Far OS2EAs[] = ".\n\ @@ -935,6 +937,9 @@ static int zi_long(__G__ pEndprev) /* #ifdef USE_EF_UT_TIME iztimes z_utime; #endif +#ifdef USE_EF_XATTR + izxattr z_xattr; +#endif int error, error_in_archive=PK_COOL; unsigned hostnum, hostver, extnum, extver, methnum, xattr; char workspace[12], attribs[22]; @@ -1076,7 +1081,12 @@ static int zi_long(__G__ pEndprev) /* G.tz_is_valid && #endif (ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1, - G.crec.last_mod_dos_datetime, &z_utime, NULL) + G.crec.last_mod_dos_datetime, &z_utime, +#ifdef USE_EF_XATTR + NULL, &z_xattr) +#else + NULL) +#endif & EB_UT_FL_MTIME)) { TIMET_TO_NATIVE(z_utime.mtime) /* NOP unless MSC 7.0 or Macintosh */ @@ -1422,6 +1432,12 @@ static int zi_long(__G__ pEndprev) /* #endif ef_fieldname = efTheos; break; + case EF_XA_NAME: + ef_fieldname = efXAname; + break; + case EF_XA_VALUE: + ef_fieldname = efXAvalue; + break; default: ef_fieldname = efUnknown; break; @@ -1755,6 +1771,9 @@ static int zi_short(__G) /* return PK- iztimes z_utime; time_t *z_modtim; #endif +#ifdef USE_EF_XATTR + izxattr z_xattr; +#endif int k, error, error_in_archive=PK_COOL; unsigned hostnum, hostver, methnum, xattr; char *p, workspace[12], attribs[16]; @@ -2053,7 +2072,12 @@ static int zi_short(__G) /* return PK- G.tz_is_valid && #endif (ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 1, - G.crec.last_mod_dos_datetime, &z_utime, NULL) + G.crec.last_mod_dos_datetime, &z_utime, +#ifdef USE_EF_XATTR + NULL, &z_xattr) +#else + NULL) +#endif & EB_UT_FL_MTIME) ? &z_utime.mtime : NULL; TIMET_TO_NATIVE(z_utime.mtime) /* NOP unless MSC 7.0 or Macintosh */ -- fedora-selinux-list mailing list fedora-selinux-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/fedora-selinux-list