📄 beos.c
字号:
/* Copyright (c) 1990-2005 Info-ZIP. All rights reserved. See the accompanying file LICENSE, version 2000-Apr-09 or later (the contents of which are also included in unzip.h) for terms of use. If, for some reason, all these files are missing, the Info-ZIP license also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html*//*--------------------------------------------------------------------------- beos.c BeOS-specific routines for use with Info-ZIP's UnZip 5.30 and later. (based on unix/unix.c) Contains: do_wild() <-- generic enough to put in fileio.c? mapattr() mapname() checkdir() close_outfile() defer_dir_attribs() set_direc_attribs() stamp_file() version() scanBeOSexfield() set_file_attrs() setBeOSexfield() printBeOSexfield() assign_MIME() ---------------------------------------------------------------------------*/#define UNZIP_INTERNAL#include "unzip.h"#include "beos.h"#include <errno.h> /* Just make sure we've got a few things... */#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <dirent.h>/* For the new post-DR8 file attributes */#include <kernel/fs_attr.h>#include <support/byteorder.h>#include <storage/Mime.h>static unsigned filtattr OF((__GPRO__ unsigned perms));static uch *scanBeOSexfield OF((const uch *ef_ptr, unsigned ef_len));static int set_file_attrs( const char *, const unsigned char *, const off_t );static void setBeOSexfield OF((const char *path, uch *extra_field));#ifdef BEOS_USE_PRINTEXFIELDstatic void printBeOSexfield OF((int isdir, uch *extra_field));#endif#ifdef BEOS_ASSIGN_FILETYPEstatic void assign_MIME( const char * );#endif#ifdef SET_DIR_ATTRIBtypedef struct uxdirattr { /* struct for holding unix style directory */ struct uxdirattr *next; /* info until can be sorted and set at end */ char *fn; /* filename of directory */ union { iztimes t3; /* mtime, atime, ctime */ ztimbuf t2; /* modtime, actime */ } u; unsigned perms; /* same as min_info.file_attr */ int have_uidgid; /* flag */ ush uidgid[2]; char fnbuf[1]; /* buffer stub for directory name */} uxdirattr;#define UxAtt(d) ((uxdirattr *)d) /* typecast shortcut */#endif /* SET_DIR_ATTRIB */#ifdef ACORN_FTYPE_NFS/* Acorn bits for NFS filetyping */typedef struct { uch ID[2]; uch size[2]; uch ID_2[4]; uch loadaddr[4]; uch execaddr[4]; uch attr[4];} RO_extra_block;#endif /* ACORN_FTYPE_NFS *//* static int created_dir; */ /* used in mapname(), checkdir() *//* static int renamed_fullpath; */ /* ditto */#ifndef SFX/**********************//* Function do_wild() */ /* for porting: dir separator; match(ignore_case) *//**********************/char *do_wild(__G__ wildspec) __GDEF ZCONST char *wildspec; /* only used first time on a given dir */{/* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in beocfg.h: static DIR *wild_dir = (DIR *)NULL; static ZCONST char *wildname; static char *dirname, matchname[FILNAMSIZ]; static int notfirstcall=FALSE, have_dirname, dirnamelen;*/ struct dirent *file; /* Even when we're just returning wildspec, we *always* do so in * matchname[]--calling routine is allowed to append four characters * to the returned string, and wildspec may be a pointer to argv[]. */ if (!G.notfirstcall) { /* first call: must initialize everything */ G.notfirstcall = TRUE; if (!iswild(wildspec)) { strncpy(G.matchname, wildspec, FILNAMSIZ); G.matchname[FILNAMSIZ-1] = '\0'; G.have_dirname = FALSE; G.wild_dir = NULL; return G.matchname; } /* break the wildspec into a directory part and a wildcard filename */ if ((G.wildname = (ZCONST char *)strrchr(wildspec, '/')) == NULL) { G.dirname = "."; G.dirnamelen = 1; G.have_dirname = FALSE; G.wildname = wildspec; } else { ++G.wildname; /* point at character after '/' */ G.dirnamelen = G.wildname - wildspec; if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == (char *)NULL) { Info(slide, 0x201, ((char *)slide, "warning: cannot allocate wildcard buffers\n")); strncpy(G.matchname, wildspec, FILNAMSIZ); G.matchname[FILNAMSIZ-1] = '\0'; return G.matchname; /* but maybe filespec was not a wildcard */ } strncpy(G.dirname, wildspec, G.dirnamelen); G.dirname[G.dirnamelen] = '\0'; /* terminate for strcpy below */ G.have_dirname = TRUE; } if ((G.wild_dir = (zvoid *)opendir(G.dirname)) != (zvoid *)NULL) { while ((file = readdir((DIR *)G.wild_dir)) != (struct dirent *)NULL) { Trace((stderr, "do_wild: readdir returns %s\n", FnFilter1(file->d_name))); if (file->d_name[0] == '.' && G.wildname[0] != '.') continue; /* Unix: '*' and '?' do not match leading dot */ if (match(file->d_name, G.wildname, 0 WISEP) &&/*0=case sens.*/ /* skip "." and ".." directory entries */ strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) { Trace((stderr, "do_wild: match() succeeds\n")); if (G.have_dirname) { strcpy(G.matchname, G.dirname); strcpy(G.matchname+G.dirnamelen, file->d_name); } else strcpy(G.matchname, file->d_name); return G.matchname; } } /* if we get to here directory is exhausted, so close it */ closedir((DIR *)G.wild_dir); G.wild_dir = (zvoid *)NULL; } Trace((stderr, "do_wild: opendir(%s) returns NULL\n", FnFilter1(G.dirname))); /* return the raw wildspec in case that works (e.g., directory not * searchable, but filespec was not wild and file is readable) */ strncpy(G.matchname, wildspec, FILNAMSIZ); G.matchname[FILNAMSIZ-1] = '\0'; return G.matchname; } /* last time through, might have failed opendir but returned raw wildspec */ if ((DIR *)G.wild_dir == (DIR *)NULL) { G.notfirstcall = FALSE; /* nothing left--reset for new wildspec */ if (G.have_dirname) free(G.dirname); return (char *)NULL; } /* If we've gotten this far, we've read and matched at least one entry * successfully (in a previous call), so dirname has been copied into * matchname already. */ while ((file = readdir((DIR *)G.wild_dir)) != (struct dirent *)NULL) { Trace((stderr, "do_wild: readdir returns %s\n", FnFilter1(file->d_name))); if (file->d_name[0] == '.' && G.wildname[0] != '.') continue; /* Unix: '*' and '?' do not match leading dot */ if (match(file->d_name, G.wildname, 0 WISEP)) { /* 0 == case sens. */ Trace((stderr, "do_wild: match() succeeds\n")); if (G.have_dirname) { /* strcpy(G.matchname, G.dirname); */ strcpy(G.matchname+G.dirnamelen, file->d_name); } else strcpy(G.matchname, file->d_name); return G.matchname; } } closedir((DIR *)G.wild_dir); /* at least one entry read; nothing left */ G.wild_dir = (zvoid *)NULL; G.notfirstcall = FALSE; /* reset for new wildspec */ if (G.have_dirname) free(G.dirname); return (char *)NULL;} /* end function do_wild() */#endif /* !SFX */#ifndef S_ISUID# define S_ISUID 0004000 /* set user id on execution */#endif#ifndef S_ISGID# define S_ISGID 0002000 /* set group id on execution */#endif#ifndef S_ISVTX# define S_ISVTX 0001000 /* save swapped text even after use */#endif/************************//* Function filtattr() *//************************//* This is used to clear or keep the SUID and GID bits on file permissions. * It's possible that a file in an archive could have one of these bits set * and, unknown to the person unzipping, could allow others to execute the * file as the user or group. The new option -K bypasses this check. */static unsigned filtattr(__G__ perms) __GDEF unsigned perms;{ /* keep setuid/setgid/tacky perms? */ if (!uO.K_flag) perms &= ~(S_ISUID | S_ISGID | S_ISVTX); return (0xffff & perms);} /* end function filtattr() *//**********************//* Function mapattr() *//**********************/int mapattr(__G) __GDEF{ ulg tmp = G.crec.external_file_attributes; G.pInfo->file_attr = 0; /* initialized to 0 for check in "default" branch below... */ switch (G.pInfo->hostnum) { case AMIGA_: tmp = (unsigned)(tmp>>17 & 7); /* Amiga RWE bits */ G.pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp); break; case THEOS_: tmp &= 0xF1FFFFFFL; if ((tmp & 0xF0000000L) != 0x40000000L) tmp &= 0x01FFFFFFL; /* not a dir, mask all ftype bits */ else tmp &= 0x41FFFFFFL; /* leave directory bit as set */ /* fall through! */ case BEOS_: case UNIX_: case VMS_: case ACORN_: case ATARI_: case ATHEOS_: case QDOS_: case TANDEM_: G.pInfo->file_attr = (unsigned)(tmp >> 16); if (G.pInfo->file_attr != 0 || !G.extra_field) { return 0; } else { /* Some (non-Info-ZIP) implementations of Zip for Unix and * VMS (and probably others ??) leave 0 in the upper 16-bit * part of the external_file_attributes field. Instead, they * store file permission attributes in some extra field. * As a work-around, we search for the presence of one of * these extra fields and fall back to the MSDOS compatible * part of external_file_attributes if one of the known * e.f. types has been detected. * Later, we might implement extraction of the permission * bits from the VMS extra field. But for now, the work-around * should be sufficient to provide "readable" extracted files. * (For ASI Unix e.f., an experimental remap of the e.f. * mode value IS already provided!) */ ush ebID; unsigned ebLen; uch *ef = G.extra_field; unsigned ef_len = G.crec.extra_field_length; int r = FALSE; while (!r && ef_len >= EB_HEADSIZE) { ebID = makeword(ef); ebLen = (unsigned)makeword(ef+EB_LEN); if (ebLen > (ef_len - EB_HEADSIZE)) /* discoverd some e.f. inconsistency! */ break; switch (ebID) { case EF_ASIUNIX: if (ebLen >= (EB_ASI_MODE+2)) { G.pInfo->file_attr = (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE)); /* force stop of loop: */ ef_len = (ebLen + EB_HEADSIZE); break; } /* else: fall through! */ case EF_PKVMS: /* "found nondecypherable e.f. with perm. attr" */ r = TRUE; default: break; } ef_len -= (ebLen + EB_HEADSIZE); ef += (ebLen + EB_HEADSIZE); } if (!r) return 0; } /* fall through! */ /* all remaining cases: expand MSDOS read-only bit into write perms */ case FS_FAT_: /* PKWARE's PKZip for Unix marks entries as FS_FAT_, but stores the * Unix attributes in the upper 16 bits of the external attributes * field, just like Info-ZIP's Zip for Unix. We try to use that * value, after a check for consistency with the MSDOS attribute * bits (see below). */ G.pInfo->file_attr = (unsigned)(tmp >> 16); /* fall through! */ case FS_HPFS_: case FS_NTFS_: case MAC_: case TOPS20_: default: /* Ensure that DOS subdir bit is set when the entry's name ends * in a '/'. Some third-party Zip programs fail to set the subdir * bit for directory entries. */ if ((tmp & 0x10) == 0) { extent fnlen = strlen(G.filename); if (fnlen > 0 && G.filename[fnlen-1] == '/') tmp |= 0x10; } /* read-only bit --> write perms; subdir bit --> dir exec bit */ tmp = !(tmp & 1) << 1 | (tmp & 0x10) >> 4; if ((G.pInfo->file_attr & 0700) == (unsigned)(0400 | tmp<<6)) /* keep previous G.pInfo->file_attr setting, when its "owner" * part appears to be consistent with DOS attribute flags! */ return 0; G.pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -