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