📄 filelist.c
字号:
/* * $Id: filelist.c,v 1.3 2003/04/24 11:18:15 andrew_belov Exp $ * --------------------------------------------------------------------------- * XMS routines and functions for dealing with file lists are located here. * Note: the current caching algorithm implies that the filelist is first * sequentially composed, then sequentially read. No random access. * */#include "arj.h"#ifndef SIMPLE_FLIST #include "arj_xms.h"#endifDEBUGHDR(__FILE__) /* Debug information block *//* This file actually consists of two completely different code groups, one for ARJ full-featured filelists, and another one for simplified filelists created by ARJSFX. */#ifndef SIMPLE_FLIST#define FLIST_BLOCK_INCREMENT 16 /* Number of blocks to preallocate when a new block is allocated */#define L_ENTRIES_INCREMENT 512 /* # of entries to reserve at once */#if TARGET==DOS #define XMS_BLOCK_PREALLOC 2 /* Number of preallocated XMS blocks */ #define XMS_MULTIPLIER (FLIST_BLOCK_SIZE/1024)#endif/* Local far heap constants */#define FAR_PROBE 32000L /* Amount of memory allocated to check if we're still alive */#define FAR_HEAP_LOWBOUND 150000 /* If the amount of free memory goes below this, the heap needs to be relocated to XMS */#else /* ARJSFX constants */#define FILES_PER_BLOCK 8#ifdef REARJ #define BLOCKS_LIMIT 512#else #define BLOCKS_LIMIT 1024#endif#endif/* Private CRC union - used for hash table calculation in ARJ. In SFX, we'll use simple checksums instead. */#ifndef SIMPLE_FLISTstruct crc_words{ unsigned short lo; unsigned short hi;};union crc32{ unsigned long crc32; struct crc_words x; char low;};#endif#ifndef SIMPLE_FLIST/* Private data. Again, it has effect in ARJ only. */static FILE_COUNT flist_capacity; /* Filelist capacity (=const) */static unsigned long crc_matches, hash_matches;#endif/* From this point onward, #define REARJ means #define SIMPLE_FLIST (although REARJ filelist model is far from SIMPLE) */#ifdef REARJ/* REARJ service routine - checks if a file is present in the exclusion list */static int is_excluded(char *name){ char tmp_name[CCHMAXPATH]; int tmp_entry, e_entry; FILE_COUNT i; tmp_entry=split_name(name, NULL, NULL); for(i=0; i<flist_exclusion.files; i++) { retrieve_entry(tmp_name, &flist_exclusion, i); e_entry=split_name(tmp_name, NULL, NULL); if(e_entry!=0&&strlen(tmp_name)==e_entry&&!strncmp(tmp_name, name, e_entry)) return(1); if(e_entry==0||(e_entry==tmp_entry&&!strncmp(tmp_name, name, e_entry))) { if(match_wildcard(name+tmp_entry, tmp_name+e_entry)) return(1); } } return(0);}#endif/* Since SFX won't permit neither XMS nor disk storage, a big part of code is skipped for it till find_match(). */#ifndef SIMPLE_FLIST/* A macro too free a block of XMS */#define xms_free(root) free_xms(root->table->xms_handle)/* Allocates a block of extended memory and stores its handle in the hash table entry given. */#if TARGET==DOSstatic int xms_malloc(unsigned long size, struct flist_root *root){ unsigned short xmsize; /* Size of allocated XMS in blocks */ short handle; xmsize=(unsigned short)(size/(unsigned long)FLIST_BLOCK_SIZE); if(size%(unsigned long)FLIST_BLOCK_SIZE!=0L) xmsize++; if(!allocate_xms(xmsize*XMS_MULTIPLIER, &handle)) return(0); root->table->xms_handle=handle; return(1);}#endif/* Reallocates a block of extended memory that belongs to the current hash structure */#if TARGET==DOSstatic int xms_realloc(unsigned long size, struct flist_root *root){ struct xms_move xms_move; unsigned short xmsize; /* Size of allocated RAM in blocks */ short handle, old_handle; xmsize=(unsigned short)(size/(unsigned long)FLIST_BLOCK_SIZE); if(size%(unsigned long)FLIST_BLOCK_SIZE!=0L) xmsize++; if(!allocate_xms(xmsize*XMS_MULTIPLIER, &handle)) return(0); xms_move.src_handle=old_handle=root->table->xms_handle; xms_move.src_offset=0L; xms_move.dest_handle=handle; xms_move.dest_offset=0L; xms_move.length=(unsigned long)root->table->xms_mem_blocks*(unsigned long)FLIST_BLOCK_SIZE; if(!move_xms(&xms_move)) return(0); /* Potential extended memory leak! */ free_xms(old_handle); root->table->xms_handle=handle; return(1);}#endif/* Creates a temporary swap file for holding file lists */static void create_swapfile(struct flist_root *root){ char *sf_name; sf_name=(char *)malloc_msg(CCHMAXPATH); sf_name[0]='\0'; if(swptr_hm[0]!='\0') add_pathsep(strcpy(sf_name, swptr_hm)); strcat(sf_name, arjtemp_spec); find_tmp_filename(sf_name); root->table->sf_name=(char *)malloc_msg(strlen(sf_name)+2); strcpy(root->table->sf_name, sf_name); if((root->table->sf_stream=file_open(root->table->sf_name, m_wbp))==NULL) error(M_CANTOPEN, root->table->sf_name); free(sf_name);}/* Reads the block given, moving it into the cache area */static void get_heap_block(unsigned int block, struct flist_root *root){ #if TARGET==DOS struct xms_move xms_move; #endif char *tmp_block; /* For transfers from far RAM */ if(root->table->block!=block) { if(root->storage==BST_FAR) far_memmove((char FAR *)root->table->cache, (char FAR *)root->table->far_ptrs[block], FLIST_BLOCK_SIZE); else if(root->storage==BST_DISK) { fseek(root->table->sf_stream, (unsigned long)block*FLIST_BLOCK_SIZE, SEEK_SET); tmp_block=(char *)malloc_msg(FLIST_BLOCK_SIZE); if(fread(tmp_block, 1, FLIST_BLOCK_SIZE, root->table->sf_stream)!=FLIST_BLOCK_SIZE) error(M_CANTREAD); far_memmove((char FAR *)root->table->cache, (char FAR *)tmp_block, FLIST_BLOCK_SIZE); free(tmp_block); } #if TARGET==DOS else if(root->storage==BST_XMS) { xms_move.src_handle=root->table->xms_handle; xms_move.src_offset=(unsigned long)block*FLIST_BLOCK_SIZE; xms_move.dest_handle=0; xms_move.dest_offset=(unsigned long)(char FAR *)root->table->cache; xms_move.length=FLIST_BLOCK_SIZE; if(!move_xms(&xms_move)) error(M_LISTING_XMS_ERROR, M_XMS_READ); } #endif root->table->block=block; }}/* Saves a cached block in the heap if it's necessary */static void save_heap_block(struct flist_root *root, char FAR *data){ #if TARGET==DOS struct xms_move xms_move; #endif unsigned int block; /* Block number */ char *tmp_block; /* Temporary transfer area */ if(root->table->not_flushed) { block=root->table->block_to_flush; if(root->storage==BST_FAR) { if(root->table->far_ptrs[block]==NULL) root->table->far_ptrs[block]=farmalloc_msg(FLIST_BLOCK_SIZE); far_memmove(root->table->far_ptrs[block], data, FLIST_BLOCK_SIZE); } else if(root->storage==BST_DISK) { if(root->table->sf_stream==NULL) create_swapfile(root); fseek(root->table->sf_stream, (unsigned long)block*FLIST_BLOCK_SIZE, SEEK_SET); tmp_block=malloc_msg(FLIST_BLOCK_SIZE); far_memmove((char FAR *)tmp_block, data, FLIST_BLOCK_SIZE); file_write(tmp_block, 1, FLIST_BLOCK_SIZE, root->table->sf_stream); free(tmp_block); } #if TARGET==DOS else if(root->storage==BST_XMS) { /* If the block number exceeds the quantity of allocated XMS blocks, resize XMS buffer */ if(block>=root->table->xms_mem_blocks) { if(!xms_realloc((unsigned long)(block+FLIST_BLOCK_INCREMENT)*FLIST_BLOCK_SIZE, root)) error(M_LISTING_XMS_ERROR, M_XMS_WRITE); root->table->xms_mem_blocks=block+FLIST_BLOCK_INCREMENT; } xms_move.src_handle=0; xms_move.src_offset=(unsigned long)data; xms_move.dest_handle=root->table->xms_handle; xms_move.dest_offset=(unsigned long)block*FLIST_BLOCK_SIZE; xms_move.length=(unsigned long)FLIST_BLOCK_SIZE; if(!move_xms(&xms_move)) error(M_LISTING_XMS_ERROR, M_XMS_WRITE); } #endif root->table->not_flushed=0; }}/* Swaps all members of the given heap to disk */static void relocate_heap(struct flist_root *root){ unsigned int hiblock, curblock; hiblock=root->table->hiblock; root->table->sf_stream=NULL; for(curblock=0; curblock<=hiblock; curblock++) { root->storage=BST_FAR; get_heap_block(curblock, root); root->storage=BST_DISK; root->table->block_to_flush=curblock; root->table->not_flushed=1; save_heap_block(root, (char FAR *)root->table->cache); farfree(root->table->far_ptrs[curblock]); } farfree(root->table->far_ptrs); root->storage=BST_DISK;}/* Updates header CRCs */static void update_hcrc(struct flist_root *root, unsigned long crc){ unsigned short hr; union crc32 crc32; char h; crc32.crc32=crc; hr=65535-flist_capacity+1; hr=(hr<=crc32.x.lo)?crc32.x.lo-hr:crc32.x.lo; h=crc32.crc32>>29; root->table->hcrc[hr]|=(1<<h);}/* Reverts CRC, should return 0 if a hash match occured */static unsigned int revert_hcrc(struct flist_root *root, unsigned long crc){ unsigned short hr; union crc32 crc32; char h; crc32.crc32=crc; hr=65535-flist_capacity+1; hr=(hr<=crc32.x.lo)?crc32.x.lo-hr:crc32.x.lo; h=crc32.crc32>>29; return((unsigned int)root->table->hcrc[hr]&((unsigned char)1<<h));}#else/* Returns a checksum for the given string -- "simple" implementation uses checksums rather than CRCs. */static char checksum(char *str){ char rc; rc=str[0]; while(*++str!='\0') rc+=*str; return(rc);}#endif#ifdef REARJ/* (REARJ) looks for a name in backup filelist */static FILE_COUNT find_d_match(struct flist_root *root, char *name){ FILE_COUNT cur_file; if((cur_file=root->d_files)>0L) { do { cur_file--; if(!far_strccmp((char FAR *)name, root->d_names[cur_file])) return(cur_file+1); } while(cur_file!=0); } return(0);}#endif/* Finds if a filename is present in the given filelist */#ifndef REARJstatic int find_match(struct flist_root *root, char *name)#elsestatic int find_match(struct flist_root *root, char *name, FILE_COUNT instance)#endif{ #ifndef SIMPLE_FLIST int cur_entry; struct idblock FAR *idblock_ptr; char FAR *fnm_ptr; /* Pointer to filename in ID block */ struct disk_file_info FAR *dptr; union crc32 crc_term; unsigned int crc_seed; int curblock; char *tmp_name; #else FILE_COUNT cur_entry; char c; #endif #ifndef SIMPLE_FLIST crc32term=CRC_MASK; tmp_name=malloc_str(name); crc32_for_block(tmp_name, strlen(tmp_name)); free(tmp_name); if(!revert_hcrc(root, crc_term.crc32=crc32term)) return(0); hash_matches++; crc_seed=crc_term.x.lo; idblock_ptr=root->table->cache; for(curblock=root->table->low_block; curblock<=root->table->hiblock; curblock++) { if(curblock!=root->table->block_to_flush) { get_heap_block(curblock, root); for(cur_entry=0; cur_entry<idblock_ptr->total_entries; cur_entry++) { if(idblock_ptr->crc[cur_entry]==crc_seed) { crc_matches++; dptr=(struct disk_file_info FAR *)&idblock_ptr->filler[idblock_ptr->sub_offset[cur_entry]]; fnm_ptr=dptr->name; if(!far_strccmp(fnm_ptr, (char FAR *)name)) { root->table->low_block=curblock; return(1); /* Matched */ } } } } } for(curblock=0; curblock<root->table->low_block; curblock++) { if(curblock!=root->table->block_to_flush) { get_heap_block(curblock, root); for(cur_entry=0; cur_entry<idblock_ptr->total_entries; cur_entry++) { if(idblock_ptr->crc[cur_entry]==crc_seed) { crc_matches++; dptr=(struct disk_file_info FAR *)&idblock_ptr->filler[idblock_ptr->sub_offset[cur_entry]]; fnm_ptr=dptr->name; if(!far_strccmp(fnm_ptr, (char FAR *)name)) { root->table->low_block=curblock; return(1); /* Matched */ } } } } } idblock_ptr=(struct idblock FAR *)root->table->sec_cache; for(cur_entry=0; cur_entry<idblock_ptr->total_entries; cur_entry++) { if(idblock_ptr->crc[cur_entry]==crc_seed) { dptr=(struct disk_file_info FAR *)&idblock_ptr->filler[idblock_ptr->sub_offset[cur_entry]]; fnm_ptr=dptr->name; if(!far_strccmp(fnm_ptr, (char FAR *)name)) { root->table->low_block=curblock; return(1); /* Matched */ } } } #else c=checksum(name); for(cur_entry=0; cur_entry<root->files; cur_entry++) { /* Return # of file + 1 if everything matched */ #ifndef REARJ if(root->checksums[cur_entry]==c&&!far_strccmp(root->names[cur_entry], (char FAR *)name)) return(cur_entry+1); #else if(root->checksums[cur_entry]==c&&root->instances[cur_entry]==instance&&!far_strccmp(root->names[cur_entry], (char FAR *)name)) return(cur_entry+1); #endif } #endif return(0);}#ifndef SIMPLE_FLIST/* Frees memory structures associated with filelist search */static void cache_cleanup(struct flist_root *root){ if(!root->table->not_allocated) { if(root->table->hiblock>0||root->table->block_to_flush>0) { save_heap_block(root, (char FAR *)root->table->sec_cache); if(root->table->sec_cache!=NULL&&root->table->sec_cache!=root->table->cache) farfree(root->table->sec_cache); root->table->sec_cache=NULL; } if(root->table->hcrc!=NULL) farfree(root->table->hcrc); root->table->hcrc=NULL; root->table->not_allocated=1; }}/* Invalidates and releases the filelist root */void flist_cleanup_proc(struct flist_root *root){ int block; if(root->table==NULL) return; if(debug_enabled&&strchr(debug_opt, 'v')!=NULL) { msg_cprintf(0, M_XLIST_BLOCKS, root->table->xlist_blocks); if(root==&flist_main) msg_cprintf(0, M_HASH_MATCHES, hash_matches, crc_matches); } if(root->storage==BST_FAR) { for(block=0; block<root->table->xlist_blocks; block++) { if(root->table->far_ptrs[block]!=NULL) farfree(root->table->far_ptrs[block]); } farfree(root->table->far_ptrs); } else if(root->storage==BST_DISK&&root->table->sf_stream!=NULL) { fclose(root->table->sf_stream); file_unlink(root->table->sf_name); free(root->table->sf_name); }#if TARGET==DOS else if(root->storage==BST_XMS) xms_free(root);#endif if(root->storage!=BST_NONE) { if(root->table->enumerators!=NULL) farfree(root->table->enumerators); if(root->table->hcrc!=NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -