OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / arj / filelist.c
1 /*
2  * $Id: filelist.c,v 1.4 2004/04/14 20:54:21 andrew_belov Exp $
3  * ---------------------------------------------------------------------------
4  * XMS routines and functions  for dealing  with file lists are located  here.
5  * Note: the  current  caching algorithm  implies that  the filelist is  first
6  * sequentially composed, then sequentially read. No random access.
7  *
8  */
9
10 #include "arj.h"
11 #ifndef SIMPLE_FLIST
12  #include "arj_xms.h"
13 #endif
14
15 DEBUGHDR(__FILE__)                      /* Debug information block */
16
17 /* This file actually consists of two completely different code groups, one
18    for ARJ full-featured filelists, and another one for simplified filelists
19    created by ARJSFX. */
20
21 #ifndef SIMPLE_FLIST
22
23 #define FLIST_BLOCK_INCREMENT     16    /* Number of blocks to preallocate
24                                            when a new block is allocated */
25 #define L_ENTRIES_INCREMENT      512    /* # of entries to reserve at once */
26
27 #if TARGET==DOS
28  #define XMS_BLOCK_PREALLOC        2    /* Number of preallocated XMS blocks */
29  #define XMS_MULTIPLIER (FLIST_BLOCK_SIZE/1024)
30 #endif
31
32 /* Local far heap constants */
33
34 #define FAR_PROBE             32000L    /* Amount of memory allocated to check
35                                            if we're still alive */
36 #define FAR_HEAP_LOWBOUND     150000    /* If the amount of free memory goes
37                                            below this, the heap needs to be
38                                            relocated to XMS */
39
40 #else                                   /* ARJSFX constants */
41
42 #define FILES_PER_BLOCK            8
43 #ifdef REARJ
44  #define BLOCKS_LIMIT            512
45 #else
46  #define BLOCKS_LIMIT           1024
47 #endif
48
49 #endif
50
51 /* Private CRC union - used for hash table calculation in ARJ. In SFX, we'll
52    use simple checksums instead. */
53
54 #ifndef SIMPLE_FLIST
55
56 struct crc_words
57 {
58  unsigned short lo;
59  unsigned short hi;
60 };
61
62 union crc32
63 {
64  unsigned long crc32;
65  struct crc_words x;
66  char low;
67 };
68
69 #endif
70
71 #ifndef SIMPLE_FLIST
72
73 /* Private data. Again, it has effect in ARJ only. */
74
75 static FILE_COUNT flist_capacity;       /* Filelist capacity (=const) */
76 static unsigned long crc_matches, hash_matches;
77
78 #endif
79
80 /* From this point onward, #define REARJ means #define SIMPLE_FLIST
81    (although REARJ filelist model is far from SIMPLE) */
82
83 #ifdef REARJ
84
85 /* REARJ service routine - checks if a file is present in the exclusion list */
86
87 static int is_excluded(char *name)
88 {
89  char tmp_name[CCHMAXPATH];
90  int tmp_entry, e_entry;
91  FILE_COUNT i;
92
93  tmp_entry=split_name(name, NULL, NULL);
94  for(i=0; i<flist_exclusion.files; i++)
95  {
96   retrieve_entry(tmp_name, &flist_exclusion, i);
97   e_entry=split_name(tmp_name, NULL, NULL);
98   if(e_entry!=0&&strlen(tmp_name)==e_entry&&!strncmp(tmp_name, name, e_entry))
99    return(1);
100   if(e_entry==0||(e_entry==tmp_entry&&!strncmp(tmp_name, name, e_entry)))
101   {
102    if(match_wildcard(name+tmp_entry, tmp_name+e_entry))
103     return(1);
104   }
105  }
106  return(0);
107 }
108
109 #endif
110
111 /* Since SFX won't permit neither XMS nor disk storage, a big part of code is
112    skipped for it till find_match(). */
113
114 #ifndef SIMPLE_FLIST
115
116 /* A macro too free a block of XMS */
117
118 #define xms_free(root) free_xms(root->table->xms_handle)
119
120 /* Allocates a block of extended memory and stores its handle in the hash
121    table entry given. */
122
123 #if TARGET==DOS
124 static int xms_malloc(unsigned long size, struct flist_root *root)
125 {
126  unsigned short xmsize;                 /* Size of allocated XMS in blocks */
127  short handle;
128
129  xmsize=(unsigned short)(size/(unsigned long)FLIST_BLOCK_SIZE);
130  if(size%(unsigned long)FLIST_BLOCK_SIZE!=0L)
131   xmsize++;
132  if(!allocate_xms(xmsize*XMS_MULTIPLIER, &handle))
133   return(0);
134  root->table->xms_handle=handle;
135  return(1);
136 }
137 #endif
138
139 /* Reallocates a block of extended memory that belongs to the current hash
140    structure */
141
142 #if TARGET==DOS
143 static int xms_realloc(unsigned long size, struct flist_root *root)
144 {
145  struct xms_move xms_move;
146  unsigned short xmsize;                 /* Size of allocated RAM in blocks */
147  short handle, old_handle;
148
149  xmsize=(unsigned short)(size/(unsigned long)FLIST_BLOCK_SIZE);
150  if(size%(unsigned long)FLIST_BLOCK_SIZE!=0L)
151   xmsize++;
152  if(!allocate_xms(xmsize*XMS_MULTIPLIER, &handle))
153   return(0);
154  xms_move.src_handle=old_handle=root->table->xms_handle;
155  xms_move.src_offset=0L;
156  xms_move.dest_handle=handle;
157  xms_move.dest_offset=0L;
158  xms_move.length=(unsigned long)root->table->xms_mem_blocks*(unsigned long)FLIST_BLOCK_SIZE;
159  if(!move_xms(&xms_move))
160   return(0);                            /* Potential extended memory leak! */
161  free_xms(old_handle);
162  root->table->xms_handle=handle;
163  return(1);
164 }
165 #endif
166
167 /* Creates a temporary swap file for holding file lists */
168
169 static void create_swapfile(struct flist_root *root)
170 {
171  char *sf_name;
172
173  sf_name=(char *)malloc_msg(CCHMAXPATH);
174  sf_name[0]='\0';
175  if(swptr_hm[0]!='\0')
176   add_pathsep(strcpy(sf_name, swptr_hm));
177  strcat(sf_name, arjtemp_spec);
178  find_tmp_filename(sf_name);
179  root->table->sf_name=(char *)malloc_msg(strlen(sf_name)+2);
180  strcpy(root->table->sf_name, sf_name);
181  if((root->table->sf_stream=file_open(root->table->sf_name, m_wbp))==NULL)
182   error(M_CANTOPEN, root->table->sf_name);
183  free(sf_name);
184 }
185
186 /* Reads the block given, moving it into the cache area */
187
188 static void get_heap_block(unsigned int block, struct flist_root *root)
189 {
190  #if TARGET==DOS
191   struct xms_move xms_move;
192  #endif
193  char *tmp_block;                       /* For transfers from far RAM */
194
195  if(root->table->block!=block)
196  {
197   if(root->storage==BST_FAR)
198    far_memmove((char FAR *)root->table->cache, (char FAR *)root->table->far_ptrs[block], FLIST_BLOCK_SIZE);
199   else if(root->storage==BST_DISK)
200   {
201    fseek(root->table->sf_stream, (unsigned long)block*FLIST_BLOCK_SIZE, SEEK_SET);
202    tmp_block=(char *)malloc_msg(FLIST_BLOCK_SIZE);
203    if(fread(tmp_block, 1, FLIST_BLOCK_SIZE, root->table->sf_stream)!=FLIST_BLOCK_SIZE)
204     error(M_CANTREAD);
205    far_memmove((char FAR *)root->table->cache, (char FAR *)tmp_block, FLIST_BLOCK_SIZE);
206    free(tmp_block);
207   }
208  #if TARGET==DOS
209   else if(root->storage==BST_XMS)
210   {
211    xms_move.src_handle=root->table->xms_handle;
212    xms_move.src_offset=(unsigned long)block*FLIST_BLOCK_SIZE;
213    xms_move.dest_handle=0;
214    xms_move.dest_offset=(unsigned long)(char FAR *)root->table->cache;
215    xms_move.length=FLIST_BLOCK_SIZE;
216    if(!move_xms(&xms_move))
217     error(M_LISTING_XMS_ERROR, M_XMS_READ);
218   }
219  #endif
220   root->table->block=block;
221  }
222 }
223
224 /* Saves a cached block in the heap if it's necessary */
225
226 static void save_heap_block(struct flist_root *root, char FAR *data)
227 {
228  #if TARGET==DOS
229   struct xms_move xms_move;
230  #endif
231  unsigned int block;                    /* Block number */
232  char *tmp_block;                       /* Temporary transfer area */
233
234  if(root->table->not_flushed)
235  {
236   block=root->table->block_to_flush;
237   if(root->storage==BST_FAR)
238   {
239    if(root->table->far_ptrs[block]==NULL)
240     root->table->far_ptrs[block]=farmalloc_msg(FLIST_BLOCK_SIZE);
241    far_memmove(root->table->far_ptrs[block], data, FLIST_BLOCK_SIZE);
242   }
243   else if(root->storage==BST_DISK)
244   {
245    if(root->table->sf_stream==NULL)
246     create_swapfile(root);
247    fseek(root->table->sf_stream, (unsigned long)block*FLIST_BLOCK_SIZE, SEEK_SET);
248    tmp_block=malloc_msg(FLIST_BLOCK_SIZE);
249    far_memmove((char FAR *)tmp_block, data, FLIST_BLOCK_SIZE);
250    file_write(tmp_block, 1, FLIST_BLOCK_SIZE, root->table->sf_stream);
251    free(tmp_block);
252   }
253  #if TARGET==DOS
254   else if(root->storage==BST_XMS)
255   {
256    /* If the block number exceeds the quantity of allocated XMS blocks, resize
257       XMS buffer */
258    if(block>=root->table->xms_mem_blocks)
259    {
260     if(!xms_realloc((unsigned long)(block+FLIST_BLOCK_INCREMENT)*FLIST_BLOCK_SIZE, root))
261      error(M_LISTING_XMS_ERROR, M_XMS_WRITE);
262     root->table->xms_mem_blocks=block+FLIST_BLOCK_INCREMENT;
263    }
264    xms_move.src_handle=0;
265    xms_move.src_offset=(unsigned long)data;
266    xms_move.dest_handle=root->table->xms_handle;
267    xms_move.dest_offset=(unsigned long)block*FLIST_BLOCK_SIZE;
268    xms_move.length=(unsigned long)FLIST_BLOCK_SIZE;
269    if(!move_xms(&xms_move))
270     error(M_LISTING_XMS_ERROR, M_XMS_WRITE);
271   }
272  #endif
273   root->table->not_flushed=0;
274  }
275 }
276
277 /* Swaps all members of the given heap to disk */
278
279 static void relocate_heap(struct flist_root *root)
280 {
281  unsigned int hiblock, curblock;
282
283  hiblock=root->table->hiblock;
284  root->table->sf_stream=NULL;
285  for(curblock=0; curblock<=hiblock; curblock++)
286  {
287   root->storage=BST_FAR;
288   get_heap_block(curblock, root);
289   root->storage=BST_DISK;
290   root->table->block_to_flush=curblock;
291   root->table->not_flushed=1;
292   save_heap_block(root, (char FAR *)root->table->cache);
293   farfree(root->table->far_ptrs[curblock]);
294  }
295  farfree(root->table->far_ptrs);
296  root->storage=BST_DISK;
297 }
298
299 /* Updates header CRCs */
300
301 static void update_hcrc(struct flist_root *root, unsigned long crc)
302 {
303  unsigned short hr;
304  union crc32 crc32;
305  char h;
306
307  crc32.crc32=crc;
308  hr=65535-flist_capacity+1;
309  hr=(hr<=crc32.x.lo)?crc32.x.lo-hr:crc32.x.lo;
310  h=crc32.crc32>>29;
311  root->table->hcrc[hr]|=(1<<h);
312 }
313
314 /* Reverts CRC, should return 0 if a hash match occured */
315
316 static unsigned int revert_hcrc(struct flist_root *root, unsigned long crc)
317 {
318  unsigned short hr;
319  union crc32 crc32;
320  char h;
321
322  crc32.crc32=crc;
323  hr=65535-flist_capacity+1;
324  hr=(hr<=crc32.x.lo)?crc32.x.lo-hr:crc32.x.lo;
325  h=crc32.crc32>>29;
326  return((unsigned int)root->table->hcrc[hr]&((unsigned char)1<<h));
327 }
328
329 #else
330
331 /* Returns a checksum for the given string -- "simple" implementation uses
332    checksums rather than CRCs. */
333
334 static char checksum(char *str)
335 {
336  char rc;
337
338  rc=str[0];
339  while(*++str!='\0')
340   rc+=*str;
341  return(rc);
342 }
343
344 #endif
345
346 #ifdef REARJ
347
348 /* (REARJ) looks for a name in backup filelist */
349
350 static FILE_COUNT find_d_match(struct flist_root *root, char *name)
351 {
352  FILE_COUNT cur_file;
353
354  if((cur_file=root->d_files)>0L)
355  {
356   do
357   {
358    cur_file--;
359    if(!far_strccmp((char FAR *)name, root->d_names[cur_file]))
360     return(cur_file+1);
361   } while(cur_file!=0);
362  }
363  return(0);
364 }
365
366 #endif
367
368 /* Finds if a filename is present in the given filelist */
369
370 #ifndef REARJ
371 static int find_match(struct flist_root *root, char *name)
372 #else
373 static int find_match(struct flist_root *root, char *name, FILE_COUNT instance)
374 #endif
375 {
376  #ifndef SIMPLE_FLIST
377   int cur_entry;
378   struct idblock FAR *idblock_ptr;
379   char FAR *fnm_ptr;                    /* Pointer to filename in ID block */
380   struct disk_file_info FAR *dptr;
381   union crc32 crc_term;
382   unsigned int crc_seed;
383   int curblock;
384   char *tmp_name;
385  #else
386   FILE_COUNT cur_entry;
387   char c;
388  #endif
389
390  #ifndef SIMPLE_FLIST
391   crc32term=CRC_MASK;
392   tmp_name=malloc_str(name);
393   crc32_for_block(tmp_name, strlen(tmp_name));
394   free(tmp_name);
395   if(!revert_hcrc(root, crc_term.crc32=crc32term))
396    return(0);
397   hash_matches++;
398   crc_seed=crc_term.x.lo;
399   idblock_ptr=root->table->cache;
400   for(curblock=root->table->low_block; curblock<=root->table->hiblock; curblock++)
401   {
402    if(curblock!=root->table->block_to_flush)
403    {
404     get_heap_block(curblock, root);
405     for(cur_entry=0; cur_entry<idblock_ptr->total_entries; cur_entry++)
406     {
407      if(idblock_ptr->crc[cur_entry]==crc_seed)
408      {
409       crc_matches++;
410       dptr=(struct disk_file_info FAR *)&idblock_ptr->filler[idblock_ptr->sub_offset[cur_entry]];
411       fnm_ptr=dptr->name;
412       if(!far_strccmp(fnm_ptr, (char FAR *)name))
413       {
414        root->table->low_block=curblock;
415        return(1);                       /* Matched */
416       }
417      }
418     }
419    }
420   }
421   for(curblock=0; curblock<root->table->low_block; curblock++)
422   {
423    if(curblock!=root->table->block_to_flush)
424    {
425     get_heap_block(curblock, root);
426     for(cur_entry=0; cur_entry<idblock_ptr->total_entries; cur_entry++)
427     {
428      if(idblock_ptr->crc[cur_entry]==crc_seed)
429      {
430       crc_matches++;
431       dptr=(struct disk_file_info FAR *)&idblock_ptr->filler[idblock_ptr->sub_offset[cur_entry]];
432       fnm_ptr=dptr->name;
433       if(!far_strccmp(fnm_ptr, (char FAR *)name))
434       {
435        root->table->low_block=curblock;
436        return(1);                       /* Matched */
437       }
438      }
439     }
440    }
441   }
442   idblock_ptr=(struct idblock FAR *)root->table->sec_cache;
443   for(cur_entry=0; cur_entry<idblock_ptr->total_entries; cur_entry++)
444   {
445    if(idblock_ptr->crc[cur_entry]==crc_seed)
446    {
447     dptr=(struct disk_file_info FAR *)&idblock_ptr->filler[idblock_ptr->sub_offset[cur_entry]];
448     fnm_ptr=dptr->name;
449     if(!far_strccmp(fnm_ptr, (char FAR *)name))
450     {
451      root->table->low_block=curblock;
452      return(1);                         /* Matched */
453     }
454    }
455   }
456  #else
457   c=checksum(name);
458   for(cur_entry=0; cur_entry<root->files; cur_entry++)
459   {
460    /* Return # of file + 1 if everything matched */
461    #ifndef REARJ
462     if(root->checksums[cur_entry]==c&&!far_strccmp(root->names[cur_entry], (char FAR *)name))
463      return(cur_entry+1);
464    #else
465     if(root->checksums[cur_entry]==c&&root->instances[cur_entry]==instance&&!far_strccmp(root->names[cur_entry], (char FAR *)name))
466      return(cur_entry+1);
467    #endif
468   }
469  #endif
470  return(0);
471 }
472
473 #ifndef SIMPLE_FLIST
474
475 /* Frees memory structures associated with filelist search */
476
477 static void cache_cleanup(struct flist_root *root)
478 {
479  if(!root->table->not_allocated)
480  {
481   if(root->table->hiblock>0||root->table->block_to_flush>0)
482   {
483    save_heap_block(root, (char FAR *)root->table->sec_cache);
484    if(root->table->sec_cache!=NULL&&root->table->sec_cache!=root->table->cache)
485     farfree(root->table->sec_cache);
486    root->table->sec_cache=NULL;
487   }
488   if(root->table->hcrc!=NULL)
489    farfree(root->table->hcrc);
490   root->table->hcrc=NULL;
491   root->table->not_allocated=1;
492  }
493 }
494
495 /* Invalidates and releases the filelist root */
496
497 void flist_cleanup_proc(struct flist_root *root)
498 {
499  int block;
500
501  if(root->table==NULL)
502   return;
503  if(debug_enabled&&strchr(debug_opt, 'v')!=NULL)
504  {
505   msg_cprintf(0, M_XLIST_BLOCKS, root->table->xlist_blocks);
506   if(root==&flist_main)
507    msg_cprintf(0, M_HASH_MATCHES, hash_matches, crc_matches);
508  }
509  if(root->storage==BST_FAR)
510  {
511   for(block=0; block<root->table->xlist_blocks; block++)
512   {
513    if(root->table->far_ptrs[block]!=NULL)
514     farfree(root->table->far_ptrs[block]);
515   }
516   farfree(root->table->far_ptrs);
517  }
518  else if(root->storage==BST_DISK&&root->table->sf_stream!=NULL)
519  {
520   fclose(root->table->sf_stream);
521   file_unlink(root->table->sf_name);
522   free(root->table->sf_name);
523  }
524 #if TARGET==DOS
525  else if(root->storage==BST_XMS)
526   xms_free(root);
527 #endif
528  if(root->storage!=BST_NONE)
529  {
530   if(root->table->enumerators!=NULL)
531    farfree(root->table->enumerators);
532   if(root->table->hcrc!=NULL)
533    farfree(root->table->hcrc);
534   if(root->table->sec_cache!=NULL&&root->table->sec_cache!=root->table->cache)
535    farfree(root->table->sec_cache);
536   if(root->table->cache!=NULL)
537    farfree(root->table->cache);
538   free(root->table);
539   if(root->fsptr!=NULL)
540    free(root->fsptr);
541  }
542  root->storage=BST_NONE;
543 }
544
545 #elif defined(REARJ)                    /* REARJ-only version of cleanup proc. */
546
547 void flist_cleanup_proc(struct flist_root *root)
548 {
549  FILE_COUNT i;
550
551  if(root->files>0)
552  {
553   for(i=0; i<root->files; i++)
554    farfree(root->names[i]);
555   for(i=0; i<root->d_files; i++)
556    farfree(root->d_names[i]);
557   farfree(root->names);
558   farfree(root->instances);
559   if(root->d_names!=NULL)
560    farfree(root->d_names);
561   if(root->checksums!=NULL)
562    farfree(root->checksums);
563   root->files=0;
564  }
565 }
566
567 #endif
568
569 /* Retrieves a filename with given entry code from the list. Two implemenations
570    follow... */
571
572 #ifndef SIMPLE_FLIST
573
574 void retrieve_entry(char *dest, struct file_properties *properties, struct flist_root *root, FILE_COUNT entry)
575 {
576  struct idblock FAR *idblock_ptr;       /* Temporary cache pointer */
577  struct disk_file_info FAR *dptr;
578  int idx;                               /* Temporary idblock index */
579  int curblock;
580
581  idblock_ptr=root->table->cache;
582  /* If there are unfreed locations, do neccessary cleanup */
583  if(!root->table->not_allocated)
584    cache_cleanup(root);
585  if(root->table->hiblock<=0)
586  {
587   curblock=0;
588   idblock_ptr=root->table->sec_cache;
589  }
590  else
591  {
592   for(curblock=0; curblock<=root->table->hiblock; curblock++)
593   {
594    if(root->table->enumerators[curblock]>entry)
595     break;
596   }
597   if(curblock>0)
598    curblock--;
599   get_heap_block(curblock, root);
600  }
601  idx=idblock_ptr->sub_offset[entry-root->table->enumerators[curblock]];
602  dptr=(struct disk_file_info FAR *)&idblock_ptr->filler[idx];
603  /* Allow NULL destinations for hardlink search -- ASR fix 24/08/2001 */
604  if(dest!=NULL)
605   far_strcpy((char FAR *)dest, (char FAR *)dptr->name);
606  if(properties!=NULL)
607   far_memmove((char FAR *)properties, (char FAR *)&dptr->file_properties, sizeof(struct file_properties));
608 }
609
610 #else
611
612 /* Retrieves a filelist entry */
613
614 void retrieve_entry(char *dest, struct flist_root *root, FILE_COUNT num)
615 {
616  #ifdef REARJ
617   FILE_COUNT instance;
618  #endif
619
620  #ifdef REARJ
621   instance=root->instances[num];
622   far_strcpy((char FAR *)dest, root->d_names[instance-1]);
623   far_strcat((char FAR *)dest, root->names[num]);
624  #else
625   far_strcpy((char FAR *)dest, root->names[num]);
626  #endif
627 }
628
629 #endif
630
631 /* Adds an entry to the hash. Returns -1 if there was an error. There are two
632    implementations of it. */
633
634 #ifndef SIMPLE_FLIST
635
636 int add_entry(struct flist_root *root, char *name, FILE_COUNT *count, struct file_properties *properties)
637 {
638  struct idblock FAR *idblock_ptr;
639  struct disk_file_info FAR *dptr;
640  #ifdef TILED
641   void FAR *tmp_ptr;                    /* Used for heap allocation test */
642  #endif
643  unsigned long tmp_crc;
644  long tmp_offset;                       /* Offset to fileinfo in blocks */
645  int new_blocks;                        /* New qty of XList blocks */
646  int old_blocks;                        /* Old qty of XList blocks */
647  int curblock;                          /* Cleanup loop variable */
648  int index;                             /* Index in ID block */
649  FILE_COUNT tmp_files;
650  int tmp_hiblock;
651  int extend_len;                        /* Number of bytes to reserve */
652
653  if(root->files>=root->maxfiles)
654  {
655   #if SFX_LEVEL>=ARJSFXV
656    msg_cprintf(0, M_NAMES_LIMIT, root->maxfiles, name);
657   #else
658    msg_cprintf(0, M_NAMES_LIMIT, root->maxfiles, name);
659   #endif
660   return(-1);
661  }
662  if((idblock_ptr=root->table->sec_cache)==NULL)
663  {
664   if(root->type!=FL_STANDARD)
665    root->table->sec_cache=farmalloc_msg(FLIST_BLOCK_SIZE);
666   else
667    root->table->sec_cache=root->table->cache;
668   idblock_ptr=root->table->sec_cache;
669   idblock_ptr->total_entries=0;
670   idblock_ptr->size=0;
671  }
672  /* ASR fix -- debug enhancement 03/10/2001 */
673  if(debug_enabled&&strchr(debug_opt, '.')!=NULL)
674   msg_cprintf(0, M_TOKEN, name);
675  if(root->type!=FL_STANDARD&&root->no_dupl)
676  {
677   if(find_match(root, name))
678   {
679    if(count!=NULL)
680     (*count)++;
681    return(0);
682   }
683  }
684  tmp_hiblock=root->table->hiblock;
685  extend_len=strlen(name)+sizeof(struct file_properties);
686  tmp_files=root->files;
687  tmp_offset=(long)idblock_ptr->size;
688  /* Check against limits */
689  if(idblock_ptr->total_entries+1>ENTRIES_PER_BLOCK||(tmp_offset+(long)extend_len+1>(long)(FLIST_BLOCK_SIZE-sizeof(struct idblock)-2)))
690  {
691   save_heap_block(root, (char FAR *)root->table->sec_cache);
692   /* WARNING: compiler-dependent... */
693   #ifdef TILED
694    if((tmp_ptr=farmalloc(FAR_PROBE))==NULL)
695    {
696     msg_cprintf(0, M_HASH_MEM_LACK, name);
697     return(-1);
698    }
699    farfree(tmp_ptr);
700   #endif
701   /* If the far heap has overgrown its limits, relocate it to XMS ASAP */
702   if(root->storage==BST_FAR&&filelist_storage!=BST_NONE)
703   {
704    if(root->files>max_filenames||farcoreleft()<FAR_HEAP_LOWBOUND)
705     relocate_heap(root);
706   }
707   root->table->block_to_flush++;
708   tmp_hiblock++;
709   /* Reallocate the block if it's needed */
710   if(tmp_hiblock+1>=root->table->xlist_blocks)
711   {
712    old_blocks=root->table->xlist_blocks;
713    root->table->xlist_blocks=new_blocks=old_blocks+FLIST_BLOCK_INCREMENT;
714    root->table->enumerators=farrealloc_msg(root->table->enumerators, (unsigned long)new_blocks*sizeof(unsigned long));
715    if(root->storage==BST_FAR)
716    {
717     root->table->far_ptrs=farrealloc_msg(root->table->far_ptrs, (unsigned long)new_blocks*sizeof(char FAR *));
718     /* Reset the newly created pointers to NULL */
719     for(curblock=old_blocks; curblock<new_blocks; curblock++)
720      root->table->far_ptrs[curblock]=NULL;
721    }
722   }
723   /* New block starts, with no file entries yet */
724   idblock_ptr->total_entries=0;
725   idblock_ptr->size=0;
726   tmp_offset=0L;
727   root->table->hiblock=tmp_hiblock;
728   root->table->enumerators[tmp_hiblock]=tmp_files;
729   root->table->enumerators[tmp_hiblock+1]=FLS_END;
730  }
731  root->table->not_flushed=1;
732  dptr=(struct disk_file_info FAR *)&idblock_ptr->filler[tmp_offset];
733  far_strcpy(dptr->name, (char FAR *)name);
734  if(properties!=NULL)
735   far_memmove((char FAR *)&dptr->file_properties, (char FAR *)properties, sizeof(struct file_properties));
736  index=tmp_files-root->table->enumerators[tmp_hiblock];
737  idblock_ptr->sub_offset[index]=(int)tmp_offset;
738  idblock_ptr->size=tmp_offset+extend_len+1;
739  idblock_ptr->total_entries++;
740  root->files++;
741  if(root->type!=FL_STANDARD)
742  {
743   crc32term=CRC_MASK;
744   crc32_for_block(name, strlen(name));
745   tmp_crc=crc32term;
746   update_hcrc(root, tmp_crc);
747   idblock_ptr->crc[index]=(char)tmp_crc;
748  }
749  if(count!=NULL)
750   (*count)++;
751  return(0);
752 }
753
754 #else
755
756 #ifdef REARJ
757 int add_entry(struct flist_root *root, char *name, FILE_COUNT *count)
758 #else
759 int add_entry(struct flist_root *root, struct flist_root *search_flist, char *name, FILE_COUNT *count)
760 #endif
761 {
762  long diff;
763  char FAR * FAR *names_ptr;
764  int nl;
765  char FAR *nptr;
766  unsigned int nblocks;
767  char FAR *checksums_ptr;
768  FILE_COUNT nfiles;
769  #ifdef REARJ
770   char tmp_name[CCHMAXPATH];
771   char pathname[CCHMAXPATH];
772   int tmp_entry;
773   FILE_COUNT dir_num;
774   FILE_COUNT FAR *instances_ptr;
775  #endif
776
777  if(root->files>=root->maxfiles)
778  {
779   #if SFX_LEVEL>=ARJSFXV
780    msg_cprintf(0, M_NAMES_LIMIT, root->maxfiles, name);
781   #else
782    msg_cprintf(0, M_NAMES_LIMIT, root->maxfiles, name);
783   #endif
784   return(-1);
785  }
786  #ifdef REARJ
787   if(root->check_excl&&is_excluded(name))
788    return(0);
789   tmp_entry=split_name(name, NULL, tmp_name);
790   if(tmp_entry>0)
791    strncpy(pathname, name, tmp_entry);
792   pathname[tmp_entry]='\0';
793   dir_num=find_d_match(root, pathname);
794   if(root->no_dupl&&dir_num!=0&&find_match(root, tmp_name, dir_num))
795    return(0);
796  #else
797   if(root->no_dupl&&find_match(root, name))
798   {
799    if(count!=NULL)
800     (*count)++;
801    return(0);
802   }
803  #endif
804  /* Separate directory storage is available in (and required by) REARJ only */
805  #ifdef REARJ
806   if(dir_num==0)
807   {
808    if(root->d_files>=root->d_boundary)
809    {
810     diff=(long)root->maxfiles-root->d_files;
811     diff=max(diff, 64L);
812     diff+=(long)root->d_files;
813     if((names_ptr=(char FAR * FAR *)farrealloc(root->d_names, diff*sizeof(char FAR *)))==NULL)
814     {
815      #if SFX_LEVEL>=ARJSFXV
816       msg_cprintf(0, M_HASH_MEM_LACK, name);
817      #else
818       msg_cprintf(0, M_HASH_MEM_LACK, name);
819      #endif
820      return(-1);
821     }
822     root->d_names=names_ptr;
823     root->d_boundary=(FILE_COUNT)diff;
824    }
825    nl=strlen(pathname);
826    if((nptr=(char FAR *)farmalloc(nl+1))==NULL)
827    {
828     #if SFX_LEVEL>=ARJSFXV
829      msg_cprintf(0, M_HASH_MEM_LACK, name);
830     #else
831      msg_cprintf(0, M_HASH_MEM_LACK, name);
832     #endif
833     return(-1);
834    }
835    root->d_names[root->d_files]=nptr;
836    far_strcpy(nptr, (char FAR *)pathname);
837    dir_num=++root->d_files;
838   }
839  #endif
840  if(root->files>=root->boundary)
841  {
842   nblocks=root->maxfiles/FILES_PER_BLOCK;
843   if(nblocks>BLOCKS_LIMIT)
844    nblocks=BLOCKS_LIMIT;
845   diff=(long)root->maxfiles-root->files;
846   if((long)nblocks<diff)
847    diff=(long)nblocks;
848   diff+=(long)root->files;
849   if((names_ptr=(char FAR * FAR *)farrealloc(root->names, diff*sizeof(char FAR *)))==NULL)
850   {
851    #if SFX_LEVEL>=ARJSFXV
852     msg_cprintf(0, M_HASH_MEM_LACK, name);
853    #else
854     msg_cprintf(0, M_HASH_MEM_LACK, name);
855    #endif
856    return(-1);
857   }
858   checksums_ptr=NULL;
859   if(root->no_dupl)
860   {
861    if((checksums_ptr=(char FAR *)farrealloc(root->checksums, diff*sizeof(FILE_COUNT)))==NULL)
862    {
863     #if SFX_LEVEL>=ARJSFXV
864      msg_cprintf(0, M_HASH_MEM_LACK, name);
865     #else
866      msg_cprintf(0, M_HASH_MEM_LACK, name);
867     #endif
868     return(-1);
869    }
870   }
871   #ifdef REARJ
872    if((instances_ptr=(FILE_COUNT FAR *)farrealloc(root->instances, diff*sizeof(FILE_COUNT)))==NULL)
873    {
874     #if SFX_LEVEL>=ARJSFXV
875      msg_cprintf(0, M_HASH_MEM_LACK, name);
876     #else
877      msg_cprintf(0, M_HASH_MEM_LACK, name);
878     #endif
879     return(-1);
880    }
881   #endif
882   root->names=names_ptr;
883   root->checksums=checksums_ptr;
884   #ifdef REARJ
885    root->instances=instances_ptr;
886   #endif
887   root->boundary=(FILE_COUNT)diff;
888  }
889  #ifdef REARJ
890   nl=strlen(tmp_name);
891  #else
892   nl=strlen(name);
893  #endif
894  if((nptr=(char FAR *)farmalloc(nl+1))==NULL)
895  {
896   #if SFX_LEVEL>=ARJSFXV
897    msg_cprintf(0, M_HASH_MEM_LACK, name);
898   #else
899    msg_cprintf(0, M_HASH_MEM_LACK, name);
900   #endif
901   return(-1);
902  }
903  nfiles=root->files;
904  root->names[nfiles]=nptr;
905  #ifdef REARJ
906   far_strcpy(nptr, (char FAR *)tmp_name);
907  #else
908   far_strcpy(nptr, (char FAR *)name);
909  #endif
910  #ifdef REARJ
911   root->instances[nfiles]=dir_num;
912   if(root->no_dupl)
913    root->checksums[nfiles]=checksum(tmp_name);
914  #else
915   if(root->no_dupl)
916    root->checksums[nfiles]=checksum(name);
917  #endif
918  root->files++;
919  if(count!=NULL)
920   (*count)++;
921  return(0);
922 }
923
924 #endif
925
926 /* Initializes the filelist storage */
927
928 #if SFX_LEVEL>=ARJ
929 void flist_init_proc(struct flist_root *root, FILE_COUNT maxfiles, char type)
930 #elif defined(REARJ)
931 void flist_init(struct flist_root *root, FILE_COUNT maxfiles, int no_dupl, int check_excl)
932 #else
933 void flist_init(struct flist_root *root, FILE_COUNT maxfiles, char no_dupl)
934 #endif
935 {
936  #ifndef SIMPLE_FLIST
937   int curblock, cur_entry;
938   char *cptr;
939
940   root->storage=BST_NONE;
941   root->maxfiles=maxfiles;
942   root->type=type;
943   root->files=0L;
944   root->no_dupl=0;
945   root->fsptr=NULL;
946   root->table=NULL;
947   if(maxfiles==0L)
948    return;
949   if(root==&flist_main)
950    hash_matches=crc_matches=0;
951   if(debug_enabled&&strchr(debug_opt, 'v')!=NULL)
952    msg_cprintf(0, M_SEARCH_FLAG, type);
953   root->table=malloc_msg(sizeof(struct flist_table));
954  #if TARGET==DOS
955   if(detect_xms()&&filelist_storage==BST_XMS)
956   {
957    root->storage=BST_XMS;
958    get_xms_entry();
959    if(!xms_malloc(XMS_BLOCK_PREALLOC*FLIST_BLOCK_SIZE, root))
960     error(M_LISTING_XMS_ERROR, M_XMS_INIT);
961    root->table->xms_mem_blocks=XMS_BLOCK_PREALLOC;
962   }
963   else
964  #endif
965   if(filelist_storage!=BST_NONE&&max_filenames<50)
966   {
967    root->storage=BST_DISK;
968    root->table->sf_stream=NULL;
969   }
970   else
971   {
972    root->storage=BST_FAR;
973    root->table->far_ptrs=farmalloc_msg((unsigned long)FLIST_BLOCK_INCREMENT*sizeof(void FAR *));
974    for(curblock=0; curblock<FLIST_BLOCK_INCREMENT; curblock++)
975     root->table->far_ptrs[curblock]=NULL;
976   }
977   root->table->cache=farmalloc_msg(FLIST_BLOCK_SIZE);
978   root->table->sec_cache=NULL;
979   root->table->block=-1;
980   root->table->block_to_flush=0;
981   root->table->low_block=0;
982   root->table->not_flushed=0;
983   root->table->not_allocated=0;
984   root->table->xlist_blocks=FLIST_BLOCK_INCREMENT;
985   root->table->enumerators=farmalloc_msg((unsigned long)FLIST_BLOCK_INCREMENT*sizeof(FILE_COUNT));
986   root->table->enumerators[0]=0;
987   root->table->enumerators[1]=FLS_END;
988   root->table->hiblock=0;
989   root->table->hcrc=NULL;
990   flist_capacity=FILELIST_CAPACITY;
991   if(debug_enabled&&(cptr=strchr(debug_opt, 'z'))!=NULL)
992    flist_capacity=(FILE_COUNT)strtol(cptr, &cptr, 10);
993   if(root->type!=FL_STANDARD)
994   {
995    root->table->hcrc=farmalloc_msg((FILE_COUNT)flist_capacity);
996    for(cur_entry=0; cur_entry<flist_capacity; cur_entry++)
997     root->table->hcrc[cur_entry]=0;
998   }
999  #else
1000   root->maxfiles=maxfiles;
1001   root->no_dupl=(int)no_dupl;
1002   root->files=0;
1003   root->boundary=0;
1004   root->checksums=NULL;
1005   root->names=NULL;
1006   #ifdef REARJ
1007    root->check_excl=check_excl;
1008    root->d_files=0;
1009    root->d_boundary=0;
1010    root->d_names=NULL;
1011    root->instances=NULL;
1012   #endif
1013  #endif
1014 }
1015
1016 #if SFX_LEVEL>=ARJ&&TARGET==UNIX
1017
1018 /* [Hard]link search routine. Either returns a pointer to an existing
1019    entry in l_search structure, or creates a new entry. May operate
1020    with symlinks too (e.g. elimination of circular links) */
1021
1022 FILE_COUNT link_search(struct l_entries *entries, struct l_search *l_search, struct file_properties *properties, FILE_COUNT ref)
1023 {
1024  FILE_COUNT i;
1025
1026  for(i=0; i<entries->total; i++)
1027  {
1028   /* The refcount values are not compared, since these may vary */
1029   if(!far_memcmp(&l_search->dev, (void FAR *)&entries->list[i].dev, sizeof(dev_t))&&
1030      l_search->inode==entries->list[i].inode)
1031   {
1032    if(properties!=NULL)
1033    {
1034     properties->islink=1;
1035     properties->l_search.ref=entries->list[i].ref;
1036     properties->type=ARJT_UXSPECIAL;
1037     properties->fsize=0L;
1038    }
1039    return(i);
1040   }
1041  }
1042  if(entries->total>=entries->alloc)
1043  {
1044   entries->alloc+=L_ENTRIES_INCREMENT;
1045   entries->list=(struct l_search FAR *)farrealloc_msg(entries->list, entries->alloc*sizeof(struct l_search));
1046  }
1047  entries->list[i]=*l_search;
1048  entries->list[i].ref=ref;
1049  entries->total++;
1050  return(FLS_NONE);
1051 }
1052
1053 #endif