alsa.audio: move handling of XRUN when writting to the slave task
[AROS.git] / tools / adflib / adf_cache.c
blobc375961db36c717e71f72bb8718f86952f52f05a
1 /*
2 * ADF Library. (C) 1997-1999 Laurent Clevy
4 * adf_cache.c
6 */
8 #include<stdlib.h>
9 #include<string.h>
11 #include"adf_defs.h"
12 #include"adf_str.h"
13 #include"adf_err.h"
14 #include"defendian.h"
15 #include"adf_cache.h"
16 #include"adf_raw.h"
17 #include"adf_disk.h"
18 #include"adf_bitm.h"
19 #include"adf_util.h"
20 #include"adf_dir.h"
23 extern struct Env adfEnv;
25 freeEntCache(struct CacheEntry *cEntry)
27 if (cEntry->name!=NULL)
28 free(cEntry->name);
29 if (cEntry->comm!=NULL)
30 free(cEntry->comm);
35 * adfGetDirEntCache
37 * replace 'adfGetDirEnt'. returns a the dir contents based on the dircache list
39 struct List* adfGetDirEntCache(struct Volume *vol, SECTNUM dir, BOOL recurs)
41 struct bEntryBlock parent;
42 struct bDirCacheBlock dirc;
43 int offset, n;
44 struct List *cell, *head;
45 struct CacheEntry caEntry;
46 struct Entry *entry;
47 SECTNUM nSect;
49 if (adfReadEntryBlock(vol,dir,&parent)!=RC_OK)
50 return NULL;
52 nSect = parent.extension;
54 cell = head = NULL;
55 do {
56 /* one loop per cache block */
57 n = offset = 0;
58 if (adfReadDirCBlock(vol, nSect, &dirc)!=RC_OK)
59 return NULL;
60 while (n<dirc.recordsNb) {
61 /* one loop per record */
62 entry = (struct Entry*)malloc(sizeof(struct Entry));
63 if (!entry) {
64 adfFreeDirList(head);
65 return NULL;
67 adfGetCacheEntry(&dirc, &offset, &caEntry);
69 /* converts a cache entry into a dir entry */
70 entry->type = (int)caEntry.type;
71 entry->name = strdup(caEntry.name);
72 if (entry->name==NULL) {
73 free(entry); adfFreeDirList(head);
74 return NULL;
76 entry->sector = caEntry.header;
77 entry->comment = strdup(caEntry.comm);
78 if (entry->comment==NULL) {
79 free(entry->name); adfFreeDirList(head);
80 return NULL;
82 entry->size = caEntry.size;
83 entry->access = caEntry.protect;
84 adfDays2Date( caEntry.days, &(entry->year), &(entry->month),
85 &(entry->days) );
86 entry->hour = caEntry.mins/60;
87 entry->mins = caEntry.mins%60;
88 entry->secs = caEntry.ticks/50;
90 /* add it into the linked list */
91 if (head==NULL)
92 head = cell = newCell(NULL, (void*)entry);
93 else
94 cell = newCell(cell, (void*)entry);
96 if (cell==NULL) {
97 adfFreeEntry(entry);
98 adfFreeDirList(head);
99 return NULL;
102 if (recurs && entry->type==ST_DIR)
103 cell->subdir = adfGetDirEntCache(vol,entry->sector,recurs);
105 n++;
107 nSect = dirc.nextDirC;
108 }while (nSect!=0);
110 return head;
116 * adfGetCacheEntry
118 * Returns a cache entry, starting from the offset p (the index into records[])
119 * This offset is updated to the end of the returned entry.
121 void adfGetCacheEntry(struct bDirCacheBlock *dirc, int *p, struct CacheEntry *cEntry)
123 int ptr;
125 ptr = *p;
127 //printf("p=%d\n",ptr);
129 #ifdef LITT_ENDIAN
130 cEntry->header = swapLong(dirc->records+ptr);
131 cEntry->size = swapLong(dirc->records+ptr+4);
132 cEntry->protect = swapLong(dirc->records+ptr+8);
133 cEntry->days = swapShort(dirc->records+ptr+16);
134 cEntry->mins = swapShort(dirc->records+ptr+18);
135 cEntry->ticks = swapShort(dirc->records+ptr+20);
136 #else
137 cEntry->header = Long(dirc->records+ptr);
138 cEntry->size = Long(dirc->records+ptr+4);
139 cEntry->protect = Long(dirc->records+ptr+8);
140 cEntry->days = Short(dirc->records+ptr+16);
141 cEntry->mins = Short(dirc->records+ptr+18);
142 cEntry->ticks = Short(dirc->records+ptr+20);
143 #endif
144 cEntry->type =(signed char) dirc->records[ptr+22];
146 cEntry->nLen = dirc->records[ptr+23];
147 /* cEntry->name = (char*)malloc(sizeof(char)*(cEntry->nLen+1));
148 if (!cEntry->name)
149 return;
150 */ memcpy(cEntry->name, dirc->records+ptr+24, cEntry->nLen);
151 cEntry->name[(int)(cEntry->nLen)]='\0';
153 cEntry->cLen = dirc->records[ptr+24+cEntry->nLen];
154 if (cEntry->cLen>0) {
155 /* cEntry->comm =(char*)malloc(sizeof(char)*(cEntry->cLen+1));
156 if (!cEntry->comm) {
157 free( cEntry->name ); cEntry->name=NULL;
158 return;
160 */ memcpy(cEntry->comm,dirc->records+ptr+24+cEntry->nLen+1,cEntry->cLen);
162 cEntry->comm[(int)(cEntry->cLen)]='\0';
163 //printf("cEntry->nLen %d cEntry->cLen %d %s\n",cEntry->nLen,cEntry->cLen,cEntry->name);
164 *p = ptr+24+cEntry->nLen+1+cEntry->cLen;
166 /* the starting offset of each record must be even (68000 constraint) */
167 if ((*p%2)!=0)
168 *p=(*p)+1;
173 * adfPutCacheEntry
175 * remplaces one cache entry at the p offset, and returns its length
177 int adfPutCacheEntry( struct bDirCacheBlock *dirc, int *p, struct CacheEntry *cEntry)
179 int ptr, l;
181 ptr = *p;
183 #ifdef LITT_ENDIAN
184 swLong(dirc->records+ptr, cEntry->header);
185 swLong(dirc->records+ptr+4, cEntry->size);
186 swLong(dirc->records+ptr+8, cEntry->protect);
187 swShort(dirc->records+ptr+16, cEntry->days);
188 swShort(dirc->records+ptr+18, cEntry->mins);
189 swShort(dirc->records+ptr+20, cEntry->ticks);
190 #else
191 memcpy(dirc->records+ptr,&(cEntry->header),4);
192 memcpy(dirc->records+ptr+4,&(cEntry->size),4);
193 memcpy(dirc->records+ptr+8,&(cEntry->protect),4);
194 memcpy(dirc->records+ptr+16,&(cEntry->days),2);
195 memcpy(dirc->records+ptr+18,&(cEntry->mins),2);
196 memcpy(dirc->records+ptr+20,&(cEntry->ticks),2);
197 #endif
198 dirc->records[ptr+22] =(signed char)cEntry->type;
200 dirc->records[ptr+23] = cEntry->nLen;
201 memcpy(dirc->records+ptr+24, cEntry->name, cEntry->nLen);
203 dirc->records[ptr+24+cEntry->nLen] = cEntry->cLen;
204 memcpy(dirc->records+ptr+24+cEntry->nLen+1, cEntry->comm, cEntry->cLen);
206 //puts("adfPutCacheEntry");
208 l = 25+cEntry->nLen+cEntry->cLen;
209 if ((l%2)==0)
210 return l;
211 else {
212 dirc->records[ptr+l] =(char)0;
213 return l+1;
216 /* ptr%2 must be == 0, if l%2==0, (ptr+l)%2==0 */
221 * adfEntry2CacheEntry
223 * converts one dir entry into a cache entry, and return its future length in records[]
225 int adfEntry2CacheEntry(struct bEntryBlock *entry, struct CacheEntry *newEntry)
227 int entryLen;
229 /* new entry */
230 newEntry->header = entry->headerKey;
231 if (entry->secType==ST_FILE)
232 newEntry->size = entry->byteSize;
233 else
234 newEntry->size = 0L;
235 newEntry->protect = entry->access;
236 newEntry->days = (short)entry->days;
237 newEntry->mins = (short)entry->mins;
238 newEntry->ticks = (short)entry->ticks;
239 newEntry->type = (signed char)entry->secType;
240 newEntry->nLen = entry->nameLen;
241 memcpy(newEntry->name, entry->name, newEntry->nLen);
242 newEntry->name[(int)(newEntry->nLen)] = '\0';
243 newEntry->cLen = entry->commLen;
244 if (newEntry->cLen>0)
245 memcpy(newEntry->comm, entry->comment, newEntry->cLen);
247 entryLen = 24+newEntry->nLen+1+newEntry->cLen;
249 /*printf("entry->name %d entry->comment %d\n",entry->nameLen,entry->commLen);
250 printf("newEntry->nLen %d newEntry->cLen %d\n",newEntry->nLen,newEntry->cLen);
251 */ if ((entryLen%2)==0)
252 return entryLen;
253 else
254 return entryLen+1;
259 * adfDelFromCache
261 * delete one cache entry from its block. don't do 'records garbage collecting'
263 RETCODE adfDelFromCache(struct Volume *vol, struct bEntryBlock *parent,
264 SECTNUM headerKey)
266 struct bDirCacheBlock dirc;
267 SECTNUM nSect, prevSect;
268 struct CacheEntry caEntry;
269 int offset, oldOffset, n;
270 BOOL found;
271 int entryLen;
272 int i;
273 RETCODE rc = RC_OK;
275 prevSect = -1;
276 nSect = parent->extension;
277 found = FALSE;
278 do {
279 adfReadDirCBlock(vol, nSect, &dirc);
280 offset = 0; n = 0;
281 while(n < dirc.recordsNb && !found) {
282 oldOffset = offset;
283 adfGetCacheEntry(&dirc, &offset, &caEntry);
284 found = (caEntry.header==headerKey);
285 if (found) {
286 entryLen = offset-oldOffset;
287 if (dirc.recordsNb>1 || prevSect==-1) {
288 if (n<dirc.recordsNb-1) {
289 /* not the last of the block : switch the following records */
290 for(i=oldOffset; i<(488-entryLen); i++)
291 dirc.records[i] = dirc.records[i+entryLen];
292 /* and clear the following bytes */
293 for(i=488-entryLen; i<488; i++)
294 dirc.records[i] = 0;
296 else {
297 /* the last record of this cache block */
298 for(i=oldOffset; i<offset; i++)
299 dirc.records[i] = 0;
301 dirc.recordsNb--;
302 if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK)
303 return -1;
305 else {
306 /* dirc.recordsNb ==1 or == 0 , prevSect!=-1 :
307 * the only record in this dirc block and a previous dirc block exists
309 adfSetBlockFree(vol, dirc.headerKey);
310 adfReadDirCBlock(vol, prevSect, &dirc);
311 dirc.nextDirC = 0L;
312 adfWriteDirCBlock(vol, prevSect, &dirc);
314 adfUpdateBitmap(vol);
317 n++;
319 prevSect = nSect;
320 nSect = dirc.nextDirC;
321 }while(nSect!=0 && !found);
323 if (!found)
324 (*adfEnv.wFct)("adfUpdateCache : entry not found");
326 return rc;
331 * adfAddInCache
334 RETCODE adfAddInCache(struct Volume *vol, struct bEntryBlock *parent,
335 struct bEntryBlock *entry)
337 struct bDirCacheBlock dirc, newDirc;
338 SECTNUM nSect, nCache;
339 struct CacheEntry caEntry, newEntry;
340 int offset, n;
341 int entryLen;
343 entryLen = adfEntry2CacheEntry(entry, &newEntry);
344 /*printf("adfAddInCache--%4ld %2d %6ld %8lx %4d %2d:%02d:%02d %30s %22s\n",
345 newEntry.header, newEntry.type, newEntry.size, newEntry.protect,
346 newEntry.days, newEntry.mins/60, newEntry.mins%60,
347 newEntry.ticks/50,
348 newEntry.name, newEntry.comm);
350 nSect = parent->extension;
351 do {
352 if (adfReadDirCBlock(vol, nSect, &dirc)!=RC_OK)
353 return RC_ERROR;
354 offset = 0; n = 0;
355 //printf("parent=%4ld\n",dirc.parent);
356 while(n < dirc.recordsNb) {
357 adfGetCacheEntry(&dirc, &offset, &caEntry);
358 /*printf("*%4ld %2d %6ld %8lx %4d %2d:%02d:%02d %30s %22s\n",
359 caEntry.header, caEntry.type, caEntry.size, caEntry.protect,
360 caEntry.days, caEntry.mins/60, caEntry.mins%60,
361 caEntry.ticks/50,
362 caEntry.name, caEntry.comm);
364 n++;
367 /* if (offset+entryLen<=488) {
368 adfPutCacheEntry(&dirc, &offset, &newEntry);
369 dirc.recordsNb++;
370 adfWriteDirCBlock(vol, dirc.headerKey, &dirc);
371 return rc;
373 nSect = dirc.nextDirC;
374 }while(nSect!=0);
376 /* in the last block */
377 if (offset+entryLen<=488) {
378 adfPutCacheEntry(&dirc, &offset, &newEntry);
379 dirc.recordsNb++;
380 //printf("entry name=%s\n",newEntry.name);
382 else {
383 /* request one new block free */
384 nCache = adfGet1FreeBlock(vol);
385 if (nCache==-1) {
386 (*adfEnv.wFct)("adfCreateDir : nCache==-1");
387 return RC_VOLFULL;
390 /* create a new dircache block */
391 memset(&newDirc,0,512);
392 if (parent->secType==ST_ROOT)
393 newDirc.parent = vol->rootBlock;
394 else if (parent->secType==ST_DIR)
395 newDirc.parent = parent->headerKey;
396 else
397 (*adfEnv.wFct)("adfAddInCache : unknown secType");
398 newDirc.recordsNb = 0L;
399 newDirc.nextDirC = 0L;
401 adfPutCacheEntry(&dirc, &offset, &newEntry);
402 newDirc.recordsNb++;
403 if (adfWriteDirCBlock(vol, nCache, &newDirc)!=RC_OK)
404 return RC_ERROR;
405 dirc.nextDirC = nCache;
407 //printf("dirc.headerKey=%ld\n",dirc.headerKey);
408 if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK)
409 return RC_ERROR;
410 /*if (strcmp(entry->name,"file_5u")==0)
411 dumpBlock(&dirc);
413 return RC_OK;
418 * adfUpdateCache
421 RETCODE adfUpdateCache(struct Volume *vol, struct bEntryBlock *parent,
422 struct bEntryBlock *entry, BOOL entryLenChg)
424 struct bDirCacheBlock dirc;
425 SECTNUM nSect;
426 struct CacheEntry caEntry, newEntry;
427 int offset, oldOffset, n;
428 BOOL found;
429 int i, oLen, nLen;
430 int sLen; /* shift length */
432 nLen = adfEntry2CacheEntry(entry, &newEntry);
434 nSect = parent->extension;
435 found = FALSE;
436 do {
437 //printf("dirc=%ld\n",nSect);
438 if (adfReadDirCBlock(vol, nSect, &dirc)!=RC_OK)
439 return RC_ERROR;
440 offset = 0; n = 0;
441 /* search entry to update with its header_key */
442 while(n < dirc.recordsNb && !found) {
443 oldOffset = offset;
444 /* offset is updated */
445 adfGetCacheEntry(&dirc, &offset, &caEntry);
446 oLen = offset-oldOffset;
447 sLen = oLen-nLen;
448 //printf("olen=%d nlen=%d\n",oLen,nLen);
449 found = (caEntry.header==newEntry.header);
450 if (found) {
451 if (!entryLenChg || oLen==nLen) {
452 /* same length : remplace the old values */
453 adfPutCacheEntry(&dirc, &oldOffset, &newEntry);
454 //if (entryLenChg) puts("oLen==nLen");
455 if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK)
456 return RC_ERROR;
458 else if (oLen>nLen) {
459 //puts("oLen>nLen");
460 /* the new record is shorter, write it,
461 * then shift down the following records
463 adfPutCacheEntry(&dirc, &oldOffset, &newEntry);
464 for(i=oldOffset+nLen; i<(488-sLen); i++)
465 dirc.records[i] = dirc.records[i+sLen];
466 /* then clear the following bytes */
467 for(i=488-sLen; i<488; i++)
468 dirc.records[i] = (char)0;
470 if (adfWriteDirCBlock(vol, dirc.headerKey, &dirc)!=RC_OK)
471 return RC_ERROR;
473 else {
474 /* the new record is larger */
475 //puts("oLen<nLen");
476 adfDelFromCache(vol,parent,entry->headerKey);
477 adfAddInCache(vol,parent,entry);
478 //puts("oLen<nLen end");
482 n++;
484 nSect = dirc.nextDirC;
485 }while(nSect!=0 && !found);
487 if (found) {
488 if (adfUpdateBitmap(vol)!=RC_OK)
489 return RC_ERROR;
491 else
492 (*adfEnv.wFct)("adfUpdateCache : entry not found");
494 return RC_OK;
499 * adfCreateEmptyCache
502 RETCODE adfCreateEmptyCache(struct Volume *vol, struct bEntryBlock *parent, SECTNUM nSect)
504 struct bDirCacheBlock dirc;
505 SECTNUM nCache;
507 if (nSect==-1) {
508 nCache = adfGet1FreeBlock(vol);
509 if (nCache==-1) {
510 (*adfEnv.wFct)("adfCreateDir : nCache==-1");
511 return RC_VOLFULL;
514 else
515 nCache = nSect;
517 if (parent->extension==0)
518 parent->extension = nCache;
520 memset(&dirc,0, sizeof(struct bDirCacheBlock));
522 if (parent->secType==ST_ROOT)
523 dirc.parent = vol->rootBlock;
524 else if (parent->secType==ST_DIR)
525 dirc.parent = parent->headerKey;
526 else {
527 (*adfEnv.wFct)("adfCreateEmptyCache : unknown secType");
528 //printf("secType=%ld\n",parent->secType);
531 dirc.recordsNb = 0;
532 dirc.nextDirC = 0;
534 if (adfWriteDirCBlock(vol, nCache, &dirc)!=RC_OK)
535 return RC_ERROR;
537 return RC_OK;
542 * adfReadDirCBlock
545 RETCODE adfReadDirCBlock(struct Volume *vol, SECTNUM nSect, struct bDirCacheBlock *dirc)
547 unsigned char buf[512];
549 if (adfReadBlock(vol, nSect, buf)!=RC_OK)
550 return RC_ERROR;
552 memcpy(dirc,buf,512);
553 #ifdef LITT_ENDIAN
554 swapEndian((unsigned char*)dirc,SWBL_CACHE);
555 #endif
556 if (dirc->checkSum!=adfNormalSum(buf,20,512))
557 (*adfEnv.wFct)("adfReadDirCBlock : invalid checksum");
558 if (dirc->type!=T_DIRC)
559 (*adfEnv.wFct)("adfReadDirCBlock : T_DIRC not found");
560 if (dirc->headerKey!=nSect)
561 (*adfEnv.wFct)("adfReadDirCBlock : headerKey!=nSect");
563 return RC_OK;
568 * adfWriteDirCblock
571 RETCODE adfWriteDirCBlock(struct Volume* vol, ULONG nSect, struct bDirCacheBlock* dirc)
573 unsigned char buf[LOGICAL_BLOCK_SIZE];
574 ULONG newSum;
576 dirc->type = T_DIRC;
577 dirc->headerKey = nSect;
579 memcpy(buf, dirc, LOGICAL_BLOCK_SIZE);
580 #ifdef LITT_ENDIAN
581 swapEndian(buf, SWBL_CACHE);
582 #endif
584 newSum = adfNormalSum(buf, 20, LOGICAL_BLOCK_SIZE);
585 swLong(buf+20,newSum);
586 // *(ULONG*)(buf+20) = swapLong((unsigned char*)&newSum);
588 if (adfWriteBlock(vol, nSect, buf)!=RC_OK)
589 return RC_ERROR;
590 //puts("adfWriteDirCBlock");
592 return RC_OK;
595 /*################################################################################*/