1 /*
2  *  ADF Library. (C) 1997-2002 Laurent Clevy
3  *
4  *  adf_dir.c
5  *
6  *  $Id$
7  *
8  *  directory code
9  *
10  *  This file is part of ADFLib.
11  *
12  *  ADFLib is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  ADFLib is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with Foobar; if not, write to the Free Software
24  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
25  *
26  */
27 
28 #include<stdlib.h>
29 #include<string.h>
30 #include<ctype.h>
31 
32 #include"adf_dir.h"
33 #include"adf_str.h"
34 #include"adf_util.h"
35 #include"defendian.h"
36 #include"adf_blk.h"
37 #include"adf_raw.h"
38 #include"adf_disk.h"
39 #include"adf_bitm.h"
40 #include"adf_file.h"
41 #include"adf_err.h"
42 #include"adf_cache.h"
43 
44 extern struct Env adfEnv;
45 
46 
47 /*
48  * adfRenameEntry
49  *
50  */
adfRenameEntry(struct Volume * vol,SECTNUM pSect,char * oldName,SECTNUM nPSect,char * newName)51 RETCODE adfRenameEntry(struct Volume *vol, SECTNUM pSect, char *oldName,
52 	SECTNUM nPSect, char *newName)
53 {
54     struct bEntryBlock parent, previous, entry, nParent;
55     SECTNUM nSect2, nSect, prevSect, tmpSect;
56     int hashValueO, hashValueN, len;
57     char name2[MAXNAMELEN+1], name3[MAXNAMELEN+1];
58 	BOOL intl;
59     RETCODE rc;
60 
61     if (strcmp(oldName,newName)==0)
62         return RC_OK;
63 
64     intl = isINTL(vol->dosType) || isDIRCACHE(vol->dosType);
65     len = strlen(newName);
66     myToUpper((uint8_t*)name2, (uint8_t*)newName, len, intl);
67     myToUpper((uint8_t*)name3, (uint8_t*)oldName, strlen(oldName), intl);
68     /* newName == oldName ? */
69 
70     if (adfReadEntryBlock( vol, pSect, &parent )!=RC_OK)
71 		return RC_ERROR;
72 
73     hashValueO = adfGetHashValue((uint8_t*)oldName, intl);
74 
75     nSect = adfNameToEntryBlk(vol, parent.hashTable, oldName, &entry, &prevSect);
76     if (nSect==-1) {
77         (*adfEnv.wFct)("adfRenameEntry : existing entry not found");
78         return RC_ERROR;
79     }
80 
81     /* change name and parent dir */
82     entry.nameLen = min(31, strlen(newName));
83     memcpy(entry.name, newName, entry.nameLen);
84     entry.parent = nPSect;
85     tmpSect = entry.nextSameHash;
86 
87     entry.nextSameHash = 0;
88     if (adfWriteEntryBlock(vol, nSect, &entry)!=RC_OK)
89 		return RC_ERROR;
90 
91     /* del from the oldname list */
92 
93     /* in hashTable */
94     if (prevSect==0) {
95         parent.hashTable[hashValueO] = tmpSect;
96         if (parent.secType==ST_ROOT)
97             rc = adfWriteRootBlock(vol, pSect, (struct bRootBlock*)&parent);
98         else
99             rc = adfWriteDirBlock(vol, pSect, (struct bDirBlock*)&parent);
100         if (rc!=RC_OK)
101             return rc;
102     }
103     else {
104         /* in linked list */
105 	    if (adfReadEntryBlock(vol, prevSect, &previous)!=RC_OK)
106             return RC_ERROR;
107         /* entry.nextSameHash (tmpSect) could be == 0 */
108         previous.nextSameHash = tmpSect;
109         if (adfWriteEntryBlock(vol, prevSect, &previous)!=RC_OK)
110             return RC_ERROR;
111     }
112 
113 
114     if (adfReadEntryBlock( vol, nPSect, &nParent )!=RC_OK)
115 		return RC_ERROR;
116 
117     hashValueN = adfGetHashValue((uint8_t*)newName, intl);
118     nSect2 = nParent.hashTable[ hashValueN ];
119     /* no list */
120     if (nSect2==0) {
121         nParent.hashTable[ hashValueN ] = nSect;
122         if (nParent.secType==ST_ROOT)
123             rc = adfWriteRootBlock(vol, nPSect, (struct bRootBlock*)&nParent);
124         else
125             rc = adfWriteDirBlock(vol, nPSect, (struct bDirBlock*)&nParent);
126     }
127     else {
128         /* a list exists : addition at the end */
129         /* len = strlen(newName);
130                    * name2 == newName
131                    */
132         do {
133             if (adfReadEntryBlock(vol, nSect2, &previous)!=RC_OK)
134                 return -1;
135             if (previous.nameLen==len) {
136                 myToUpper((uint8_t*)name3,(uint8_t*)previous.name,previous.nameLen,intl);
137                 if (strncmp(name3,name2,len)==0) {
138                     (*adfEnv.wFct)("adfRenameEntry : entry already exists");
139                     return -1;
140                 }
141             }
142             nSect2 = previous.nextSameHash;
143 /*printf("sect=%ld\n",nSect2);*/
144         }while(nSect2!=0);
145 
146         previous.nextSameHash = nSect;
147         if (previous.secType==ST_DIR)
148             rc=adfWriteDirBlock(vol, previous.headerKey,
149 			       (struct bDirBlock*)&previous);
150         else if (previous.secType==ST_FILE)
151             rc=adfWriteFileHdrBlock(vol, previous.headerKey,
152                    (struct bFileHeaderBlock*)&previous);
153         else {
154             (*adfEnv.wFct)("adfRenameEntry : unknown entry type");
155             rc = RC_ERROR;
156         }
157 
158 	}
159     if (rc!=RC_OK)
160         return rc;
161 
162     if (isDIRCACHE(vol->dosType)) {
163 		if (pSect==nPSect) {
164             adfUpdateCache(vol, &parent, (struct bEntryBlock*)&entry,TRUE);
165         }
166         else {
167             adfDelFromCache(vol,&parent,entry.headerKey);
168             adfAddInCache(vol,&nParent,&entry);
169         }
170     }
171 /*
172     if (isDIRCACHE(vol->dosType) && pSect!=nPSect) {
173         adfUpdateCache(vol, &nParent, (struct bEntryBlock*)&entry,TRUE);
174     }
175 */
176     return RC_OK;
177 }
178 
179 /*
180  * adfRemoveEntry
181  *
182  */
adfRemoveEntry(struct Volume * vol,SECTNUM pSect,char * name)183 RETCODE adfRemoveEntry(struct Volume *vol, SECTNUM pSect, char *name)
184 {
185     struct bEntryBlock parent, previous, entry;
186     SECTNUM nSect2, nSect;
187     int hashVal;
188     BOOL intl;
189     char buf[200];
190 
191     if (adfReadEntryBlock( vol, pSect, &parent )!=RC_OK)
192 		return RC_ERROR;
193     nSect = adfNameToEntryBlk(vol, parent.hashTable, name, &entry, &nSect2);
194     if (nSect==-1) {
195       sprintf(buf, "adfRemoveEntry : entry '%s' not found", name);
196         (*adfEnv.wFct)(buf);
197         return RC_ERROR;
198     }
199     /* if it is a directory, is it empty ? */
200     if ( entry.secType==ST_DIR && !isDirEmpty((struct bDirBlock*)&entry) ) {
201       sprintf(buf, "adfRemoveEntry : directory '%s' not empty", name);
202         (*adfEnv.wFct)(buf);
203         return RC_ERROR;
204     }
205 /*    printf("name=%s  nSect2=%ld\n",name, nSect2);*/
206 
207     /* in parent hashTable */
208     if (nSect2==0) {
209         intl = isINTL(vol->dosType) || isDIRCACHE(vol->dosType);
210         hashVal = adfGetHashValue( (uint8_t*)name, intl );
211 /*printf("hashTable=%d nexthash=%d\n",parent.hashTable[hashVal],
212  entry.nextSameHash);*/
213         parent.hashTable[hashVal] = entry.nextSameHash;
214         if (adfWriteEntryBlock(vol, pSect, &parent)!=RC_OK)
215 			return RC_ERROR;
216     }
217     /* in linked list */
218     else {
219         if (adfReadEntryBlock(vol, nSect2, &previous)!=RC_OK)
220 			return RC_ERROR;
221         previous.nextSameHash = entry.nextSameHash;
222         if (adfWriteEntryBlock(vol, nSect2, &previous)!=RC_OK)
223 			return RC_ERROR;
224     }
225 
226     if (entry.secType==ST_FILE) {
227         adfFreeFileBlocks(vol, (struct bFileHeaderBlock*)&entry);
228         if (adfEnv.useNotify)
229              (*adfEnv.notifyFct)(pSect,ST_FILE);
230     }
231     else if (entry.secType==ST_DIR) {
232         adfSetBlockFree(vol, nSect);
233         /* free dir cache block : the directory must be empty, so there's only one cache block */
234         if (isDIRCACHE(vol->dosType))
235             adfSetBlockFree(vol, entry.extension);
236         if (adfEnv.useNotify)
237             (*adfEnv.notifyFct)(pSect,ST_DIR);
238     }
239     else {
240       sprintf(buf, "adfRemoveEntry : secType %d not supported", entry.secType);
241         (*adfEnv.wFct)(buf);
242         return RC_ERROR;
243     }
244 
245     if (isDIRCACHE(vol->dosType))
246         adfDelFromCache(vol, &parent, entry.headerKey);
247 
248     adfUpdateBitmap(vol);
249 
250     return RC_OK;
251 }
252 
253 
254 /*
255  * adfSetEntryComment
256  *
257  */
adfSetEntryComment(struct Volume * vol,SECTNUM parSect,char * name,char * newCmt)258 RETCODE adfSetEntryComment(struct Volume* vol, SECTNUM parSect, char* name,
259     char* newCmt)
260 {
261     struct bEntryBlock parent, entry;
262     SECTNUM nSect;
263 
264     if (adfReadEntryBlock( vol, parSect, &parent )!=RC_OK)
265 		return RC_ERROR;
266     nSect = adfNameToEntryBlk(vol, parent.hashTable, name, &entry, NULL);
267     if (nSect==-1) {
268         (*adfEnv.wFct)("adfSetEntryComment : entry not found");
269         return RC_ERROR;
270     }
271 
272     entry.commLen = min(MAXCMMTLEN, strlen(newCmt));
273     memcpy(entry.comment, newCmt, entry.commLen);
274 
275     if (entry.secType==ST_DIR)
276         adfWriteDirBlock(vol, nSect, (struct bDirBlock*)&entry);
277     else if (entry.secType==ST_FILE)
278         adfWriteFileHdrBlock(vol, nSect, (struct bFileHeaderBlock*)&entry);
279     else
280         (*adfEnv.wFct)("adfSetEntryComment : entry secType incorrect");
281 
282     if (isDIRCACHE(vol->dosType))
283         adfUpdateCache(vol, &parent, (struct bEntryBlock*)&entry, TRUE);
284 
285     return RC_OK;
286 }
287 
288 
289 /*
290  * adfSetEntryAccess
291  *
292  */
adfSetEntryAccess(struct Volume * vol,SECTNUM parSect,char * name,int32_t newAcc)293 RETCODE adfSetEntryAccess(struct Volume* vol, SECTNUM parSect, char* name,
294     int32_t newAcc)
295 {
296     struct bEntryBlock parent, entry;
297     SECTNUM nSect;
298 
299     if (adfReadEntryBlock( vol, parSect, &parent )!=RC_OK)
300 		return RC_ERROR;
301     nSect = adfNameToEntryBlk(vol, parent.hashTable, name, &entry, NULL);
302     if (nSect==-1) {
303         (*adfEnv.wFct)("adfSetEntryAccess : entry not found");
304         return RC_ERROR;
305     }
306 
307     entry.access = newAcc;
308     if (entry.secType==ST_DIR)
309         adfWriteDirBlock(vol, nSect, (struct bDirBlock*)&entry);
310     else if (entry.secType==ST_FILE)
311         adfWriteFileHdrBlock(vol, nSect, (struct bFileHeaderBlock*)&entry);
312     else
313         (*adfEnv.wFct)("adfSetEntryAccess : entry secType incorrect");
314 
315     if (isDIRCACHE(vol->dosType))
316         adfUpdateCache(vol, &parent, (struct bEntryBlock*)&entry, FALSE);
317 
318     return RC_OK;
319 }
320 
321 
322 /*
323  * isDirEmpty
324  *
325  */
isDirEmpty(struct bDirBlock * dir)326 BOOL isDirEmpty(struct bDirBlock *dir)
327 {
328     int i;
329 
330     for(i=0; i<HT_SIZE; i++)
331         if (dir->hashTable[i]!=0)
332            return FALSE;
333 
334     return TRUE;
335 }
336 
337 
338 /*
339  * adfFreeDirList
340  *
341  */
adfFreeDirList(struct List * list)342 void adfFreeDirList(struct List* list)
343 {
344     struct List *root, *cell;
345 
346     root = cell = list;
347     while(cell!=NULL) {
348         adfFreeEntry(cell->content);
349         if (cell->subdir!=NULL)
350             adfFreeDirList(cell->subdir);
351         cell = cell->next;
352     }
353     freeList(root);
354 }
355 
356 
357 /*
358  * adfGetRDirEnt
359  *
360  */
adfGetRDirEnt(struct Volume * vol,SECTNUM nSect,BOOL recurs)361 struct List* adfGetRDirEnt(struct Volume* vol, SECTNUM nSect, BOOL recurs )
362 {
363     struct bEntryBlock entryBlk;
364 	struct List *cell, *head;
365     int i;
366     struct Entry *entry;
367     SECTNUM nextSector;
368     int32_t *hashTable;
369     struct bEntryBlock parent;
370 
371 
372     if (adfEnv.useDirCache && isDIRCACHE(vol->dosType))
373         return (adfGetDirEntCache(vol, nSect, recurs ));
374 
375 
376     if (adfReadEntryBlock(vol,nSect,&parent)!=RC_OK)
377 		return NULL;
378 
379     hashTable = parent.hashTable;
380     cell = head = NULL;
381     for(i=0; i<HT_SIZE; i++) {
382         if (hashTable[i]!=0) {
383              entry = (struct Entry *)malloc(sizeof(struct Entry));
384              if (!entry) {
385                  adfFreeDirList(head);
386 				 (*adfEnv.eFct)("adfGetDirEnt : malloc");
387                  return NULL;
388              }
389              if (adfReadEntryBlock(vol, hashTable[i], &entryBlk)!=RC_OK) {
390 				 adfFreeDirList(head);
391                  return NULL;
392              }
393              if (adfEntBlock2Entry(&entryBlk, entry)!=RC_OK) {
394 				 adfFreeDirList(head); return NULL;
395              }
396              entry->sector = hashTable[i];
397 
398              if (head==NULL)
399                  head = cell = newCell(0, (void*)entry);
400              else
401                  cell = newCell(cell, (void*)entry);
402              if (cell==NULL) {
403                  adfFreeDirList(head); return NULL;
404              }
405 
406              if (recurs && entry->type==ST_DIR)
407                  cell->subdir = adfGetRDirEnt(vol,entry->sector,recurs);
408 
409              /* same hashcode linked list */
410              nextSector = entryBlk.nextSameHash;
411              while( nextSector!=0 ) {
412                  entry = (struct Entry *)malloc(sizeof(struct Entry));
413                  if (!entry) {
414                      adfFreeDirList(head);
415 					 (*adfEnv.eFct)("adfGetDirEnt : malloc");
416                      return NULL;
417                  }
418                  if (adfReadEntryBlock(vol, nextSector, &entryBlk)!=RC_OK) {
419 					 adfFreeDirList(head); return NULL;
420                  }
421 
422                  if (adfEntBlock2Entry(&entryBlk, entry)!=RC_OK) {
423 					 adfFreeDirList(head);
424                      return NULL;
425                  }
426                  entry->sector = nextSector;
427 
428                  cell = newCell(cell, (void*)entry);
429                  if (cell==NULL) {
430                      adfFreeDirList(head); return NULL;
431                  }
432 
433                  if (recurs && entry->type==ST_DIR)
434                      cell->subdir = adfGetRDirEnt(vol,entry->sector,recurs);
435 
436                  nextSector = entryBlk.nextSameHash;
437              }
438         }
439     }
440 
441 /*    if (parent.extension && isDIRCACHE(vol->dosType) )
442         adfReadDirCache(vol,parent.extension);
443 */
444     return head;
445 }
446 
447 
448 /*
449  * adfGetDirEnt
450  *
451  */
adfGetDirEnt(struct Volume * vol,SECTNUM nSect)452 struct List* adfGetDirEnt(struct Volume* vol, SECTNUM nSect )
453 {
454     return adfGetRDirEnt(vol, nSect, FALSE);
455 }
456 
457 
458 /*
459  * adfFreeEntry
460  *
461  */
adfFreeEntry(struct Entry * entry)462 void adfFreeEntry(struct Entry *entry)
463 {
464 	if (entry==NULL)
465        return;
466     if (entry->name)
467         free(entry->name);
468     if (entry->comment)
469         free(entry->comment);
470     free(entry);
471 }
472 
473 
474 /*
475  * adfToRootDir
476  *
477  */
adfToRootDir(struct Volume * vol)478 RETCODE adfToRootDir(struct Volume *vol)
479 {
480     vol->curDirPtr = vol->rootBlock;
481 
482     return RC_OK;
483 }
484 
485 
486 /*
487  * adfChangeDir
488  *
489  */
adfChangeDir(struct Volume * vol,char * name)490 RETCODE adfChangeDir(struct Volume* vol, char *name)
491 {
492     struct bEntryBlock entry;
493     SECTNUM nSect;
494 
495     if (adfReadEntryBlock( vol, vol->curDirPtr, &entry )!=RC_OK)
496 		return RC_ERROR;
497     nSect = adfNameToEntryBlk(vol, entry.hashTable, name, &entry, NULL);
498 /*printf("adfChangeDir=%d\n",nSect);*/
499     if (nSect!=-1) {
500         vol->curDirPtr = nSect;
501 /*        if (*adfEnv.useNotify)
502             (*adfEnv.notifyFct)(0,ST_ROOT);*/
503         return RC_OK;
504     }
505     else
506 		return RC_ERROR;
507 }
508 
509 
510 /*
511  * adfParentDir
512  *
513  */
adfParentDir(struct Volume * vol)514 SECTNUM adfParentDir(struct Volume* vol)
515 {
516     struct bEntryBlock entry;
517 
518     if (vol->curDirPtr!=vol->rootBlock) {
519         if (adfReadEntryBlock( vol, vol->curDirPtr, &entry )!=RC_OK)
520 			return RC_ERROR;
521         vol->curDirPtr = entry.parent;
522     }
523     return RC_OK;
524 }
525 
526 
527 /*
528  * adfEntBlock2Entry
529  *
530  */
adfEntBlock2Entry(struct bEntryBlock * entryBlk,struct Entry * entry)531 RETCODE adfEntBlock2Entry(struct bEntryBlock *entryBlk, struct Entry *entry)
532 {
533     char buf[MAXCMMTLEN+1];
534     int len;
535 
536 	entry->type = entryBlk->secType;
537     entry->parent = entryBlk->parent;
538 
539     len = min(entryBlk->nameLen, MAXNAMELEN);
540     strncpy(buf, entryBlk->name, len);
541     buf[len] = '\0';
542     entry->name = strdup(buf);
543     if (entry->name==NULL)
544         return RC_MALLOC;
545 /*printf("len=%d name=%s parent=%ld\n",entryBlk->nameLen, entry->name,entry->parent );*/
546     adfDays2Date( entryBlk->days, &(entry->year), &(entry->month), &(entry->days));
547 	entry->hour = entryBlk->mins/60;
548     entry->mins = entryBlk->mins%60;
549     entry->secs = entryBlk->ticks/50;
550 
551     entry->access = -1;
552     entry->size = 0L;
553     entry->comment = NULL;
554     entry->real = 0L;
555     switch(entryBlk->secType) {
556     case ST_ROOT:
557         break;
558     case ST_DIR:
559         entry->access = entryBlk->access;
560         len = min(entryBlk->commLen, MAXCMMTLEN);
561         strncpy(buf, entryBlk->comment, len);
562         buf[len] = '\0';
563         entry->comment = strdup(buf);
564         if (entry->comment==NULL) {
565             free(entry->name);
566             return RC_MALLOC;
567         }
568         break;
569     case ST_FILE:
570         entry->access = entryBlk->access;
571         entry->size = entryBlk->byteSize;
572         len = min(entryBlk->commLen, MAXCMMTLEN);
573         strncpy(buf, entryBlk->comment, len);
574         buf[len] = '\0';
575         entry->comment = strdup(buf);
576         if (entry->comment==NULL) {
577             free(entry->name);
578             return RC_MALLOC;
579         }
580         break;
581     case ST_LFILE:
582     case ST_LDIR:
583         entry->real = entryBlk->realEntry;
584     case ST_LSOFT:
585         break;
586     default:
587         (*adfEnv.wFct)("unknown entry type");
588     }
589 
590     return RC_OK;
591 }
592 
593 
594 /*
595  * adfNameToEntryBlk
596  *
597  */
adfNameToEntryBlk(struct Volume * vol,int32_t ht[],char * name,struct bEntryBlock * entry,SECTNUM * nUpdSect)598 SECTNUM adfNameToEntryBlk(struct Volume *vol, int32_t ht[], char* name,
599     struct bEntryBlock *entry, SECTNUM *nUpdSect)
600 {
601     int hashVal;
602     uint8_t upperName[MAXNAMELEN+1];
603     uint8_t upperName2[MAXNAMELEN+1];
604     SECTNUM nSect;
605     int nameLen;
606     BOOL found;
607     SECTNUM updSect;
608     BOOL intl;
609 
610     intl = isINTL(vol->dosType) || isDIRCACHE(vol->dosType);
611     hashVal = adfGetHashValue( (uint8_t*)name, intl );
612     nameLen = min(strlen(name), MAXNAMELEN);
613     myToUpper( upperName, (uint8_t*)name, nameLen, intl );
614 
615     nSect = ht[hashVal];
616 /*printf("name=%s ht[%d]=%d upper=%s len=%d\n",name,hashVal,nSect,upperName,nameLen);
617 printf("hashVal=%d\n",adfGetHashValue(upperName, intl ));
618 if (!strcmp("espa�a.country",name)) {
619 int i;
620 for(i=0; i<HT_SIZE; i++) printf("ht[%d]=%d    ",i,ht[i]);
621 }*/
622     if (nSect==0)
623         return -1;
624 
625     updSect = 0;
626     found = FALSE;
627     do {
628         if (adfReadEntryBlock(vol, nSect, entry)!=RC_OK)
629 			return -1;
630         if (nameLen==entry->nameLen) {
631             myToUpper( upperName2, (uint8_t*)entry->name, nameLen, intl );
632 /*printf("2=%s %s\n",upperName2,upperName);*/
633             found = strncmp((char*)upperName, (char*)upperName2, nameLen)==0;
634         }
635         if (!found) {
636             updSect = nSect;
637             nSect = entry->nextSameHash;
638         }
639     }while( !found && nSect!=0 );
640 
641     if ( nSect==0 && !found )
642         return -1;
643     else {
644         if (nUpdSect!=NULL)
645             *nUpdSect = updSect;
646         return nSect;
647     }
648 }
649 
650 
651 /*
652  * Access2String
653  *
654  */
655     char*
adfAccess2String(int32_t acc)656 adfAccess2String(int32_t acc)
657 {
658     static char ret[8+1];
659 
660     strcpy(ret,"----rwed");
661     if (hasD(acc)) ret[7]='-';
662     if (hasE(acc)) ret[6]='-';
663     if (hasW(acc)) ret[5]='-';
664     if (hasR(acc)) ret[4]='-';
665     if (hasA(acc)) ret[3]='a';
666     if (hasP(acc)) ret[2]='p';
667     if (hasS(acc)) ret[1]='s';
668     if (hasH(acc)) ret[0]='h';
669 
670     return(ret);
671 }
672 
673 
674 /*
675  * adfCreateEntry
676  *
677  * if 'thisSect'==-1, allocate a sector, and insert its pointer into the hashTable of 'dir', using the
678  * name 'name'. if 'thisSect'!=-1, insert this sector pointer  into the hashTable
679  * (here 'thisSect' must be allocated before in the bitmap).
680  */
adfCreateEntry(struct Volume * vol,struct bEntryBlock * dir,char * name,SECTNUM thisSect)681 SECTNUM adfCreateEntry(struct Volume *vol, struct bEntryBlock *dir, char *name,
682     SECTNUM thisSect )
683 {
684     BOOL intl;
685     struct bEntryBlock updEntry;
686     int len, hashValue;
687     RETCODE rc;
688     char name2[MAXNAMELEN+1], name3[MAXNAMELEN+1];
689     SECTNUM nSect, newSect, newSect2;
690     struct bRootBlock* root;
691 
692 /*puts("adfCreateEntry in");*/
693 
694     intl = isINTL(vol->dosType) || isDIRCACHE(vol->dosType);
695     len = min(strlen(name), MAXNAMELEN) ;
696     myToUpper((uint8_t*)name2, (uint8_t*)name, len, intl);
697     hashValue = adfGetHashValue((uint8_t*)name, intl);
698     nSect = dir->hashTable[ hashValue ];
699 
700     if ( nSect==0 ) {
701         if (thisSect!=-1)
702             newSect = thisSect;
703         else {
704             newSect = adfGet1FreeBlock(vol);
705             if (newSect==-1) {
706                (*adfEnv.wFct)("adfCreateEntry : nSect==-1");
707                return -1;
708             }
709         }
710 
711         dir->hashTable[ hashValue ] = newSect;
712         if (dir->secType==ST_ROOT) {
713             root = (struct bRootBlock*)dir;
714             adfTime2AmigaTime(adfGiveCurrentTime(),
715                 &(root->cDays),&(root->cMins),&(root->cTicks));
716             rc=adfWriteRootBlock(vol, vol->rootBlock, root);
717         }
718         else {
719             adfTime2AmigaTime(adfGiveCurrentTime(),&(dir->days),&(dir->mins),&(dir->ticks));
720             rc=adfWriteDirBlock(vol, dir->headerKey, (struct bDirBlock*)dir);
721         }
722 /*puts("adfCreateEntry out, dir");*/
723         if (rc!=RC_OK) {
724             adfSetBlockFree(vol, newSect);
725             return -1;
726         }
727         else
728             return( newSect );
729     }
730 
731     do {
732         if (adfReadEntryBlock(vol, nSect, &updEntry)!=RC_OK)
733 			return -1;
734         if (updEntry.nameLen==len) {
735             myToUpper((uint8_t*)name3,(uint8_t*)updEntry.name,updEntry.nameLen,intl);
736             if (strncmp(name3,name2,len)==0) {
737                 (*adfEnv.wFct)("adfCreateEntry : entry already exists");
738                 return -1;
739             }
740         }
741         nSect = updEntry.nextSameHash;
742     }while(nSect!=0);
743 
744     if (thisSect!=-1)
745         newSect2 = thisSect;
746     else {
747         newSect2 = adfGet1FreeBlock(vol);
748         if (newSect2==-1) {
749             (*adfEnv.wFct)("adfCreateEntry : nSect==-1");
750             return -1;
751         }
752     }
753 
754     rc = RC_OK;
755     updEntry.nextSameHash = newSect2;
756     if (updEntry.secType==ST_DIR)
757         rc=adfWriteDirBlock(vol, updEntry.headerKey, (struct bDirBlock*)&updEntry);
758     else if (updEntry.secType==ST_FILE)
759         rc=adfWriteFileHdrBlock(vol, updEntry.headerKey,
760 		    (struct bFileHeaderBlock*)&updEntry);
761     else
762         (*adfEnv.wFct)("adfCreateEntry : unknown entry type");
763 
764 /*puts("adfCreateEntry out, hash");*/
765     if (rc!=RC_OK) {
766         adfSetBlockFree(vol, newSect2);
767         return -1;
768     }
769     else
770         return(newSect2);
771 }
772 
773 
774 
775 
776 /*
777  * adfIntlToUpper
778  *
779  */
780     uint8_t
adfIntlToUpper(uint8_t c)781 adfIntlToUpper(uint8_t c)
782 {
783 return (c>='a' && c<='z') || (c>=224 && c<=254 && c!=247) ? c - ('a'-'A') : c ;
784 }
785 
786     uint8_t
adfToUpper(uint8_t c)787 adfToUpper(uint8_t c)
788 {
789 return (c>='a' && c<='z') ? c - ('a'-'A') : c ;
790 }
791 
792 /*
793  * myToUpper
794  *
795  */
796     void
myToUpper(uint8_t * nstr,uint8_t * ostr,int nlen,BOOL intl)797 myToUpper( uint8_t *nstr, uint8_t *ostr, int nlen, BOOL intl )
798 {
799     int i;
800 
801     if (intl)
802         for(i=0; i<nlen; i++)
803             nstr[i]=adfIntlToUpper(ostr[i]);
804     else
805         for(i=0; i<nlen; i++)
806             nstr[i]=adfToUpper(ostr[i]);
807     nstr[nlen]='\0';
808 }
809 
810 
811 /*
812  * adfGetHashValue
813  *
814  */
815     int
adfGetHashValue(uint8_t * name,BOOL intl)816 adfGetHashValue(uint8_t *name, BOOL intl)
817 {
818     uint32_t hash, len;
819     unsigned int i;
820     uint8_t upper;
821 
822     len = hash = strlen((char*)name);
823     for(i=0; i<len; i++) {
824         if (intl)
825             upper = adfIntlToUpper(name[i]);
826         else
827             upper = toupper(name[i]);
828         hash = (hash * 13 + upper) & 0x7ff;
829     }
830     hash = hash % HT_SIZE;
831 
832     return(hash);
833 }
834 
835 
836 /*
837  * printEntry
838  *
839  */
printEntry(struct Entry * entry)840 void printEntry(struct Entry* entry)
841 {
842     printf("%-30s %2d %6d ", entry->name, entry->type, entry->sector);
843     printf("%2d/%02d/%04d %2d:%02d:%02d",entry->days, entry->month, entry->year,
844         entry->hour, entry->mins, entry->secs);
845     if (entry->type==ST_FILE)
846         printf("%8d ",entry->size);
847     else
848         printf("         ");
849     if (entry->type==ST_FILE || entry->type==ST_DIR)
850         printf("%-s ",adfAccess2String(entry->access));
851     if (entry->comment!=NULL)
852         printf("%s ",entry->comment);
853     putchar('\n');
854 }
855 
856 
857 /*
858  * adfCreateDir
859  *
860  */
adfCreateDir(struct Volume * vol,SECTNUM nParent,char * name)861 RETCODE adfCreateDir(struct Volume* vol, SECTNUM nParent, char* name)
862 {
863     SECTNUM nSect;
864     struct bDirBlock dir;
865     struct bEntryBlock parent;
866 
867     if (adfReadEntryBlock(vol, nParent, &parent)!=RC_OK)
868 		return RC_ERROR;
869 
870     /* -1 : do not use a specific, already allocated sector */
871     nSect = adfCreateEntry(vol, &parent, name, -1);
872     if (nSect==-1) {
873         (*adfEnv.wFct)("adfCreateDir : no sector available");
874         return RC_ERROR;
875     }
876     memset(&dir, 0, sizeof(struct bDirBlock));
877     dir.nameLen = min(MAXNAMELEN, strlen(name));
878     memcpy(dir.dirName,name,dir.nameLen);
879     dir.headerKey = nSect;
880 
881     if (parent.secType==ST_ROOT)
882         dir.parent = vol->rootBlock;
883     else
884         dir.parent = parent.headerKey;
885     adfTime2AmigaTime(adfGiveCurrentTime(),&(dir.days),&(dir.mins),&(dir.ticks));
886 
887     if (isDIRCACHE(vol->dosType)) {
888         /* for adfCreateEmptyCache, will be added by adfWriteDirBlock */
889         dir.secType = ST_DIR;
890         adfAddInCache(vol, &parent, (struct bEntryBlock *)&dir);
891         adfCreateEmptyCache(vol, (struct bEntryBlock *)&dir, -1);
892     }
893 
894     /* writes the dirblock, with the possible dircache assiocated */
895     if (adfWriteDirBlock(vol, nSect, &dir)!=RC_OK)
896 		return RC_ERROR;
897 
898     adfUpdateBitmap(vol);
899 
900     if (adfEnv.useNotify)
901         (*adfEnv.notifyFct)(nParent,ST_DIR);
902 
903     return RC_OK;
904 }
905 
906 
907 /*
908  * adfCreateFile
909  *
910  */
adfCreateFile(struct Volume * vol,SECTNUM nParent,char * name,struct bFileHeaderBlock * fhdr)911 RETCODE adfCreateFile(struct Volume* vol, SECTNUM nParent, char *name,
912     struct bFileHeaderBlock *fhdr)
913 {
914     SECTNUM nSect;
915     struct bEntryBlock parent;
916 /*puts("adfCreateFile in");*/
917     if (adfReadEntryBlock(vol, nParent, &parent)!=RC_OK)
918 		return RC_ERROR;
919 
920     /* -1 : do not use a specific, already allocated sector */
921     nSect = adfCreateEntry(vol, &parent, name, -1);
922     if (nSect==-1) return RC_ERROR;
923 /*printf("new fhdr=%d\n",nSect);*/
924     memset(fhdr,0,512);
925     fhdr->nameLen = min(MAXNAMELEN, strlen(name));
926     memcpy(fhdr->fileName,name,fhdr->nameLen);
927     fhdr->headerKey = nSect;
928     if (parent.secType==ST_ROOT)
929         fhdr->parent = vol->rootBlock;
930     else if (parent.secType==ST_DIR)
931         fhdr->parent = parent.headerKey;
932     else
933         (*adfEnv.wFct)("adfCreateFile : unknown parent secType");
934     adfTime2AmigaTime(adfGiveCurrentTime(),
935         &(fhdr->days),&(fhdr->mins),&(fhdr->ticks));
936 
937     if (adfWriteFileHdrBlock(vol,nSect,fhdr)!=RC_OK)
938 		return RC_ERROR;
939 
940     if (isDIRCACHE(vol->dosType))
941         adfAddInCache(vol, &parent, (struct bEntryBlock *)fhdr);
942 
943     adfUpdateBitmap(vol);
944 
945     if (adfEnv.useNotify)
946         (*adfEnv.notifyFct)(nParent,ST_FILE);
947 
948     return RC_OK;
949 }
950 
951 
952 /*
953  * adfReadEntryBlock
954  *
955  */
adfReadEntryBlock(struct Volume * vol,SECTNUM nSect,struct bEntryBlock * ent)956 RETCODE adfReadEntryBlock(struct Volume* vol, SECTNUM nSect, struct bEntryBlock *ent)
957 {
958     uint8_t buf[512];
959 
960     if (adfReadBlock(vol, nSect, buf)!=RC_OK)
961         return RC_ERROR;
962 
963     memcpy(ent, buf, 512);
964 #ifdef LITT_ENDIAN
965     swapEndian((uint8_t*)ent, SWBL_ENTRY);
966 #endif
967 /*printf("readentry=%d\n",nSect);*/
968     if (ent->checkSum!=adfNormalSum((uint8_t*)buf,20,512)) {
969         (*adfEnv.wFct)("adfReadEntryBlock : invalid checksum");
970         return RC_ERROR;
971     }
972     if (ent->type!=T_HEADER) {
973         (*adfEnv.wFct)("adfReadEntryBlock : T_HEADER id not found");
974         return RC_ERROR;
975     }
976     if (ent->nameLen<0 || ent->nameLen>MAXNAMELEN || ent->commLen>MAXCMMTLEN) {
977         (*adfEnv.wFct)("adfReadEntryBlock : nameLen or commLen incorrect");
978         printf("nameLen=%d, commLen=%d, name=%s sector%d\n",
979             ent->nameLen,ent->commLen,ent->name, ent->headerKey);
980     }
981 
982     return RC_OK;
983 }
984 
985 
986 /*
987  * adfWriteEntryBlock
988  *
989  */
adfWriteEntryBlock(struct Volume * vol,SECTNUM nSect,struct bEntryBlock * ent)990 RETCODE adfWriteEntryBlock(struct Volume* vol, SECTNUM nSect, struct bEntryBlock *ent)
991 {
992     uint8_t buf[512];
993     uint32_t newSum;
994 
995 
996     memcpy(buf, ent, sizeof(struct bEntryBlock));
997 
998 #ifdef LITT_ENDIAN
999     swapEndian(buf, SWBL_ENTRY);
1000 #endif
1001     newSum = adfNormalSum(buf,20,sizeof(struct bEntryBlock));
1002     swLong(buf+20, newSum);
1003 
1004     if (adfWriteBlock(vol, nSect, buf)!=RC_OK)
1005 		return RC_ERROR;
1006 
1007     return RC_OK;
1008 }
1009 
1010 
1011 /*
1012  * adfWriteDirBlock
1013  *
1014  */
adfWriteDirBlock(struct Volume * vol,SECTNUM nSect,struct bDirBlock * dir)1015 RETCODE adfWriteDirBlock(struct Volume* vol, SECTNUM nSect, struct bDirBlock *dir)
1016 {
1017     uint8_t buf[512];
1018     uint32_t newSum;
1019 
1020 
1021 /*printf("wdirblk=%d\n",nSect);*/
1022     dir->type = T_HEADER;
1023     dir->highSeq = 0;
1024     dir->hashTableSize = 0;
1025     dir->secType = ST_DIR;
1026 
1027     memcpy(buf, dir, sizeof(struct bDirBlock));
1028 #ifdef LITT_ENDIAN
1029     swapEndian(buf, SWBL_DIR);
1030 #endif
1031     newSum = adfNormalSum(buf,20,sizeof(struct bDirBlock));
1032     swLong(buf+20, newSum);
1033 
1034     if (adfWriteBlock(vol, nSect, buf)!=RC_OK)
1035 		return RC_ERROR;
1036 
1037     return RC_OK;
1038 }
1039 
1040 
1041 
1042 /*###########################################################################*/
1043