/*********************************************************************** This file is part of HA, a general purpose file archiver. Copyright (C) 1995 Harri Hirvola This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ************************************************************************ HA *nix specific routines ***********************************************************************/ #include #include #include #include #include #include #include "ha.h" #include "error.h" #include "archive.h" #define HA_ISVTX 0x0200 #define HA_ISGID 0x0400 #define HA_ISUID 0x0800 #define HA_IRUSR 0x0100 #define HA_IWUSR 0x0080 #define HA_IXUSR 0x0040 #define HA_IRGRP 0x0020 #define HA_IWGRP 0x0010 #define HA_IXGRP 0x0008 #define HA_IROTH 0x0004 #define HA_IWOTH 0x0002 #define HA_IXOTH 0x0001 #define HA_IFMT 0xf000 #define HA_IFIFO 0x1000 #define HA_IFCHR 0x2000 #define HA_IFDIR 0x4000 #define HA_IFBLK 0x6000 #define HA_IFREG 0x8000 #define HA_IFLNK 0xa000 #define HA_IFSOCK 0xc000 #define HA_ISDIR(m) ((m&HA_IFMT)==HA_IFDIR) #define HA_ISCHR(m) ((m&HA_IFMT)==HA_IFCHR) #define HA_ISBLK(m) ((m&HA_IFMT)==HA_IFBLK) #define HA_ISLNK(m) ((m&HA_IFMT)==HA_IFLNK) #define HA_ISFIFO(m) ((m&HA_IFMT)==HA_IFIFO) #define HA_ISSOCK(m) ((m&HA_IFMT)==HA_IFSOCK) typedef struct { unsigned mtype; unsigned attr; unsigned user; unsigned group; } Mdhd; #define MDHDLEN 7 /* Length of Mdhd in archive */ static Mdhd mdhd; struct stat filestat; static void sig_handler(int signo) { error(1,ERR_INT,signo); } void md_init(void) { signal(SIGINT,sig_handler); signal(SIGTERM,sig_handler); signal(SIGPIPE,sig_handler); signal(SIGQUIT,sig_handler); umask(0); } U32B md_systime(void) { return (U32B)time(NULL); } static mode_t md_tomdattr(U16B haattr) { mode_t mdattr; mdattr=0; if (haattr&HA_IRUSR) mdattr|=S_IRUSR; if (haattr&HA_IWUSR) mdattr|=S_IWUSR; if (haattr&HA_ISUID) mdattr|=S_ISUID; if (haattr&HA_IXUSR) mdattr|=S_IXUSR; if (haattr&HA_IRGRP) mdattr|=S_IRGRP; if (haattr&HA_IWGRP) mdattr|=S_IWGRP; if (haattr&HA_ISGID) mdattr|=S_ISGID; if (haattr&HA_IXGRP) mdattr|=S_IXGRP; if (haattr&HA_IROTH) mdattr|=S_IROTH; if (haattr&HA_IWOTH) mdattr|=S_IWOTH; #ifdef S_ISVTX if (haattr&HA_ISVTX) mdattr|=S_ISVTX; #endif if (haattr&HA_IXOTH) mdattr|=S_IXOTH; return mdattr; } static U16B md_tohaattr(mode_t mdattr) { U16B haattr; haattr=0; if (mdattr&S_IRUSR) haattr|=HA_IRUSR; if (mdattr&S_IWUSR) haattr|=HA_IWUSR; if (mdattr&S_ISUID) haattr|=HA_ISUID; if (mdattr&S_IXUSR) haattr|=HA_IXUSR; if (mdattr&S_IRGRP) haattr|=HA_IRGRP; if (mdattr&S_IWGRP) haattr|=HA_IWGRP; if (mdattr&S_ISGID) haattr|=HA_ISGID; if (mdattr&S_IXGRP) haattr|=HA_IXGRP; if (mdattr&S_IROTH) haattr|=HA_IROTH; if (mdattr&S_IWOTH) haattr|=HA_IWOTH; if (mdattr&S_IXOTH) haattr|=HA_IXOTH; #ifdef S_ISVTX if (mdattr&S_ISVTX) haattr|=HA_ISVTX; #endif if (S_ISDIR(mdattr)) haattr|=HA_IFDIR; else if (S_ISCHR(mdattr)) haattr|=HA_IFCHR; else if (S_ISBLK(mdattr)) haattr|=HA_IFBLK; #ifdef S_ISLNK else if (S_ISLNK(mdattr)) haattr|=HA_IFLNK; #endif #ifdef S_ISFIFO else if (S_ISFIFO(mdattr)) haattr|=HA_IFIFO; #endif #ifdef S_ISSOCK else if (S_ISSOCK(mdattr)) haattr|=HA_IFSOCK; #endif return haattr; } static char *attrstring(unsigned haattr) { static char as[11]; sprintf(as,"%c%c%c%c%c%c%c%c%c%c", HA_ISFIFO(haattr)?'f':HA_ISSOCK(haattr)?'s':HA_ISLNK(haattr)?'l': HA_ISDIR(haattr)?'d':HA_ISCHR(haattr)?'c':HA_ISBLK(haattr)?'b':'-', (haattr&HA_IRUSR)?'r':'-', (haattr&HA_IWUSR)?'w':'-', (haattr&HA_ISUID)?(haattr& HA_IXUSR)?'s':'S':(haattr&HA_IXUSR)?'x':'-', (haattr&HA_IRGRP)?'r':'-', (haattr&HA_IWGRP)?'w':'-', (haattr&HA_ISGID)?(haattr& HA_IXGRP)?'s':'S':(haattr&HA_IXGRP)?'x':'-', (haattr&HA_IROTH)?'r':'-', (haattr&HA_IWOTH)?'w':'-', (haattr&HA_ISVTX)?(haattr& HA_IXOTH)?'t':'T':(haattr&HA_IXOTH)?'x':'-' ); return as; } void md_gethdr(int len, int mode) { static int longest=0; static unsigned char *buf=NULL; if (len>longest) { if (buf!=NULL) buf=realloc(buf,len); else buf=malloc(len); if (buf==NULL) error(1,ERR_MEM,"md_gethdr()"); longest=len; } read(arcfile,buf,len); mdhd.mtype=buf[0]; if (mdhd.mtype==UNIXMDH) { mdhd.attr=buf[1]|(buf[2]<<8); mdhd.user=buf[3]|(buf[4]<<8); mdhd.group=buf[5]|(buf[6]<<8); } else { switch (mode) { case M_DIR: mdhd.attr=md_tohaattr(DEF_DIRATTR); mdhd.attr|=HA_IFDIR; break; default: mdhd.attr=md_tohaattr(DEF_FILEATTR); break; } } } void md_puthdr(void) { unsigned char buf[MDHDLEN]; buf[0]=UNIXMDH; buf[1]=mdhd.attr&0xff; buf[2]=(mdhd.attr>>8)&0xff; buf[3]=mdhd.user&0xff; buf[4]=(mdhd.user>>8)&0xff; buf[5]=mdhd.group&0xff; buf[6]=(mdhd.group>>8)&0xff; write(arcfile,buf,MDHDLEN); } int md_filetype(char *path, char *name) { char *fullpath; if (!strcmp(name,".") || !strcmp(name,"..")) return T_SKIP; fullpath=md_pconcat(0,path,name); if (lstat(fullpath,&filestat)<0) { error(0,ERR_STAT,fullpath); free(fullpath); return T_SKIP; } free(fullpath); if (filestat.st_ino==arcstat.st_ino) return T_SKIP; if (S_ISDIR(filestat.st_mode)) return T_DIR; if (S_ISREG(filestat.st_mode)) return T_REGULAR; return T_SPECIAL; } int md_newfile(void) { mdhd.attr=md_tohaattr(filestat.st_mode); mdhd.user=filestat.st_uid; mdhd.group=filestat.st_gid; return MDHDLEN; } int md_special(char *fullname, unsigned char **sdata) { static unsigned char *dat=NULL; int len; if (dat!=NULL) { free(dat); dat=NULL; } if (HA_ISCHR(mdhd.attr)||HA_ISBLK(mdhd.attr)) { if ((dat=malloc(sizeof(dev_t)))==NULL) error(1,ERR_MEM,"md_special()"); *(dev_t*)dat=filestat.st_rdev; *sdata=dat; return sizeof(dev_t); } if (HA_ISLNK(mdhd.attr)) { if ((dat=malloc(1024))==NULL) error(1,ERR_MEM,"md_special()"); if ((len=readlink(fullname,(char*)dat,1024))<0) error(1,ERR_RDLINK,fullname); dat[len]=0; *sdata=dat; return len+1; } else { *sdata=dat; return 0; } } int md_mkspecial(char *ofname,unsigned sdlen,unsigned char *sdata) { if (mdhd.mtype!=UNIXMDH) { error(0,ERR_HOW,ofname); return 0; } if (HA_ISCHR(mdhd.attr)) { mknod(ofname,md_tomdattr(mdhd.attr)|S_IFCHR,*(dev_t*)sdata); if (useattr) chown(ofname,mdhd.user,mdhd.group); return 1; } else if (HA_ISBLK(mdhd.attr)) { mknod(ofname,md_tomdattr(mdhd.attr)|S_IFBLK,*(dev_t*)sdata); if (useattr) chown(ofname,mdhd.user,mdhd.group); return 1; } #ifdef S_ISLNK else if (HA_ISLNK(mdhd.attr)) { if (symlink(ofname,(char*)sdata)<0) error(0,ERR_MKLINK,sdata,ofname); if (useattr) { chmod(ofname,md_tomdattr(mdhd.attr)); chown(ofname,mdhd.user,mdhd.group); } return 1; } #endif #ifdef S_ISFIFO else if (HA_ISFIFO(mdhd.attr)) { if (mkfifo(ofname,md_tomdattr(mdhd.attr))<0) error(0,ERR_MKFIFO,sdata,ofname); if (useattr) chown(ofname,mdhd.user,mdhd.group); return 1; } #endif error(0,ERR_HOW,ofname); return 0; } void md_setfattrs(char *file) { if (useattr) { chmod(file,md_tomdattr(mdhd.attr)); chown(file,mdhd.user,mdhd.group); } } void md_setft(char *file,U32B time) { struct utimbuf utb; utb.actime=time; utb.modtime=time; utime(file,&utb); } void md_listhdr(void) { printf("\n attr"); } void md_listdat(void) { printf("\n %s",attrstring(mdhd.attr)); } char *md_timestring(unsigned long t) { static char ts[22]; struct tm *tim; tim=localtime((long *)&t); sprintf(ts,"%04d-%02d-%02d %02d:%02d",tim->tm_year+1900,tim->tm_mon+1, tim->tm_mday,tim->tm_hour,tim->tm_min); return ts; } char *md_arcname(char *name_req) { int pos; char *newname; pos=strlen(name_req); if (pos>3 && tolower(name_req[pos-1])=='a' && tolower(name_req[pos-2])=='h' && name_req[pos-3]=='.') return name_req; if ((newname=malloc(pos+4))==NULL) error(1,ERR_MEM,"md_arcname()"); strcpy(newname,name_req); strcpy(newname+pos,".ha"); return newname; } void md_truncfile(int fh, U32B len) { ftruncate(fh,len); } char *md_tohapath(char *mdpath) { int i,j; static char *hapath=NULL; if (hapath!=NULL) free(hapath),hapath=NULL; j=strlen(mdpath); for (i=0;mdpath[i];++i) if (mdpath[i]!='.' && mdpath[i]!='/') break; while (i>0 && mdpath[i-1]=='.') --i; if (i==0) skipemptypath=1; else skipemptypath=0; if ((hapath=malloc(j+1-i))==NULL) error(1,ERR_MEM,"md_tohapath()"); strcpy(hapath,mdpath+i); for (i=0;hapath[i];++i) if (hapath[i]=='/') hapath[i]=0xff; return md_strcase(hapath); } char *md_tomdpath(char *hapath) { int i; static char *mdpath=NULL; if (mdpath!=NULL) free(mdpath),mdpath=NULL; if ((mdpath=malloc(strlen(hapath)+1))==NULL) error(1,ERR_MEM,"md_tomdpath()"); strcpy(mdpath,hapath); for (i=0;mdpath[i];++i) if ((unsigned char)mdpath[i]==0xff) mdpath[i]='/'; return mdpath; } char *md_strippath(char *mdfullpath) { int i; static char *plainpath=NULL; if (plainpath!=NULL) free(plainpath),plainpath=NULL; if ((plainpath=malloc(strlen(mdfullpath)+1))==NULL) error(1,ERR_MEM,"md_strippath()"); strcpy(plainpath,mdfullpath); for (i=strlen(plainpath)-1;i>=0;i--) { if (plainpath[i]=='/') break; } plainpath[i+1]=0; return plainpath; } char *md_stripname(char *mdfullpath) { int i; static char *plainname=NULL; if (plainname!=NULL) free(plainname),plainname=NULL; if ((plainname=malloc(strlen(mdfullpath)+1))==NULL) error(1,ERR_MEM,"md_stripname()"); for (i=strlen(mdfullpath)-1;i>=0;i--) { if (mdfullpath[i]=='/') { i++; break; } } strcpy(plainname,mdfullpath+i); return plainname; } char *md_pconcat(int delim2, char *head, char *tail) { char *newpath; int headlen,delim1; delim1=0; if ((headlen=strlen(head))!=0) { if (head[headlen-1]!='/') delim1=1; } if ((newpath=malloc(headlen+strlen(tail)+delim2+delim1+1))==NULL) error(1,ERR_MEM,"md_pconcat()"); if (headlen!=0) strcpy(newpath,head); if (delim1) newpath[headlen]='/'; strcpy(newpath+headlen+delim1,tail); if (delim2) strcpy(newpath+strlen(newpath),"/"); return newpath; } int md_namecmp(char *pat, char *cmp) { if (*pat==0) return !*cmp; if (*pat=='?') { if (!*cmp) return 0; return md_namecmp(pat+1,cmp+1); } if (*pat=='*') { if (*(pat+1)==0) return 1; for (;*cmp;++cmp) { if (md_namecmp(pat+1,cmp)) return 1; } return 0; } if (*pat=='\\') { ++pat; if (*pat==0) return 0; } if (*pat==*cmp) return md_namecmp(pat+1,cmp+1); return 0; }