/*----------------------------------------------------------------------*/ /* LHarc Archiver Driver for UNIX */ /* */ /* Copyright(C) MCMLXXXIX Yooichi.Tagawa */ /* Thanks to H.Yoshizaki. (MS-DOS LHarc) */ /* */ /* V0.00 Original 1988.05.23 Y.Tagawa */ /* V0.01 Alpha Version (for 4.2BSD) 1989.05.28 Y.Tagawa */ /* V0.02 Alpha Version Rel.2 1989.05.29 Y.Tagawa */ /* V0.03 Release #3 Beta Version 1989.07.02 Y.Tagawa */ /* V0.03a Fix few bug 1989.07.03 Y.Tagawa */ /*----------------------------------------------------------------------*/ #include #include #ifdef atarist #include #include #include #include #include #include #endif #include #include #include /* most of System V, define SYSTIME_HAS_NO_TM */ #ifdef SYSTIME_HAS_NO_TM #include #else #include #endif /* #include */ /* #include */ /*----------------------------------------------------------------------*/ /* DIRECTORY ACCESS STUFF */ /*----------------------------------------------------------------------*/ #ifndef NODIRECTORY #ifdef SYSV_SYSTEM_DIR #include #define DIRENTRY struct dirent #define NAMLEN(p) ((int)strlen (p->d_name)) #else /* not SYSV_SYSTEM_DIR */ #ifdef NONSYSTEM_DIR_LIBRARY #include "lhdir.h" #else /* not NONSYSTEM_DIR_LIBRARY */ #include #endif /* not NONSYSTEM_DIR_LIBRARY */ #define DIRENTRY struct direct #define NAMLEN(p) p->d_namlen extern DIR *opendir (); extern struct direct *readdir (); #endif /* not SYSV_SYSTEM_DIR */ #endif /*----------------------------------------------------------------------*/ /* FILE ATTRIBUTES */ /*----------------------------------------------------------------------*/ /* If file mode is not compatible between your Machine/OS and LHarc standard UNIX file mode. (See UNIX Manual stat(1), , and/or below UNIX_* difinitions. ) */ /* #define NOT_COMPATIBLE_MODE */ /*----------------------------------------------------------------------*/ /* MEMORY FUNCTIONS */ /*----------------------------------------------------------------------*/ #ifdef NOBSTRING #ifdef __ANSI__ #include "mem.h" #define bcmp(a,b,n) memcmp ((a),(b),(n)) #define bcopy(s,d,n) memmove((d),(s),(n)) #define bzero(d,n) memset((d),0,(n)) #else /* not __ANSI__ */ #include "memory.h" #define bcmp(a,b,n) memcmp ((a),(b),(n)) #define bcopy(s,d,n) memcpy ((d),(s),(n)) /* movmem((s),(d),(n)) */ #define bzero(d,n) memset((d),0,(n)) #endif /* not __ANSI__ */ #endif /* NOBSTRING */ /*----------------------------------------------------------------------*/ /* YOUR CUSTOMIZIES */ /*----------------------------------------------------------------------*/ /* These difinitions are changable to you like. */ #define ARCHIVENAME_EXTENTION ".lzh" #ifndef atarist #define TMP_FILENAME_TEMPLATE "/tmp/lhXXXXXX" #else #define TMP_FILENAME_TEMPLATE "lhXXXXXX" #endif #define BACKUPNAME_EXTENTION ".bak" /* #define MULTIBYTE_CHAR */ /* #define USE_PROF */ #define SJC_FIRST_P(c) \ (((unsigned char)(c) >= 0x80) && \ (((unsigned char)(c) < 0xa0) || \ ((unsigned char)(c) >= 0xe0) && \ ((unsigned char)(c) < 0xfd))) #define SJC_SECOND_P(c) \ (((unsigned char)(c) >= 0x40) && \ ((unsigned char)(c) < 0xfd) && \ ((ungigned char)(c) != 0x7f)) #ifdef MULTIBYTE_CHAR #define MULTIBYTE_FIRST_P SJC_FIRST_P #define MULTIBYTE_SECOND_P SJC_SECOND_P #endif MULTIBYTE_CHAR /*----------------------------------------------------------------------*/ /* OTHER DIFINITIONS */ /*----------------------------------------------------------------------*/ #ifndef SEEK_SET #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif #ifdef ultrix #define R_MODE "r" #define W_MODE "w" #else #define R_MODE "rb" #define W_MODE "wb" #endif #ifndef atarist #define FILENAME_LENGTH 1024 #else #define FILENAME_LENGTH FILENAME_MAX #endif /* non-integral functions */ extern struct tm *localtime (); extern char *getenv (); #ifndef atarist extern char *malloc (); extern char *realloc (); #endif /* external variables */ extern int errno; #define FALSE 0 #define TRUE 1 typedef int boolean; /*----------------------------------------------------------------------*/ /* LHarc FILE DIFINITIONS */ /*----------------------------------------------------------------------*/ #define METHOD_TYPE_STRAGE 5 #define LZHUFF0_METHOD "-lh0-" #define LZHUFF1_METHOD "-lh1-" #define LARC4_METHOD "-lz4-" #define LARC5_METHOD "-lz5-" #define I_HEADER_SIZE 0 #define I_HEADER_CHECKSUM 1 #define I_METHOD 2 #define I_PACKED_SIZE 7 #define I_ORIGINAL_SIZE 11 #define I_LAST_MODIFIED_STAMP 15 #define I_ATTRIBUTE 19 #define I_NAME_LENGTH 21 #define I_NAME 22 #define I_CRC 22 /* + name_length */ #define I_EXTEND_TYPE 24 /* + name_length */ #define I_MINOR_VERSION 25 /* + name_length */ #define I_UNIX_LAST_MODIFIED_STAMP 26 /* + name_length */ #define I_UNIX_MODE 30 /* + name_length */ #define I_UNIX_UID 32 /* + name_length */ #define I_UNIX_GID 34 /* + name_length */ #define I_UNIX_EXTEND_BOTTOM 36 /* + name_length */ #define EXTEND_GENERIC 0 #define EXTEND_UNIX 'U' #define EXTEND_MSDOS 'M' #define EXTEND_MACOS 'm' #define EXTEND_OS9 '9' #define EXTEND_OS2 '2' #define EXTEND_OS68K 'K' #define EXTEND_OS386 '3' #define EXTEND_HUMAN 'H' #define EXTEND_CPM 'C' #define EXTEND_FLEX 'F' #define GENERIC_ATTRIBUTE 0x20 #define GENERIC_DIRECTORY_ATTRIBUTE 0x10 #define CURRENT_UNIX_MINOR_VERSION 0x00 typedef struct LzHeader { unsigned char header_size; char method[METHOD_TYPE_STRAGE]; long packed_size; long original_size; long last_modified_stamp; unsigned short attribute; char name[256]; unsigned short crc; boolean has_crc; unsigned char extend_type; unsigned char minor_version; /* extend_type == EXTEND_UNIX and convert from other type. */ time_t unix_last_modified_stamp; unsigned short unix_mode; unsigned short unix_uid; unsigned short unix_gid; } LzHeader; #define UNIX_FILE_TYPEMASK 0170000 #define UNIX_FILE_REGULAR 0100000 #define UNIX_FILE_DIRECTORY 0040000 #define UNIX_SETUID 0004000 #define UNIX_SETGID 0002000 #define UNIX_STYCKYBIT 0001000 #define UNIX_OWNER_READ_PERM 0000400 #define UNIX_OWNER_WRITE_PERM 0000200 #define UNIX_OWNER_EXEC_PERM 0000100 #define UNIX_GROUP_READ_PERM 0000040 #define UNIX_GROUP_WRITE_PERM 0000020 #define UNIX_GROUP_EXEC_PERM 0000010 #define UNIX_OTHER_READ_PERM 0000004 #define UNIX_OTHER_WRITE_PERM 0000002 #define UNIX_OTHER_EXEC_PERM 0000001 #define UNIX_RW_RW_RW 0000666 #define LZHEADER_STRAGE 256 #include "proto.h" static boolean expand_archive_name P((char *dst , char *src )); static int sort_by_ascii P((char **a , char **b )); static boolean find_files P((char *name , int *v_filec , char ***v_filev )); static free_files P((int filec , char **filev )); static int calc_sum P((char *p , int len )); static unsigned short get_word P((void )); static put_word P((unsigned int v )); static long get_longword P((void )); static put_longword P((long v )); static msdos_to_unix_filename P((char *name , int len )); static generic_to_unix_filename P((char *name , int len )); static macos_to_unix_filename P((char *name , int len )); static long gettz P((void )); static struct tm *msdos_to_unix_stamp_tm P((long a )); static time_t generic_to_unix_stamp P((long t )); static long unix_to_generic_stamp P((time_t t )); static boolean get_header P((FILE *fp , LzHeader *hdr )); static init_header P((char *name , struct stat *v_stat , LzHeader *hdr )); static boolean archive_is_msdos_sfx1 P((char *name )); static boolean skip_msdos_sfx1_code P((FILE *fp )); static make_standard_archive_name P((char *name , char *orginal )); static boolean make_parent_path P((char *name )); static FILE *open_with_make_path P((char *name )); static copy_old_one P((FILE *oafp , FILE *nafp , LzHeader *hdr )); static int write_header P((FILE *nafp , LzHeader *hdr )); static int extract_one P((FILE *fp , LzHeader *hdr )); static int append_one P((FILE *fp , FILE *nafp , LzHeader *hdr )); static boolean need_file P((char *name )); #ifdef atarist static int st_truncate (FILE *fp, long pos); static void stexit (int status); #endif #undef P /*----------------------------------------------------------------------*/ /* PROGRAM */ /*----------------------------------------------------------------------*/ #define CMD_UNKNOWN 0 #define CMD_EXTRACT 1 #define CMD_APPEND 2 #define CMD_VIEW 3 static int cmd = CMD_UNKNOWN; static char **cmd_filev; static int cmd_filec; static char *archive_name; static char expanded_archive_name[FILENAME_LENGTH]; static char temporary_name[FILENAME_LENGTH]; /* options */ boolean quiet = FALSE; boolean text_mode = FALSE; /*static boolean verbose = FALSE; */ static boolean noexec = FALSE; /* debugging option */ static boolean force = FALSE; static boolean prof = FALSE; static boolean backup = FALSE; #ifdef atarist static boolean hold = FALSE; #endif /* view flags */ static boolean long_format_listing = FALSE; /* extract flags */ static boolean output_to_stdout = FALSE; #ifdef TSTFLG boolean tstflg = FALSE; #endif /* append flags */ static boolean new_archive = FALSE; static boolean update_if_newer = FALSE; static boolean update_freshen = FALSE; static boolean delete_after_append = FALSE; static boolean delete_from_archive = FALSE; static boolean remove_temporary_at_error = FALSE; #ifdef atarist /* Additional variables for Atari specific chores */ extern char arcshpath[]; /* Path for ARCSHELL */ static boolean arcsh_flg = FALSE; /* Using ARCSHELL ? */ extern char **targv; extern int targc; extern char dirbuf[]; /* Original directory when using ARCSHELL */ extern int wildcard; extern int desktop; extern int fullpath; #endif /*----------------------------------------------------------------------*/ /* NOTES : Text File Format */ /* GENERATOR NewLine */ /* [generic] 0D 0A */ /* [MS-DOS] 0D 0A */ /* [MacOS] 0D */ /* [UNIX] 0A */ /*----------------------------------------------------------------------*/ #ifndef atarist main (argc, argv) #else lzmain(argc, argv) #endif int argc; char *argv[]; { char *p; if (argc < 3) print_tiny_usage_and_exit (); /* commands */ #ifndef atarist switch (argv[1][0]) { #ifdef TSTFLG case 't': tstflg = TRUE; #endif case 'x': case 'e': cmd = CMD_EXTRACT; break; case 'p': output_to_stdout = TRUE; cmd = CMD_EXTRACT; break; case 'c': new_archive = TRUE; cmd = CMD_APPEND; break; case 'a': cmd = CMD_APPEND; break; case 'd': delete_from_archive = TRUE; cmd = CMD_APPEND; break; case 'u': update_if_newer = TRUE; cmd = CMD_APPEND; break; case 'm': delete_after_append = TRUE; cmd = CMD_APPEND; break; case 'l': long_format_listing = TRUE; case 'v': cmd = CMD_VIEW; break; case 'h': default: print_tiny_usage_and_exit (); } /* options */ p = &argv[1][1]; for (p = &argv[1][1]; *p; ) { switch (*p++) { case 'q': quiet = TRUE; break; case 'f': force = TRUE; break; case 'p': prof = TRUE; break; /* case 'v': verbose = TRUE; break; */ case 't': text_mode = TRUE; break; case 'n': noexec = TRUE; break; default: fprintf (stderr, "unknown option '%c'.\n", p[-1]); exit (1); } } #else switch (tolower (argv[1][0])) /* Converts from upper case only < TOS 1.4 */ { case 't': tstflg = TRUE; case 'x': case 'e': cmd = CMD_EXTRACT; break; case 'p': output_to_stdout = TRUE; cmd = CMD_EXTRACT; break; case 'c': new_archive = TRUE; cmd = CMD_APPEND; break; case 'm': delete_after_append = TRUE; case 'a': cmd = CMD_APPEND; break; case 'd': delete_from_archive = TRUE; fullpath = TRUE; cmd = CMD_APPEND; break; case 'u': update_if_newer = TRUE; cmd = CMD_APPEND; break; case 'f': update_if_newer = update_freshen = TRUE; cmd = CMD_APPEND; break; case 'v': long_format_listing = TRUE; case 'l': cmd = CMD_VIEW; break; default: print_tiny_usage_and_exit (); } /* options */ p = &argv[1][1]; for (p = &argv[1][1]; *p; ) { switch (tolower (*p++)) /* Converts from upper case only for < TOS 1.4 */ { case 'q': quiet = TRUE; break; case 'f': force = TRUE; break; case 'z': if (desktop) fullpath = TRUE; else fullpath = FALSE; break; case 's': text_mode = TRUE; break; case 'n': noexec = TRUE; break; case 'b': backup = TRUE; break; case 'h': hold = TRUE; break; default: fprintf (stderr, "unknown option '%c'.\n", p[-1]); stexit (1); } } #endif /* archive file name */ archive_name = argv[2]; /* target file name */ cmd_filec = argc - 3; #ifdef ultrix cmd_filev = &argv[3]; #else cmd_filev = argv + 3; #endif sort_files (); switch (cmd) { case CMD_EXTRACT: cmd_extract (); break; case CMD_APPEND: cmd_append (); break; case CMD_VIEW: cmd_view (); break; } #ifdef USE_PROF if (!prof) exit (0); #endif #ifndef atarist exit (0); #else stexit (0); #endif } print_tiny_usage_and_exit () { #ifndef atarist fprintf (stderr, "\ LHarc for UNIX V0.03 (Beta Version) Copyright(C) 1989 Y.Tagawa\n\ usage: lharc {axevludmcp}[qnft] archive_file [files or directories...]\n\ commands: options: \n\ a Append q quiet \n\ x,e EXtract n no execute \n\ v,l View/List f force (over write at extract) \n\ u Update newer files \n\ d Delete t FILES are TEXT file \n\ m Move \n\ c re-Construct new archive \n\ p Print to STDOUT \n\ t Test the archive only \n\ "); exit (1); #else fprintf (stderr, "LHarc for the Atari ST V1.2 Based on UNIX V0.03 (C) Y. Tagawa\n\ ===============================================================12/07/90========\n\ <<< High-performance file-compression program >>>\n\ ===============================================================================\n\ usage : xlharc {}[] archive [files or directories]\n\ -------------------------------------------------------------------------------\n\ \n\ a: Add files to archive u: Update files to archive\n\ f: Freshen files in archive m: Move new files into archive\n\ d: Delete files from archive e,x: EXtract files from archive\n\ p: disPlay files in archive l,v: View List of files in archive\n\ c: re-Construct new archive t: Test integrity of archive\n\ \n\ b: keep a Backup h: Hold screen\n\ q: Quiet mode f: Force overwrite at extract\n\ s: files are text files z: %s\n\ ===============================================================================\n\ Atari ST version ported by Bill Shroka bjsjr@NCoast.ORG\n\ GEnie: B.Shroka\n", (desktop) ? "distinguish full pathnames" : "ignore full pathnames"); stexit (1); #endif } message (title, msg) char *title, *msg; { fprintf (stderr, "LHarc: "); if (errno == 0) fprintf (stderr, "%s %s\n", title, msg); else perror (msg); } warning (msg) char *msg; { message ("Warning :", msg); } error (msg) char *msg; { message ("Error :", msg); if (remove_temporary_at_error) unlink (temporary_name); #ifndef atarist exit (1); #else stexit (1); #endif } static char *writting_filename; static char *reading_filename; write_error () { error (writting_filename); } read_error () { error (reading_filename); } /*----------------------------------------------------------------------*/ /* */ /*----------------------------------------------------------------------*/ static boolean expand_archive_name (dst, src) char *dst, *src; { register char *p, *dot; strcpy (dst, src); for (p = dst, dot = (char*)0; *p; p++) if (*p == '.') dot = p; else if (*p == '/') dot = (char*)0; if (dot) p = dot; #ifdef ARCHIVENAME_EXTENTION strcpy (p, ARCHIVENAME_EXTENTION); #else strcpy (p, ".lzh"); #endif return (strcmp (dst, src) != 0); } #define STRING_COMPARE(a,b) strcmp((a),(b)) static int sort_by_ascii (a, b) char **a, **b; { return STRING_COMPARE (*a, *b); } sort_files () { if(cmd_filec > 0) qsort (cmd_filev, cmd_filec, sizeof (char*), sort_by_ascii); } #ifndef atarist static char *strdup (string) char *string; { int len = strlen (string) + 1; char *p = malloc (len); bcopy (string, p, len); return p; } #endif #ifdef NODIRECTORY /* please need your imprementation */ static boolean find_files (name, v_filec, v_filev) char *name; int *v_filec; char ***v_filev; { return FALSE; /* DUMMY */ } #else #define NUM_ENTRIES 61 /* Added for clarity and ease of change bjsjr */ static boolean find_files (name, v_filec, v_filev) char *name; int *v_filec; char ***v_filev; { char newname[FILENAME_LENGTH]; int len, n; DIR *dirp; DIRENTRY *dp; int alloc_size = sizeof (char**) * NUM_ENTRIES; /* any (^_^) */ char **filev; int filec = 0; int alloc_counter = 0; /* Counter to notify when it's time to realloc bjsjr */ strcpy (newname, name); len = strlen (name); dirp = opendir (name); if (dirp) { filev = (char**)malloc (alloc_size); if (!filev) error ("not enough memory"); for (dp = readdir (dirp); dp != NULL; dp = readdir (dirp)) { n = NAMLEN (dp); if ((dp->d_ino != 0) && ((dp->d_name[0] != '.') || ((n != 1) && ((dp->d_name[1] != '.') || (n != 2)))) && /* exclude '.' and '..' */ (strcmp (dp->d_name, temporary_name) != 0) && (strcmp (dp->d_name, archive_name) != 0)) { if ((len != 0) && (newname[len-1] != '/')) { newname[len] = '/'; strncpy (newname+len+1, dp->d_name, n); newname[len+n+1] = '\0'; } else { strncpy (newname+len, dp->d_name, n); newname[len+n] = '\0'; } filev[filec++] = strdup (newname); if (++alloc_counter == NUM_ENTRIES) /* If true, time to realloc */ { alloc_counter = 0; /* Reset counter */ alloc_size *= 2; filev = (char**)realloc (filev, alloc_size); } } } closedir (dirp); } *v_filev = filev; *v_filec = filec; if (dirp) { qsort (filev, filec, sizeof (char*), sort_by_ascii); return TRUE; } else return FALSE; } #endif static free_files (filec, filev) int filec; char **filev; { int i; for (i = 0; i < filec; i ++) free (filev[i]); free (filev); } /*----------------------------------------------------------------------*/ /* */ /*----------------------------------------------------------------------*/ static int calc_sum (p, len) register char *p; register int len; { register int sum; for (sum = 0; len; len--) sum += *p++; return sum & 0xff; } static unsigned char *get_ptr; #define setup_get(PTR) get_ptr = (unsigned char*)(PTR) #define get_byte() (*get_ptr++) #define put_ptr get_ptr #define setup_put(PTR) put_ptr = (unsigned char*)(PTR) #define put_byte(c) *put_ptr++ = (unsigned char)(c) static unsigned short get_word () { int b0, b1; b0 = get_byte (); b1 = get_byte (); return (b1 << 8) + b0; } static put_word (v) unsigned int v; { put_byte (v); put_byte (v >> 8); } static long get_longword () { long b0, b1, b2, b3; b0 = get_byte (); b1 = get_byte (); b2 = get_byte (); b3 = get_byte (); return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0; } static put_longword (v) long v; { put_byte (v); put_byte (v >> 8); put_byte (v >> 16); put_byte (v >> 24); } static msdos_to_unix_filename (name, len) register char *name; register int len; { register int i; #ifdef MULTIBYTE_CHAR for (i = 0; i < len; i ++) { if (MULTIBYTE_FIRST_P (name[i]) && MULTIBYTE_SECOND_P (name[i+1])) i ++; else if (name[i] == '\\') name[i] = '/'; else if (isupper (name[i])) name[i] = tolower (name[i]); } #else for (i = 0; i < len; i ++) { if (name[i] == '\\') name[i] = '/'; else if (isupper (name[i])) name[i] = tolower (name[i]); } #endif } static generic_to_unix_filename (name, len) register char *name; register int len; { register int i; boolean lower_case_used = FALSE; #ifdef MULTIBYTE_CHAR for (i = 0; i < len; i ++) { if (MULTIBYTE_FIRST_P (name[i]) && MULTIBYTE_SECOND_P (name[i+1])) i ++; else if (islower (name[i])) { lower_case_used = TRUE; break; } } for (i = 0; i < len; i ++) { if (MULTIBYTE_FIRST_P (name[i]) && MULTIBYTE_SECOND_P (name[i+1])) i ++; else if (name[i] == '\\') name[i] = '/'; else if (!lower_case_used && isupper (name[i])) name[i] = tolower (name[i]); } #else for (i = 0; i < len; i ++) if (islower (name[i])) { lower_case_used = TRUE; break; } for (i = 0; i < len; i ++) { if (name[i] == '\\') name[i] = '/'; else if (!lower_case_used && isupper (name[i])) name[i] = tolower (name[i]); } #endif } static macos_to_unix_filename (name, len) register char *name; register int len; { register int i; for (i = 0; i < len; i ++) { if (name[i] == ':') name[i] = '/'; else if (name[i] == '/') name[i] = ':'; } } /*----------------------------------------------------------------------*/ /* */ /* Generic stamp format: */ /* */ /* 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 */ /* |<-------- year ------->|<- month ->|<-- day -->| */ /* */ /* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 */ /* |<--- hour --->|<---- minute --->|<- second*2 ->| */ /* */ /*----------------------------------------------------------------------*/ #ifdef atarist long gettz() { struct tm *tm; static char first_time = 1; static long t; extern time_t _timezone; if(first_time) { first_time = 0; t = time ((long *) 0); tm = localtime (&t); t = _timezone - tm->tm_isdst*3600; } return t; } #else static long gettz () { struct timeval tp; struct timezone tzp; gettimeofday (&tp, &tzp); /* specific to 4.3BSD */ /* return (tzp.tz_minuteswest * 60 + (tzp.tz_dsttime != 0 ? 60L * 60L : 0));*/ return (tzp.tz_minuteswest * 60); } #endif #ifdef NOT_USED static struct tm *msdos_to_unix_stamp_tm (a) long a; { static struct tm t; t.tm_sec = ( a & 0x1f) * 2; t.tm_min = (a >> 5) & 0x3f; t.tm_hour = (a >> 11) & 0x1f; t.tm_mday = (a >> 16) & 0x1f; t.tm_mon = (a >> 16+5) & 0x0f - 1; t.tm_year = ((a >> 16+9) & 0x7f) + 80; return &t; } #endif static time_t generic_to_unix_stamp (t) long t; { int year, month, day, hour, min, sec; long longtime; static unsigned int dsboy[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; unsigned int days; year = ((int)(t >> 16+9) & 0x7f) + 1980; month = (int)(t >> 16+5) & 0x0f; /* 1..12 means Jan..Dec */ day = (int)(t >> 16) & 0x1f; /* 1..31 means 1st,...31st */ hour = ((int)t >> 11) & 0x1f; min = ((int)t >> 5) & 0x3f; sec = ((int)t & 0x1f) * 2; /* Calculate days since 1970.01.01 */ days = (365 * (year - 1970) + /* days due to whole years */ (year - 1970 + 1) / 4 + /* days due to leap years */ dsboy[month-1] + /* days since beginning of this year */ day-1); /* days since beginning of month */ if ((year % 4 == 0) && (year % 400 != 0) && (month >= 3)) /* if this is a leap year and month */ days++; /* is March or later, add a day */ /* Knowing the days, we can find seconds */ /* Added time_t cast -bjsjr */ longtime = ((((time_t)days * 24) + hour) * 60 + min) * 60 + sec; longtime += gettz (); /* adjust for timezone */ /* special case: if MSDOS format date and time were zero, then we set time to be zero here too. */ if (t == 0) longtime = 0; /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00. */ return (time_t)longtime; } static long unix_to_generic_stamp (t) time_t t; { if(!t) return 0L; else { struct tm *tm = localtime (&t); return ((((long)(tm->tm_year - 80)) << 25) + (((long)(tm->tm_mon + 1)) << 21) + (((long)tm->tm_mday) << 16) + (long)((tm->tm_hour << 11) + (tm->tm_min << 5) + (tm->tm_sec / 2))); } } /*----------------------------------------------------------------------*/ /* */ /*----------------------------------------------------------------------*/ static boolean get_header (fp, hdr) FILE *fp; register LzHeader *hdr; { int header_size; int name_length; char data[LZHEADER_STRAGE]; int checksum; int i; bzero (hdr, sizeof (LzHeader)); if (((header_size = getc (fp)) == EOF) || (header_size == 0)) { return FALSE; /* finish */ } if (fread (data + I_HEADER_CHECKSUM, sizeof (char), header_size + 1, fp) < header_size + 1) { error ("Invalid header (LHarc file ?)"); return FALSE; /* finish */ } setup_get (data + I_HEADER_CHECKSUM); checksum = calc_sum (data + I_METHOD, header_size); if (get_byte () != checksum) warning ("Checksum error (LHarc file?)"); hdr->header_size = header_size; bcopy (data + I_METHOD, hdr->method, METHOD_TYPE_STRAGE); #ifdef OLD if ((bcmp (hdr->method, LZHUFF1_METHOD, METHOD_TYPE_STRAGE) != 0) && (bcmp (hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STRAGE) != 0) && (bcmp (hdr->method, LARC5_METHOD, METHOD_TYPE_STRAGE) != 0) && (bcmp (hdr->method, LARC4_METHOD, METHOD_TYPE_STRAGE) != 0)) { warning ("Unknown method (LHarc file ?)"); return FALSE; /* invalid method */ } #endif setup_get (data + I_PACKED_SIZE); hdr->packed_size = get_longword (); hdr->original_size = get_longword (); hdr->last_modified_stamp = get_longword (); hdr->attribute = get_word (); name_length = get_byte (); for (i = 0; i < name_length; i ++) hdr->name[i] =(char)get_byte (); hdr->name[name_length] = '\0'; /* defaults for other type */ hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW; hdr->unix_gid = 0; hdr->unix_uid = 0; if (header_size - name_length >= 24) { /* EXTEND FORMAT */ hdr->crc = get_word (); hdr->extend_type = get_byte (); hdr->minor_version = get_byte (); hdr->has_crc = TRUE; } else if (header_size - name_length == 22) { /* Generic with CRC */ hdr->crc = get_word (); hdr->extend_type = EXTEND_GENERIC; hdr->has_crc = TRUE; } else if (header_size - name_length == 20) { /* Generic no CRC */ hdr->extend_type = EXTEND_GENERIC; hdr->has_crc = FALSE; } else { warning ("Unknown header (LHarc file ?)"); return FALSE; } switch (hdr->extend_type) { case EXTEND_MSDOS: msdos_to_unix_filename (hdr->name, name_length); hdr->unix_last_modified_stamp = generic_to_unix_stamp (hdr->last_modified_stamp); break; case EXTEND_UNIX: hdr->unix_last_modified_stamp = (time_t)get_longword (); hdr->unix_mode = get_word (); hdr->unix_uid = get_word (); hdr->unix_gid = get_word (); break; case EXTEND_MACOS: macos_to_unix_filename (hdr->name, name_length); hdr->unix_last_modified_stamp = generic_to_unix_stamp (hdr->last_modified_stamp); break; default: generic_to_unix_filename (hdr->name, name_length); hdr->unix_last_modified_stamp = generic_to_unix_stamp (hdr->last_modified_stamp); } return TRUE; } static init_header (name, v_stat, hdr) char *name; struct stat *v_stat; LzHeader *hdr; { #ifdef atarist char *temp; #endif bcopy (LZHUFF1_METHOD, hdr->method, METHOD_TYPE_STRAGE); hdr->packed_size = 0; hdr->original_size = v_stat->st_size; hdr->last_modified_stamp = unix_to_generic_stamp (v_stat->st_mtime); hdr->attribute = GENERIC_ATTRIBUTE; #ifndef atarist strcpy (hdr->name, name); #else if (fullpath || delete_from_archive) { temp = strchr (name, ':'); strcpy (hdr->name, temp ? (temp + 2) : name); } else { temp = strrchr (name, '\\'); strcpy (hdr->name, temp ? ++temp : name); } #endif hdr->crc = 0x0000; hdr->extend_type = EXTEND_UNIX; hdr->unix_last_modified_stamp = v_stat->st_mtime; /* 00:00:00 since JAN.1.1970 */ #ifdef NOT_COMPATIBLE_MODE Please need your modification in this space. #else hdr->unix_mode = v_stat->st_mode; #endif hdr->unix_uid = v_stat->st_uid; hdr->unix_gid = v_stat->st_gid; if (!delete_from_archive) if ((v_stat->st_mode & S_IFMT) == S_IFDIR) { bcopy (LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE); hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE; hdr->original_size = 0; strcat (hdr->name, "/"); } } /* Write only unix extended header. */ static write_header (nafp, hdr) FILE *nafp; LzHeader *hdr; { int header_size; int name_length; char data[LZHEADER_STRAGE]; bzero (data, LZHEADER_STRAGE); bcopy (hdr->method, data + I_METHOD, METHOD_TYPE_STRAGE); setup_put (data + I_PACKED_SIZE); put_longword (hdr->packed_size); put_longword (hdr->original_size); put_longword (hdr->last_modified_stamp); put_word (hdr->attribute); name_length = strlen (hdr->name); put_byte (name_length); bcopy (hdr->name, data + I_NAME, name_length); setup_put (data + I_NAME + name_length); put_word (hdr->crc); put_byte (EXTEND_UNIX); put_byte (CURRENT_UNIX_MINOR_VERSION); put_longword ((long)hdr->unix_last_modified_stamp); put_word (hdr->unix_mode); put_word (hdr->unix_uid); put_word (hdr->unix_gid); header_size = I_UNIX_EXTEND_BOTTOM - 2 + name_length; data[I_HEADER_SIZE] = header_size; data[I_HEADER_CHECKSUM] = calc_sum (data + I_METHOD, header_size); if (fwrite (data, sizeof (char), header_size + 2, nafp) == 0) error ("cannot write to temporary file"); } static boolean archive_is_msdos_sfx1 (name) char *name; { int len = strlen (name); return ((len >= 4) && (strcmp (name + len - 4, ".com") == 0 || strcmp (name + len - 4, ".exe") == 0 || strcmp (name + len - 4, ".ttp") == 0 || strcmp (name + len - 4, ".prg") == 0 || strcmp (name + len - 4, ".tos") == 0)); } static boolean skip_msdos_sfx1_code (fp) FILE *fp; { unsigned char buffer[2048]; unsigned char *p, *q; int n; n = fread (buffer, sizeof (char), 2048, fp); for (p = buffer + 2, q = buffer + n - 5; p < q; p ++) { /* found "-l??-" keyword (as METHOD type string) */ if (p[0] == '-' && p[1] == 'l' && p[4] == '-') { /* size and checksum validate check */ if (p[-2] > 20 && p[-1] == calc_sum (p, p[-2])) { fseek (fp, ((p - 2) - buffer) - n, SEEK_CUR); return TRUE; } } } fseek (fp, -n, SEEK_CUR); return FALSE; } /*----------------------------------------------------------------------*/ /* */ /*----------------------------------------------------------------------*/ make_tmp_name (original, name) char *original; char *name; { #ifdef TMP_FILENAME_TEMPLATE /* "/tmp/lhXXXXXX" etc. */ char *lhtemp; char c; extern char *rindex(), *getenv(); if (lhtemp = getenv ("ARCTEMP")) { strcpy (name, lhtemp); /*if(lhtemp[(strlen(lhtemp) - 1)] != '/')*/ c = lhtemp[(strlen(lhtemp) - 1)]; if ((c != '/') && (c != '\\')) strcat (name, "/"); strcat(name, (((lhtemp = rindex(TMP_FILENAME_TEMPLATE, '/')) == NULL)? TMP_FILENAME_TEMPLATE : &lhtemp[1])); } else strcpy (name, TMP_FILENAME_TEMPLATE); #else char *p, *s; strcpy (name, original); for (p = name, s = (char*)0; *p; p++) if (*p == '/') s = p; strcpy ((s ? s+1 : name), "#..lhXXXXXX"); #endif mktemp (name); } make_backup_name (name, orginal) char *name; char *orginal; { register char *p, *dot; strcpy (name, orginal); for (p = name, dot = (char*)0; *p; p ++) { if (*p == '.') dot = p; else if (*p == '/') dot = (char*)0; } if (dot) p = dot; #ifdef BACKUPNAME_EXTENTION strcpy (p, BACKUPNAME_EXTENTION) ; #else strcpy (p, ".bak"); #endif } static make_standard_archive_name (name, orginal) char *name; char *orginal; { register char *p, *dot; strcpy (name, orginal); for (p = name, dot = (char*)0; *p; p ++) { if (*p == '.') dot = p; else if (*p == '/') dot = (char*)0; } if (dot) p = dot; #ifdef ARCHIVENAME_EXTENTION strcpy (p, ARCHIVENAME_EXTENTION); #else strcpy (p, ".lzh"); #endif } /*----------------------------------------------------------------------*/ /* */ /*----------------------------------------------------------------------*/ static boolean need_file (name) char *name; { int i; #ifdef atarist char *temp; #endif if (cmd_filec == 0) return TRUE; for (i = 0; i < cmd_filec; i ++) { #ifdef atarist temp = strstr (cmd_filev[i], name); if ((temp) && (strlen (cmd_filev[i]) != strlen (temp))) { strncpy (arcshpath, cmd_filev[i], (strlen (cmd_filev[i]) - strlen (temp)) - 1); chdir (arcshpath); strcpy (name, temp); return TRUE; } else if (!temp) return FALSE; else if (strcmp (cmd_filev[i], name) == 0) return TRUE; } #else if (strcmp (cmd_filev[i], name) == 0) return TRUE; } #endif return FALSE; } FILE *xfopen (name, mode) char *name, *mode; { FILE *fp; if ((fp = fopen (name, mode)) == NULL) error (name); return fp; } /*----------------------------------------------------------------------*/ /* Listing Stuff */ /*----------------------------------------------------------------------*/ /* need 14 or 22 (when long_format_listing is TRUE) column spaces */ print_size (packed_size, original_size) long packed_size, original_size; { #ifndef atarist if (long_format_listing) printf ("%7ld ", packed_size); #endif printf ("%7ld ", original_size); #ifdef atarist printf (" %7ld ", packed_size); #endif if (original_size == 0L) printf ("******"); else printf ("%3d.%1d%%", (int)((packed_size * 100L) / original_size), (int)((packed_size * 1000L) / original_size) % 10); } /* need 12 or 17 (when long_format_listing is TRUE) column spaces */ print_stamp (t) #ifdef atarist time_t t; #else long t; #endif { static boolean got_now = FALSE; static time_t now; static unsigned int threshold; #ifndef INTERNATIONAL_TIME static char t_month[12*3+1] = "JanFebMarAprMayJunJulAugSepOctNovDec"; /* fixed DecNov to NovDec bjsjr */ #endif struct tm *p; if (t == 0) { if (long_format_listing) printf (" "); /* 17 spaces */ else printf (" "); /* 12 spaces */ return; } if (!got_now) { now = time ((time_t*)0); p = localtime (&now); threshold = p->tm_year * 12 + p->tm_mon - 6; got_now = TRUE; } p = localtime (&t); if (long_format_listing) #ifndef atarist printf ("%.3s %2d %02d:%02d %04d", &t_month[p->tm_mon * 3], p->tm_mday, p->tm_hour, p->tm_min, p->tm_year + 1900); else if (p->tm_year * 12 + p->tm_mon > threshold) printf ("%.3s %2d %02d:%02d", &t_month[p->tm_mon * 3], p->tm_mday, p->tm_hour, p->tm_min); else printf ("%.3s %2d %04d", &t_month[p->tm_mon * 3], p->tm_mday, p->tm_year + 1900); #else printf ("%04d-%02d-%02d %02d:%02d:%02d", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec); else if (p->tm_year * 12 + p->tm_mon > threshold) printf ("%02d-%02d %02d:%02d:%02d", p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec); else printf ("%04d-%02d-%02d", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday); #endif } print_bar () { /* 17+1+(0 or 7+1)+7+1+6+1+(0 or 1+4)+(12 or 17)+1+20 */ /* 12345678901234567_ 1234567_123456 _123456789012 1234 */ #ifndef atarist if (long_format_listing) printf ("----------------- ------- ------- ------ ---- ----------------- -------------\n"); else printf ("----------------- ------- ------ ------------ --------------------\n"); #else if (long_format_listing) printf ("-------- ------- ------ ------------------- ----- ---- --------------------\n"); else printf ("-------- ------- ------ --------------------------------------\n"); #endif } /* view */ cmd_view () { FILE *fp; LzHeader hdr; register char *p; long a_packed_size = 0L; long a_original_size = 0L; int n_files = 0; struct stat v_stat; if ((fp = fopen (archive_name, R_MODE)) == NULL) if (!expand_archive_name (expanded_archive_name, archive_name)) error (archive_name); else { errno = 0; fp = xfopen (expanded_archive_name, R_MODE); archive_name = expanded_archive_name; } if (archive_is_msdos_sfx1 (archive_name)) { skip_msdos_sfx1_code (fp); } #ifndef atarist if (!quiet) { /* 12345678901234567_ 1234567_123456 _ 123456789012 1234 */ printf (" PERMSSN UID GID %s SIZE RATIO%s %s STAMP %s NAME\n", long_format_listing ? " PACKED " : "", /* 8,0 */ long_format_listing ? " CRC" : "", /* 5,0 */ long_format_listing ? " " : "", /* 2,0 */ long_format_listing ? " " : ""); /* 3,0 */ print_bar (); } while (get_header (fp, &hdr)) { if (need_file (hdr.name)) { if (hdr.extend_type == EXTEND_UNIX) { printf ("%c%c%c%c%c%c%c%c%c%4d/%-4d", ((hdr.unix_mode & UNIX_OWNER_READ_PERM) ? 'r' : '-'), ((hdr.unix_mode & UNIX_OWNER_WRITE_PERM) ? 'w' : '-'), ((hdr.unix_mode & UNIX_OWNER_EXEC_PERM) ? 'x' : '-'), ((hdr.unix_mode & UNIX_GROUP_READ_PERM) ? 'r' : '-'), ((hdr.unix_mode & UNIX_GROUP_WRITE_PERM) ? 'w' : '-'), ((hdr.unix_mode & UNIX_GROUP_EXEC_PERM) ? 'x' : '-'), ((hdr.unix_mode & UNIX_OTHER_READ_PERM) ? 'r' : '-'), ((hdr.unix_mode & UNIX_OTHER_WRITE_PERM) ? 'w' : '-'), ((hdr.unix_mode & UNIX_OTHER_EXEC_PERM) ? 'x' : '-'), hdr.unix_uid, hdr.unix_gid); } else { switch (hdr.extend_type) { /* max 18 characters */ case EXTEND_GENERIC: p = "[generic]"; break; case EXTEND_CPM: p = "[CP/M]"; break; /* OS-9 and FLEX's CPU is MC-6809. I like it. :-) */ case EXTEND_FLEX: p = "[FLEX]"; break; case EXTEND_OS9: p = "[OS-9]"; break; /* I guessed from this ID. Is this right? */ case EXTEND_OS68K: p = "[OS-9/68K]"; break; case EXTEND_MSDOS: p = "[MS-DOS]"; break; /* I have Macintosh. :-) */ case EXTEND_MACOS: p = "[Mac OS]"; break; case EXTEND_OS2: p = "[OS/2]"; break; case EXTEND_HUMAN: p = "[Human68K]"; break; case EXTEND_OS386: p = "[OS-386]"; break; #ifdef EXTEND_TOWNSOS /* This ID isn't fixed */ case EXTEND_TOWNSOS: p = "[TownsOS]"; break; #endif /* Ouch! Please customize it's ID. */ default: p = "[unknown]"; break; } printf ("%-18.18s", p); } print_size (hdr.packed_size, hdr.original_size); if (long_format_listing) if (hdr.has_crc) printf (" %04x", hdr.crc); else printf (" ****"); printf (" "); print_stamp (hdr.unix_last_modified_stamp); printf (" %s\n", hdr.name); n_files ++; a_packed_size += hdr.packed_size; a_original_size += hdr.original_size; } fseek (fp, hdr.packed_size, SEEK_CUR); } #else if (!quiet) { /* 12345678901234567_ 1234567_123456 _ 123456789012 1234 */ printf("Listing of archive : '%s'\n\n", archive_name); printf ("Original Packed Ratio %s %s%s Name\n", long_format_listing ? " Stamp" : "", /* 8,0 */ long_format_listing ? " Methd" : "", /* 5,0 */ long_format_listing ? " CRC" : "", /* 2,0 */ long_format_listing ? " " : ""); /* 3,0 */ print_bar (); } while (get_header (fp, &hdr)) { if (need_file (hdr.name)) { print_size (hdr.packed_size, hdr.original_size); if (long_format_listing) { printf (" "); print_stamp (hdr.unix_last_modified_stamp); printf (" %5s", hdr.method); if (hdr.has_crc) printf (" %04x", hdr.crc); else printf (" ****"); } printf (" %s\n", hdr.name); n_files ++; a_packed_size += hdr.packed_size; a_original_size += hdr.original_size; } fseek (fp, hdr.packed_size, SEEK_CUR); } #endif /* atarist */ fclose (fp); if (!quiet) { print_bar (); #ifndef atarist printf (" Total %4d file%c ", n_files, (n_files == 1) ? ' ' : 's'); print_size (a_packed_size, a_original_size); printf (" "); if (long_format_listing) printf (" "); if (stat (archive_name, &v_stat) < 0) print_stamp ((time_t)0); else print_stamp (v_stat.st_mtime); printf ("\n"); } #else print_size (a_packed_size, a_original_size); printf (" "); if (stat (archive_name, &v_stat) < 0) print_stamp ((time_t)0); else print_stamp (v_stat.st_mtime); printf (" %4d file%c Total\n", n_files, (n_files == 1) ? ' ' : 's'); } #endif return; } static boolean make_parent_path (name) char *name; { char path[FILENAME_LENGTH]; struct stat v_stat; register char *p; #ifdef TSTFLG if (tstflg) return TRUE; #endif /* make parent directory name into PATH for recursive call */ strcpy (path, name); for (p = path + strlen (path); p > path; p --) if (p[-1] == '/') { p[-1] = '\0'; break; } if (p == path) return FALSE; /* no more parent. */ if (stat (path, &v_stat) >= 0) { if ((v_stat.st_mode & S_IFMT) != S_IFDIR) return FALSE; /* already exist. but it isn't directory. */ return TRUE; /* already exist its directory. */ } errno = 0; if (!quiet) message ("Making Directory", path); #ifdef atarist if (mkdir (path) >= 0) /* try */ #else if (mkdir (path, 0777) >= 0) /* try */ #endif return TRUE; /* successful done. */ errno = 0; if (!make_parent_path (path)) return FALSE; #ifdef atarist if (mkdir (path) < 0) /* try again */ #else if (mkdir (path, 0777) < 0) /* try again */ #endif return FALSE; return TRUE; } static FILE *open_with_make_path (name) char *name; { FILE *fp; struct stat v_stat; char buffer[1024]; if (stat (name, &v_stat) >= 0) { if ((v_stat.st_mode & S_IFMT) != S_IFREG) return NULL; if (!force) { for (;;) { fprintf (stderr, "%s OverWrite ?(Yes/No/All) ", name); fflush (stderr); gets (buffer); if (buffer[0] == 'N' || buffer[0] == 'n') return NULL; if (buffer[0] == 'Y' || buffer[0] == 'y') break; if (buffer[0] == 'A' || buffer[0] == 'a') { force = TRUE; break; } } } } fp = fopen (name, W_MODE); if (!fp) { errno = 0; if (!make_parent_path (name)) return NULL; fp = fopen (name, W_MODE); if (!fp) message ("Error :", name); } return fp; } extern int decode_lzhuf (), decode_larc (); extern int decode_stored_crc (), decode_stored_nocrc (); static extract_one (fp, hdr) FILE *fp; LzHeader *hdr; { FILE *ofp; /* output file */ char name[1024]; time_t utimebuf[2]; int crc; int (*decode_proc)(); /* (ifp,ofp,original_size,name) */ int save_quiet; #ifdef TSTFLG char *temp; #endif strcpy (name, hdr->name); #ifdef atarist if (!fullpath && !tstflg) if (temp = strrchr (name, '/')) strcpy (name, ++temp); #endif if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR) { if (bcmp (hdr->method, LZHUFF1_METHOD, METHOD_TYPE_STRAGE) == 0) decode_proc = decode_lzhuf; else if ((bcmp (hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STRAGE) == 0) || (bcmp (hdr->method, LARC4_METHOD, METHOD_TYPE_STRAGE) == 0)) decode_proc = (hdr->has_crc) ? decode_stored_crc : decode_stored_nocrc; else if (bcmp (hdr->method, LARC5_METHOD, METHOD_TYPE_STRAGE) == 0) decode_proc = decode_larc; else message ("Error :", "Sorry, Cannot Extract this method."); reading_filename = archive_name; writting_filename = name; if (output_to_stdout) { if (!quiet) printf ("::::::::\n%s\n::::::::\n", name); save_quiet = quiet; quiet = TRUE; crc = (*decode_proc) (fp, stdout, hdr->original_size, name); quiet = save_quiet; } else { #ifdef TSTFLG if (!tstflg) { /* If we are really EXtracting and not merely Testing */ #endif if ((ofp = open_with_make_path (name)) == NULL) return; else { crc = (*decode_proc) (fp, ofp, hdr->original_size, name); fclose (ofp); } #ifdef TSTFLG } else /* If we are just Testing */ #ifdef atarist crc = (*decode_proc) (fp, NULL, hdr->original_size, name); #else if ((ofp = fopen("/dev/null", "w")) == NULL) return; else { crc = (*decode_proc) (fp, ofp, hdr->original_size, name); fclose (ofp); } #endif /*atarist */ #endif /* TSTFLG */ } if (hdr->has_crc && (crc != hdr->crc)) error ("CRC Error"); } else { #ifdef atarist if (fullpath || tstflg) #endif /* NAME has trailing SLASH '/', (^_^) */ if (!output_to_stdout && !make_parent_path (name)) error (name); } #ifndef TSTFLG if (!output_to_stdout) #else if (!output_to_stdout && !tstflg) #endif { utimebuf[0] = utimebuf[1] = hdr->unix_last_modified_stamp; utime (name, utimebuf); #ifdef NOT_COMPATIBLE_MODE Please need your modification in this space. #else chmod (name, hdr->unix_mode); #endif #ifndef atarist chown (name, hdr->unix_uid, hdr->unix_gid); #endif errno = 0; } } /* extract */ cmd_extract () { LzHeader hdr; long pos; FILE *fp; if ((fp = fopen (archive_name, R_MODE)) == NULL) if (!expand_archive_name (expanded_archive_name, archive_name)) error (archive_name); else { errno = 0; fp = xfopen (expanded_archive_name, R_MODE); archive_name = expanded_archive_name; } #ifdef TSTFLG printf ("%s '%s'\n", ((!tstflg) ? "Extract from" : "Testing"), archive_name); #endif if (archive_is_msdos_sfx1 (archive_name)) { skip_msdos_sfx1_code (fp); } #ifdef atarist if (wildcard) { chdir (arcshpath); cmd_filec = 0; } #endif while (get_header (fp, &hdr)) { if (need_file (hdr.name)) { pos = ftell (fp); extract_one (fp, &hdr); fseek (fp, pos + hdr.packed_size, SEEK_SET); } else { fseek (fp, hdr.packed_size, SEEK_CUR); } } fclose (fp); return; } /*----------------------------------------------------------------------*/ /* */ /*----------------------------------------------------------------------*/ extern int encode_lzhuf (); extern int encode_storerd_crc (); static append_one (fp, nafp, hdr) FILE *fp, *nafp; LzHeader *hdr; { long header_pos, next_pos, org_pos, data_pos; long v_original_size, v_packed_size; reading_filename = hdr->name; writting_filename = temporary_name; org_pos = ftell (fp); header_pos = ftell (nafp); write_header (nafp, hdr); /* DUMMY */ if (hdr->original_size == 0) return; /* previous write_header is not DUMMY. (^_^) */ data_pos = ftell (nafp); hdr->crc = encode_lzhuf (fp, nafp, hdr->original_size, &v_original_size, &v_packed_size, hdr->name); if (v_packed_size < v_original_size) { next_pos = ftell (nafp); } else { /* retry by stored method */ fseek (fp, org_pos, SEEK_SET); fseek (nafp, data_pos, SEEK_SET); hdr->crc = encode_stored_crc (fp, nafp, hdr->original_size, &v_original_size, &v_packed_size); fflush (nafp); next_pos = ftell (nafp); #ifdef atarist st_truncate (nafp, next_pos); #else ftruncate (fileno (nafp), next_pos); #endif bcopy (LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE); } hdr->original_size = v_original_size; hdr->packed_size = v_packed_size; fseek (nafp, header_pos, SEEK_SET); write_header (nafp, hdr); fseek (nafp, next_pos, SEEK_SET); } write_tail (nafp) FILE *nafp; { putc (0x00, nafp); } static copy_old_one (oafp, nafp, hdr) FILE *oafp, *nafp; LzHeader *hdr; { if (noexec) { fseek (oafp, (long)(hdr->header_size + 2) + hdr->packed_size, SEEK_CUR); } else { reading_filename = archive_name; writting_filename = temporary_name; copy_file (oafp, nafp, (long)(hdr->header_size + 2) + hdr->packed_size); } } FILE *append_it (name, oafp, nafp) char *name; FILE *oafp, *nafp; { LzHeader ahdr, hdr; FILE *fp; long old_header; int cmp; int filec; char **filev; int i; struct stat v_stat; boolean directory; #ifdef atarist char *temp; #endif if (!delete_from_archive) { if (stat (name, &v_stat) < 0) { message ("Error : ", name); return oafp; } } else bzero(&v_stat, sizeof(v_stat)); directory = ((v_stat.st_mode & S_IFMT) == S_IFDIR); #ifndef atarist init_header (name, &v_stat, &hdr); #else if (!fullpath) { if (!directory) if (temp = strrchr (name,'/')) init_header (++temp, &v_stat, &hdr); else init_header (name, &v_stat, &hdr); else goto nodir; } else init_header (name, &v_stat, &hdr); #endif if (!delete_from_archive && !directory) fp = xfopen (name, R_MODE); else fp = NULL; while (oafp) { old_header = ftell (oafp); if (!get_header (oafp, &ahdr)) { fclose (oafp); oafp = NULL; break; } else { cmp = STRING_COMPARE (ahdr.name, hdr.name); if (cmp < 0) { /* SKIP */ fseek (oafp, old_header, SEEK_SET); copy_old_one (oafp, nafp, &ahdr); } else if (cmp == 0) { /* REPLACE */ fseek (oafp, ahdr.packed_size, SEEK_CUR); break; } else /* cmp > 0, INSERT */ { fseek (oafp, old_header, SEEK_SET); break; } } } if (delete_from_archive) { if (noexec) fprintf (stderr, "DELETE %s\n", name); else printf ("%s - Deleted\n", name); } else { if (!oafp || /* not in archive */ (cmp > 0) || /* // */ !update_if_newer || /* always update */ (ahdr.unix_last_modified_stamp < /* newer than archive's */ hdr.unix_last_modified_stamp)) { if(fp) { if (noexec) fprintf (stderr, "APPEND %s\n", name); else if (!update_freshen || (cmp == 0)) append_one (fp, nafp, &hdr); } } else { /* archive has old one */ fseek (oafp, old_header, SEEK_SET); copy_old_one (oafp, nafp, &ahdr); } #ifdef atarist nodir: #endif if (!directory) { if (!noexec) fclose (fp); } else { /* recurcive call */ if (find_files (name, &filec, &filev)) { for (i = 0; i < filec; i ++) oafp = append_it (filev[i], oafp, nafp); free_files (filec, filev); } return oafp; } } return oafp; } remove_it (name) char *name; { struct stat v_stat; int i; char **filev; int filec; if (stat (name, &v_stat) < 0) { fprintf (stderr, "cannot access \"%s\".\n", name); return; } if ((v_stat.st_mode & S_IFMT) == S_IFDIR) { if (!find_files (name, &filec, &filev)) { fprintf (stderr, "cannot open directory \"%s\".\n", name); return; } for (i = 0; i < filec; i ++) remove_it (filev[i]); free_files (filec, filev); if (noexec) printf ("REMOVE DIRECTORY \"%s\"\n", name); else if (rmdir (name) < 0) fprintf (stderr, "cannot remove directory \"%s\".\n", name); else if (!quiet) printf ("Erased \"%s\".\n", name); } else { if (noexec) printf ("ERASE \"%s\".\n", name); else if (unlink (name) < 0) fprintf (stderr, "cannot remove \"%s\".\n", name); else if (!quiet) printf ("Erased \"%s\".\n", name); } } cmd_append () { LzHeader ahdr; FILE *oafp, *nafp; char backup_archive_name [ FILENAME_LENGTH ]; char new_archive_name_buffer [ FILENAME_LENGTH ]; char *new_archive_name; int i; long old_header; struct stat v_stat; boolean old_archive_exist; if (cmd_filec == 0) return; make_tmp_name (archive_name, temporary_name); if ((oafp = fopen (archive_name, R_MODE)) == NULL) if (expand_archive_name (expanded_archive_name, archive_name)) { errno = 0; oafp = fopen (expanded_archive_name, R_MODE); archive_name = expanded_archive_name; } old_archive_exist = (oafp) ? TRUE : FALSE; if (new_archive && oafp) { fclose (oafp); oafp = NULL; } if (oafp && archive_is_msdos_sfx1 (archive_name)) { skip_msdos_sfx1_code (oafp); make_standard_archive_name (new_archive_name_buffer, archive_name); new_archive_name = new_archive_name_buffer; } else { new_archive_name = archive_name; } errno = 0; if (!noexec) { nafp = xfopen (temporary_name, W_MODE); remove_temporary_at_error = TRUE; } for (i = 0; i < cmd_filec; i ++) oafp = append_it (cmd_filev[i], oafp, nafp); if (oafp) { old_header = ftell (oafp); while (get_header (oafp, &ahdr)) { fseek (oafp, old_header, SEEK_SET); copy_old_one (oafp, nafp, &ahdr); old_header = ftell (oafp); } fclose (oafp); } if (!noexec) { write_tail (nafp); fclose (nafp); } if (backup) { make_backup_name (backup_archive_name, archive_name); if (!noexec && old_archive_exist) if (rename (archive_name, backup_archive_name) < 0) error (archive_name); } if (!quiet && new_archive_name == new_archive_name_buffer) { /* warning at old archive is SFX */ printf ("New Archive File is \"%s\"\n", new_archive_name); } if (!noexec && rename (temporary_name, new_archive_name) < 0) { if (stat (temporary_name, &v_stat) < 0) error (temporary_name); oafp = xfopen (temporary_name, R_MODE); nafp = xfopen (archive_name, W_MODE); reading_filename = temporary_name; writting_filename = archive_name; copy_file (oafp, nafp, (long)v_stat.st_size); fclose (nafp); fclose (oafp); unlink (temporary_name); } remove_temporary_at_error = FALSE; if (delete_after_append) { if (!quiet && !noexec) printf ("Erasing...\n"); for (i = 0; i < cmd_filec; i ++) remove_it (cmd_filev[i]); } return; } #ifdef atarist #include static int st_truncate (fp, pos) FILE *fp; long pos; { int ifp; char filename[FILENAME_MAX]; if(fflush(fp)) return -1; if(fseek(fp, pos, SEEK_SET)) return -1; ifp = __OPEN_INDEX(fp->_file); strcpy(filename, __open_stat[ifp].filename); close(fp->_file); if((fp->_file = open(filename, O_RDWR)) < 0) return -1; fseek(fp, 0L, SEEK_END); return 0; } void stexit (status) int status; { int i; if (hold) { fprintf (stderr,"\nHit any key to exit ......"); fflush (stderr); Bconin (2); } chdir (dirbuf); for (i = 0; i < targc; i++) free (targv[i]); free (targv); exit (status); } #endif