/* * $Id: arj.c,v 1.13 2005/06/21 19:53:13 andrew_belov Exp $ * --------------------------------------------------------------------------- * This is the main file of the ARJ project. The routines in this file have * a wide variety of purposes, however, all archive-related procedures are NOT * put into ARJ.C. * */ #include #include #include "arj.h" DEBUGHDR(__FILE__) /* Debug information block */ /* Expiry date/time */ #define EXPIRABLE 0 /* 1 -> allow expiry as such */ #define EXPIRY_YR 1980 #define EXPIRY_MO 1 #define EXPIRY_DY 1 #define EXPIRY_H 0 #define EXPIRY_M 0 #define EXPIRY_S 0 /* Local variables */ static char fixed_arjtemp[]="ARJTEMP.$$$"; static char arjtemp_wildcard[]="ARJTEMP.$??"; static char wildcard_pattern[]="?*[]^"; static int tmp_archive_exists; static int tmp_archive_removed; static unsigned long ticks; static unsigned int limit; static char brief_help[]="arjs.txt"; static char full_help[]="arjl.txt"; static char sort_filename[]="arjsort.$$$"; static char *arj_env_str=NULL; static char single_spc[]=" "; /* Forward references */ static void finish_archive_name(char *name); static void final_cleanup(void); /* Checks if all the files given to ARJ were successfully processed. */ static void file_arg_cleanup(struct flist_root *flist) { int cur_arg; FILE_COUNT cur_file; char *tmp_name; for(cur_arg=0; cur_argfiles>0) { tmp_name=malloc_msg(FILENAME_MAX); for(cur_file=0; cur_filefiles; cur_file++) { flist_retrieve(tmp_name, NULL, flist, cur_file); msg_cprintf(H_ERR, M_CANT_FIND, tmp_name); if(listfile_err_opt) { if(errorlevel==ARJ_ERL_SUCCESS) errorlevel=ARJ_ERL_WARNING; errors++; } } free(tmp_name); } } /* Depending on the command given, issues some special setup */ static void cmd_setup(int *cmd, int *is_add_cmd) { int cnv_cmd; int add_cmd; char *tmp_swptr; char *vptr; unsigned long vol_size; cnv_cmd=*cmd; switch(*cmd) { case ARJ_CMD_MOVE: cnv_cmd=ARJ_CMD_ADD; delete_processed=DP_ADD; case ARJ_CMD_ADD: if(freshen_criteria) cnv_cmd=ARJ_CMD_FRESHEN; if(update_criteria) cnv_cmd=ARJ_CMD_UPDATE; break; case ARJ_CMD_REM_BAK: current_chapter=RESERVED_CHAPTER; break; case ARJ_CMD_FRESHEN: if(freshen_criteria==FC_NONE) freshen_criteria=FC_EXISTING; break; case ARJ_CMD_UPDATE: if(update_criteria==FC_NONE) update_criteria=FC_EXISTING; break; case ARJ_CMD_SECURE: sign_with_arjsec=1; break; case ARJ_CMD_ADDC: cnv_cmd=ARJ_CMD_UPDATE; update_criteria=UC_NEW_OR_DIFFERENT; chapter_mode=CHAP_USE; break; case ARJ_CMD_CNVC: cnv_cmd=ARJ_CMD_COPY; chapter_mode=CHAP_USE; break; case ARJ_CMD_DELC: cnv_cmd=ARJ_CMD_DELETE; chapter_mode=CHAP_USE; break; case ARJ_CMD_EXEC: cnv_cmd=ARJ_CMD_EXTR_NP; execute_cmd=1; if(extraction_filename[0]=='\0') { extraction_filename=fixed_arjtemp; extract_to_file=1; } break; case ARJ_CMD_SAMPLE: cnv_cmd=ARJ_CMD_PRINT; print_with_more=1; break; case ARJ_CMD_PRINT: if(!prompt_for_more) break; print_with_more=1; break; case ARJ_CMD_V_LIST: cnv_cmd=ARJ_CMD_LIST; std_list_cmd=1; break; case ARJ_CMD_EXTRACT: cnv_cmd=ARJ_CMD_EXTR_NP; subdir_extraction=1; break; } if(cnv_cmd==ARJ_CMD_EXTR_NP&&delete_processed&&!execute_cmd) { cnv_cmd=ARJ_CMD_DELETE; delete_processed=DP_EXTRACT; } add_cmd=msg_strchr(M_ADD_COMMANDS, (char)cnv_cmd)!=NULL; if(file_args<0) { if(!append_curtime) error(M_NO_FILE_GIVEN); else { archive_name[0]='\0'; file_args++; finish_archive_name(archive_name); } } if(cnv_cmd==ARJ_CMD_DELETE&&file_args==0&&delete_processed!=DP_EXTRACT) error(M_NO_DELETE_ARG); if(cnv_cmd!=ARJ_CMD_COMMENT&&msg_strchr(M_MODIFY_COMMANDS, (char)cnv_cmd)!=NULL&¤t_chapter!=0&¤t_chapter<=CHAPTERS_MAX) error(M_BAD_SYNTAX); if(add_cmd&&multivolume_option) { if(volume_limit0) error(M_BAD_SYNTAX); if(win32_platform&&lfn_mode==LFN_DUAL) error(M_BAD_SYNTAX); if(chapter_mode==CHAP_REMOVE&&cnv_cmd!=ARJ_CMD_COPY) error(M_BAD_SYNTAX); if(test_archive_crc>=TC_CRC_AND_CONTENTS&&exclude_paths) error(M_JT_UNUSABLE, "-e/-e1"); if(test_archive_crc>=TC_CRC_AND_CONTENTS&&fix_longnames) error(M_JT_UNUSABLE, "-2l"); if(arcmail_sw&&serialize_exts) error(M_JO_UNUSABLE, "-2a"); #if TARGET==DOS if(priority.class!=0) error(M_OS_DEPENDENT, "-2p"); #endif if(ea_supported&&restart_at_filename) error(M_CANT_RESTART_W_EAS); if(assign_work_directory&&work_directory[0]=='\0') error(M_MISSING_FILENAME_ARG, "-w"); if(extract_to_file&&extraction_filename[0]=='\0') error(M_MISSING_FILENAME_ARG, "-jw"); if(create_list_file&&list_file[0]=='\0') error(M_MISSING_FILENAME_ARG, "-l"); if(create_index&&index_name[0]=='\0') error(M_MISSING_FILENAME_ARG, "-ji"); if(restart_at_filename&&filename_to_restart[0]=='\0'&&index_name[0]=='\0') error(M_MISSING_FILENAME_ARG, "-jn"); if((cnv_cmd==ARJ_CMD_EXTR_NP||cnv_cmd==ARJ_CMD_EXTRACT)&&use_comment&&archive_cmt_name[0]=='\0') error(M_MISSING_FILENAME_ARG, "-z"); if(chk_arj_version) { tmp_swptr=swptr_hv; if(tmp_swptr[0]=='\0'||tmp_swptr[0]=='R'||tmp_swptr[0]=='r') { if(!is_registered) exit(ARJ_ERL_WARNING); else if(tmp_swptr[0]!='\0') tmp_swptr++; } if(tmp_swptr[0]!='\0') { msg_strcpy(strcpy_buf, M_VERSION); vptr=strcpy_buf; if(vptr[0]offset&&archive_ext_list[offset]!='\0'&&archive_ext_list[offset]!='.'); while(c_offset=params_max) error(M_ARGTABLE_OVERFLOW); f_arg_array[file_args++]=token; } } else f_arg_array[file_args++]=token; } } } return(cmd); } /* Ctrl+C handler */ static void ctrlc_handler(SIGHDLPARAMS) { ctrlc_processing=1; /* Check if we are able to honor the request. If we aren't, raise the signal again and make a speedy getaway. */ if(!ctrlc_not_busy) raise(SIGINT); else { error_occured=1; /* ARJ needs termination */ signal(SIGINT, NULL); /* Restore default Ctrl+C handler */ msg_cprintf(H_SIG, M_BREAK_SIGNALED); exit(ARJ_ERL_BREAK); } } /* Termination handler */ #ifndef NO_TERM_HDL static void term_handler(SIGHDLPARAMS) { error_occured=1; /* ARJ needs termination */ signal(SIGTERM, NULL); msg_cprintf(H_SIG, M_SIGTERM); exit(ARJ_ERL_BREAK); } #endif /* Executes an OS command with checking for break */ void exec_cmd(char *cmd) { flush_kbd(); ctrlc_not_busy=0; /* Say that we are busy */ system_cmd(cmd); ctrlc_not_busy=1; if(ctrlc_processing) /* If processing was delayed... */ #if COMPILER==BCC ctrlc_handler(); #else ctrlc_handler(0); #endif } /* atexit routine - closes all files and frees memory */ static void final_cleanup(void) { short pad; static int double_shutdown=0; file_close(idxstream); file_close(aistream); file_close(atstream); idxstream=NULL; aistream=NULL; atstream=NULL; if(aostream!=NULL) { if(last_hdr_offset>0L) { fseek(aostream, last_hdr_offset+2L, SEEK_SET); pad=0; fwrite(&pad, 1, 2, aostream); } file_close(aostream); aostream=NULL; } #if TARGET!=UNIX||defined(HAVE_FCLOSEALL) fcloseall(); #endif if(tmp_archive_name!=NULL) { if(tmp_archive_removed) { rename_with_check(tmp_archive_name, archive_name); tmp_archive_name[0]='\0'; } if(!keep_tmp_archive&&tmp_archive_name[0]!='\0'&&(!tmp_archive_used||!tmp_archive_exists)) file_unlink(tmp_archive_name); if(tmp_archive_used==1) file_unlink(archive_name); free(tmp_archive_name); tmp_archive_name=NULL; } if(tmp_tmp_filename!=NULL) { if(!keep_tmp_file&&tmp_tmp_filename[0]!='\0') file_unlink(tmp_tmp_filename); free(tmp_tmp_filename); tmp_tmp_filename=NULL; } if(debug_enabled&&strchr(debug_opt, 'v')!=NULL) { msg_cprintf(0, M_EXITING_PROGRAM); if(double_shutdown) msg_cprintf(0, M_HERE_TWICE); if(verify_heap()) msg_cprintf(H_ERR, M_BAD_HEAP); } if(double_shutdown) return; double_shutdown=1; flist_cleanup(&flist_main); flist_cleanup(&flist_order); flist_cleanup(&flist_exclusion); flist_cleanup(&flist_archive); #if defined(HAVE_EAS) flist_cleanup(&flist_ea); flist_cleanup(&flist_xea); #endif #if TARGET==UNIX if(l_entries.list!=NULL) farfree(l_entries.list); #endif if(quiet_mode) freopen(dev_con, m_w, stdout); if(ferror(stdout)) msg_fprintf(stderr, M_DISK_FULL); if(debug_enabled&&strchr(debug_opt, 't')!=NULL) { ticks=get_ticks()-ticks; msg_cprintf(H_HL|H_NFMT, M_FINAL_TIMING, ticks); } if(!store_by_suffix) free(archive_suffixes); cfa_shutdown(); if(arj_env_str!=NULL) free_env_str(arj_env_str); if(eh!=NULL) { eh_release(eh); eh=NULL; } if(ntext!=NULL) /* ASR fix for 2.76.05 */ free(ntext); free_fmsg(arj_env_name); free(header); free(archive_name); free(misc_buf); free(strcpy_buf); free(exe_name); farfree(order); free(f_arg_array); #ifdef COLOR_OUTPUT scrn_reset(); #endif } /* Waits and then prints an error message */ static void wait_error(FMSG *errmsg) { arj_delay(5); error(errmsg); } /* Checks if the ARJ beta has expired */ static void arj_exec_validation() { #if !defined(COMMERCIAL)&&EXPIRABLE==1 struct timestamp cur_time, expiry_time; #endif limit=0; #if !defined(COMMERCIAL)&&EXPIRABLE==1 /* See top of this module for definitions */ cur_time_stamp(&cur_time); make_timestamp(&expiry_time, EXPIRY_YR, EXPIRY_MO, EXPIRY_DY, EXPIRY_H, EXPIRY_M, EXPIRY_S); if(ts_cmp(&cur_time, &expiry_time)>=0) limit=100; #endif /* The EXE validation must occur here. Skipped for speed-up */ } /* This is not an optimization -- ASR fix for High C -- 05/04/2001 */ #if COMPILER==HIGHC&&!defined(DEBUG) #pragma on(Optimize_for_space) #endif /* Main routine */ int main(int argc, char *argv[]) { int cmd; int is_add_cmd; unsigned long start_time, proc_time; FILE_COUNT i; int j; int cur_arg; FILE *stream; char *tmp_ptr, *tptr, *endptr; int got_str=0; char *name; int flist_type; FILE_COUNT numfiles; int expand_wildcards; int entry; int sort_f; FILE_COUNT count; FILE_COUNT cur_file; int ansi_cpf; FILE *tmp_stdout; FILE_COUNT default_capacity=EXT_FILELIST_CAPACITY; #if TARGET==WIN32 win32_platform=1; #else win32_platform=0; #endif #ifdef COLOR_OUTPUT no_colors=redirected=!is_tty(stdout); #endif errorlevel=0; ignore_errors=0; ansi_cpf=0; in_key=1; params_max=argc+PARAMS_MAX; order=NULL; f_arg_array=NULL; #ifdef USE_TZSET tzset(); #endif ticks=get_ticks(); detect_lfns(); detect_eas(); ticks=get_ticks(); cmd=preprocess_cmdline(argc, argv); set_file_apis(use_ansi_cp); /* ARJ32 only (from v 2.72) */ #ifndef NO_FATAL_ERROR_HDL install_smart_handler(); #endif /* Perform STDOUT setup -- ASR fix for IBM C Set++, VisualAge C++ and GLIBC builds */ #ifdef STDOUT_SETBUF_FIX setbuf(stdout, NULL); setbuf(stderr, NULL); #endif new_stderr=NULL; if(quiet_mode) new_stderr=fopen(dev_null, m_w); if(quiet_mode==ARJ_QUIET||quiet_mode==ARJ_SILENT) new_stdout=new_stderr; /* Test for low-memory DOS situtations */ #if TARGET==DOS free(malloc_msg(10000)); farfree(farmalloc_msg(9000)); #endif /* Locate the executables. On UNIX systems, before assuming /usr/bin/arj, we try to guess if ARGV contains a somewhat qualified filename. This is a special hack for PACKAGER. */ exe_name=(char *)malloc_msg(CCHMAXPATH); #ifndef SKIP_GET_EXE_NAME get_exe_name(exe_name); #else get_exe_name(exe_name, argv[0]); #endif case_path(arj_env_name); init_crc(); start_time=get_ticks(); ctrlc_processing=0; tmp_archive_removed=0; tmp_archive_exists=0; is_registered=1; #ifdef COMMERCIAL is_commercial=1; #else is_commercial=0; #endif archive_suffixes=NULL; header=(char *)malloc_msg(HEADERSIZE_MAX); archive_name=(char *)malloc_msg(FILENAME_MAX); archive_name[0]='\0'; /* ASR fix for ARJ -i in ARJ 2.73 */ misc_buf=(char *)malloc_msg(FILENAME_MAX+INPUT_LENGTH); tmp_tmp_filename=(char *)malloc_msg(FILENAME_MAX); strcpy_buf=(char *)malloc_msg(200); order=(FILE_COUNT FAR *)farmalloc_msg(params_max*sizeof(FILE_COUNT)); f_arg_array=(char **)malloc_msg(params_max*sizeof(char *)); limit=20; parse_reg_key(); arj_exec_validation(); set_file_apis(use_ansi_cp); init(); flist_init(&flist_main, 0, FL_STANDARD); flist_init(&flist_exclusion, 0, FL_STANDARD); flist_init(&flist_order, 0, FL_STANDARD); flist_init(&flist_archive, 0, FL_STANDARD); #if defined(HAVE_EAS) flist_init(&flist_ea, 0, FL_STANDARD); flist_init(&flist_xea, 0, FL_STANDARD); #endif if(signal(SIGINT, ctrlc_handler)==SIG_ERR) error(M_SIGNAL_FAILED); #ifndef NO_TERM_HDL if(signal(SIGTERM, term_handler)==SIG_ERR) error(M_SIGNAL_FAILED); #endif #ifdef HAVE_BREAK_HANDLER if(signal(SIGBREAK, term_handler)==SIG_ERR) error(M_SIGNAL_FAILED); #endif atexit(final_cleanup); for(i=0; i<10; i++) is_registered=reg_validation(regdata+REG_KEY1_SHIFT, regdata+REG_KEY2_SHIFT, regdata+REG_NAME_SHIFT, regdata+REG_HDR_SHIFT); check_fmsg(CHKMSG_SKIP); if((tmp_stdout=new_stdout)==new_stderr&&!is_registered) new_stdout=stderr; msg_strcpy(strcpy_buf, M_VERSION); msg_cprintf(0, M_ARJ_BANNER, M_ARJ_BINDING, strcpy_buf, build_date); if(!is_registered&&!msg_strcmp((FMSG *)(regdata+REG_KEY2_SHIFT), M_REG_TYPE)) msg_cprintf(0, M_REGISTERED_TO, regdata+REG_NAME_SHIFT); else msg_cprintf(0, (FMSG *)lf); new_stdout=tmp_stdout; proc_time=get_ticks(); flist_init(&flist_exclusion, FCLIM_EXCLUSION, FL_STANDARD); #if defined(HAVE_EAS) flist_init(&flist_ea, FCLIM_EA, FL_STANDARD); flist_init(&flist_xea, FCLIM_EA, FL_STANDARD); #endif switch_char='\0'; if(!disable_arj_sw) { if((arj_env_str=malloc_env_str(arj_env_name))!=NULL) parse_arj_sw(cmd, arj_env_str, header); else { #ifndef SKIP_GET_EXE_NAME split_name(exe_name, archive_name, NULL); msg_strcat(archive_name, M_ARJ_CFG); if(file_exists(archive_name)) parse_arj_sw(cmd, archive_name, header); #else msg_strcpy(misc_buf, M_ARJ_CFG); sprintf(archive_name, "%s/.%s", getenv("HOME"), misc_buf); if(!file_exists(archive_name)) sprintf(archive_name, "/usr/local/etc/%s", misc_buf); if(file_exists(archive_name)) parse_arj_sw(cmd, archive_name, header); #endif archive_name[0]='\0'; /* ASR fix */ } } if(install_errhdl) ignore_errors=1; if(force_lfn) lfn_supported=LFN_SUPPORTED; if(use_ansi_cp==ANSICP_CONVERT) ansi_cpf=1; set_file_apis(use_ansi_cp); #ifndef NO_FATAL_ERROR_HDL if(win32_platform) install_smart_handler(); #endif if(lfn_mode==LFN_NONE||lfn_mode==LFN_IGNORE) lfn_supported=LFN_NOT_SUPPORTED; if(lfn_supported!=LFN_NOT_SUPPORTED&&lfn_mode==LFN_DUAL) lfn_supported=LFN_COMP; is_registered=!is_registered; if(!is_registered&®data[REG_NAME_SHIFT]!='\0') wait_error(M_CRC_ERROR); cmd=0; if(rsp_name[0]=='\0') { for(cur_arg=1; cur_arg0) { /* ASR fix: check for overrun -- 25/08/2001 */ while(*tptr=='\0'&&((endptr-tptr)>0)) tptr++; if((endptr-tptr)>0) { cmd=parse_cmdline(tptr, cmd); while(*tptr!='\0'&&((endptr-tptr)>0)) tptr++; } } } fclose(stream); if(!got_str) error(M_CANTREAD); } if(install_errhdl) ignore_errors=1; if(force_lfn) lfn_supported=LFN_SUPPORTED; set_file_apis(use_ansi_cp); #ifndef NO_FATAL_ERROR_HDL if(win32_platform) install_smart_handler(); #endif if(file_args>=0) { case_path(archive_name); finish_archive_name(archive_name); } for(j=0; j0) set_priority(&priority); #endif if(run_cmd_at_start&&start_cmd[0]!='\0') exec_cmd(start_cmd); if(!exclude_files) { flist_cleanup(&flist_exclusion); flist_init(&flist_exclusion, FCLIM_EXCLUSION, FL_STANDARD); } flist_add_files(&flist_exclusion, NULL, arjtemp_wildcard, 0, 0, 0, NULL); if(filter_same_or_newer||filter_older) convert_time_limits(); if(cmd==ARJ_CMD_WHERE||extm_mode) search_setup(); else if(execute_cmd) get_exec_cmd(); if(garble_enabled) { if(!strcmp(garble_password, "?")) { tptr=(char *)malloc_msg(INPUT_LENGTH+1); msg_cprintf(0, M_ENTER_PWD); read_line_noecho(tptr, INPUT_LENGTH); garble_password=malloc_str(tptr); if(is_add_cmd||cmd=='G') { msg_cprintf(0, M_VERIFY_PWD); read_line_noecho(tptr, INPUT_LENGTH); if(strcmp(tptr, garble_password)) error(M_PWD_MISMATCH); } free(tptr); } } if(garble_password[0]=='\0'&&(cmd==ARJ_CMD_GARBLE||garble_enabled)) error(M_NO_PWD_OPTION); limit=20; if(append_curtime) append_curtime_proc(); if(is_add_cmd&&file_exists(archive_name)) { tmp_archive_exists=1; if(tmp_archive_name==NULL) { tmp_archive_used=-1; tmp_archive_name=malloc_msg(FILENAME_MAX); tmp_archive_name[0]='\0'; tmp_archive_used=0; } split_name(archive_name, tmp_archive_name, NULL); strcat(tmp_archive_name, arjtemp_spec); find_tmp_filename(tmp_archive_name); if(!stricmp(archive_name, tmp_archive_name)) error(M_CANTRENAME, archive_name, tmp_archive_name); file_unlink(tmp_archive_name); tmp_archive_removed=1; rename_with_check(archive_name, tmp_archive_name); } set_file_apis(1); arj_exec_validation(); set_file_apis(use_ansi_cp); #if TARGET!=UNIX if(cmd!=ARJ_CMD_ORDER) flist_type=find_dupl_drivespecs(f_arg_array, file_args)?FL_HASH:FL_STANDARD; else flist_type=FL_STANDARD; #else flist_type=FL_STANDARD; #endif numfiles=default_capacity; if((tptr=strchr(debug_opt, 'i'))!=NULL) { tptr++; numfiles=(FILE_COUNT)strtol(tptr, &tptr, 10); } if(strchr(debug_opt, 'q')!=NULL) flist_type=FL_STANDARD; flist_init(&flist_main, numfiles, (char)flist_type); flist_init(&flist_order, FILELIST_CAPACITY, (char)FL_STANDARD); if(is_add_cmd) { arch_wildcard_allowed=1; expand_wildcards=1; } else expand_wildcards=0; name=malloc_msg(FILENAME_MAX); for(j=limit; j0) error(M_FOUND_N_ERRORS, errors); return(errorlevel); }