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
is_excluded(char * name)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
xms_malloc(unsigned long size,struct flist_root * root)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
xms_realloc(unsigned long size,struct flist_root * root)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
create_swapfile(struct flist_root * root)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
get_heap_block(unsigned int block,struct flist_root * root)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
save_heap_block(struct flist_root * root,char FAR * data)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
relocate_heap(struct flist_root * root)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
update_hcrc(struct flist_root * root,unsigned long crc)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
revert_hcrc(struct flist_root * root,unsigned long crc)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
checksum(char * str)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
find_d_match(struct flist_root * root,char * name)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
find_match(struct flist_root * root,char * name)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
cache_cleanup(struct flist_root * root)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
flist_cleanup_proc(struct flist_root * root)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
flist_cleanup_proc(struct flist_root * root)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
retrieve_entry(char * dest,struct file_properties * properties,struct flist_root * root,FILE_COUNT entry)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
retrieve_entry(char * dest,struct flist_root * root,FILE_COUNT num)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
add_entry(struct flist_root * root,char * name,FILE_COUNT * count,struct file_properties * properties)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
add_entry(struct flist_root * root,char * name,FILE_COUNT * count)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
flist_init_proc(struct flist_root * root,FILE_COUNT maxfiles,char type)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
link_search(struct l_entries * entries,struct l_search * l_search,struct file_properties * properties,FILE_COUNT ref)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
1054