added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / workbench / devs / afs / filehandles2.c
blobfad82ef0e074279e1bccfccb65d687851a1b7c42
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
4 */
5 /*
6 * -date------ -name------------------- -description-----------------------------
7 * 02-jan-2008 [Tomasz Wiszkowski] added disk validation
8 * 04-jan-2008 [Tomasz Wiszkowski] corrected tabulation
9 */
12 #ifndef DEBUG
13 #define DEBUG 0
14 #endif
16 #include "os.h"
17 #include "filehandles2.h"
18 #include "afsblocks.h"
19 #include "bitmap.h"
20 #include "checksums.h"
21 #include "error.h"
22 #include "extstrings.h"
23 #include "filehandles1.h"
24 #include "hashing.h"
25 #include "misc.h"
26 #include "baseredef.h"
27 #include "validator.h"
29 extern ULONG error;
31 /********************************************
32 Name : setHeaderDate
33 Descr.: set actual date for an object
34 Input : volume -
35 blockbuffer - header block of object
36 ds - datestamp to set
37 Output: 0 for success; error code otherwise
38 *********************************************/
39 ULONG setHeaderDate
41 struct AFSBase *afsbase,
42 struct Volume *volume,
43 struct BlockCache *blockbuffer,
44 struct DateStamp *ds
48 D(bug
50 "[afs] setHeaderDate: for headerblock %lu\n",
51 blockbuffer->blocknum)
53 blockbuffer->buffer[BLK_DAYS(volume)] = OS_LONG2BE(ds->ds_Days);
54 blockbuffer->buffer[BLK_MINS(volume)] = OS_LONG2BE(ds->ds_Minute);
55 blockbuffer->buffer[BLK_TICKS(volume)] = OS_LONG2BE(ds->ds_Tick);
56 writeBlockDeferred(afsbase, volume, blockbuffer, BLK_CHECKSUM);
57 blockbuffer = getBlock
58 (afsbase, volume, OS_BE2LONG(blockbuffer->buffer[BLK_PARENT(volume)]));
59 if (blockbuffer == NULL)
60 return ERROR_UNKNOWN;
61 return writeHeader(afsbase, volume, blockbuffer);
65 /********************************************
66 Name : setDate
67 Descr.: set actual date for an object
68 Input : ah - filehandle name is relative to
69 name - name of object
70 ds - datestamp to set
71 Output: 0 for success; error code otherwise
72 *********************************************/
73 ULONG setDate
75 struct AFSBase *afsbase,
76 struct AfsHandle *ah,
77 STRPTR name,
78 struct DateStamp *ds
81 ULONG block;
82 struct BlockCache *blockbuffer;
84 D(bug("[afs] setData()\n"));
85 if (0 == checkValid(afsbase, ah->volume))
86 return ERROR_DISK_WRITE_PROTECTED;
88 blockbuffer = findBlock(afsbase, ah, name, &block);
89 if (blockbuffer == NULL)
90 return error;
91 return setHeaderDate(afsbase, ah->volume, blockbuffer, ds);
94 /********************************************
95 Name : setProtect
96 Descr.: set protection bits for an object
97 Input : ah - filehandle name is relative to
98 name - name of object
99 mask - protection bit mask
100 Output: 0 for success; error code otherwise
101 *********************************************/
102 ULONG setProtect
104 struct AFSBase *afsbase,
105 struct AfsHandle *ah,
106 STRPTR name,
107 ULONG mask
110 ULONG block;
111 struct BlockCache *blockbuffer;
113 D(bug("[afs] setProtect(ah,%s,%ld)\n", name, mask));
114 if (0 == checkValid(afsbase, ah->volume))
115 return ERROR_DISK_WRITE_PROTECTED;
116 blockbuffer = findBlock(afsbase, ah, name, &block);
117 if (blockbuffer == NULL)
118 return error;
119 blockbuffer->buffer[BLK_PROTECT(ah->volume)] = OS_LONG2BE(mask);
120 return writeHeader(afsbase, ah->volume, blockbuffer);
123 /********************************************
124 Name : setComment
125 Descr.: set comment for an object
126 Input : ah - filehandle name is relative to
127 name - name of object
128 comment - comment to set
129 Output: 0 for success; error code otherwise
130 *********************************************/
131 ULONG setComment
132 (struct AFSBase *afsbase, struct AfsHandle *ah, STRPTR name, STRPTR comment)
134 ULONG block;
135 struct BlockCache *blockbuffer;
137 D(bug("[afs] setComment(ah,%s,%s)\n", name, comment));
138 if (0 == checkValid(afsbase, ah->volume))
139 return ERROR_DISK_WRITE_PROTECTED;
140 if (strlen(comment) >= MAXCOMMENTLENGTH)
141 return ERROR_COMMENT_TOO_BIG;
142 blockbuffer = findBlock(afsbase, ah, name, &block);
143 if (blockbuffer == NULL)
144 return error;
145 StrCpyToBstr
147 comment,
148 (APTR)((char *)blockbuffer->buffer+(BLK_COMMENT_START(ah->volume)*4)),
149 MAX_COMMENT_LENGTH
151 return writeHeader(afsbase, ah->volume, blockbuffer);
154 /************************************************
155 Name : unLinkBlock
156 Descr.: unlinks an entry from the directorylist
157 Input : lastentry - node before entry to unlink
158 (directory itself (head) or last block
159 which HASHCHAIN points to the entry to unlink
160 entry - entry to unlink
161 Output: -
162 Note : unlink is only done in buffers
163 nothing is written to disk!
164 ************************************************/
165 void unLinkBlock
167 struct AFSBase *afsbase,
168 struct Volume *volume,
169 struct BlockCache *lastentry,
170 struct BlockCache *entry
173 ULONG key;
175 D(bug("[afs] unlinkBlock: unlinking %lu\n", entry->blocknum));
176 /* find the "member" where entry is linked
177 ->linked into hashchain or hashtable */
178 key = BLK_HASHCHAIN(volume);
179 if (OS_BE2LONG(lastentry->buffer[key])!=entry->blocknum)
181 for (key = BLK_TABLE_START; key<=BLK_TABLE_END(volume); key++)
183 if (OS_BE2LONG(lastentry->buffer[key]) == entry->blocknum)
184 break;
187 /* unlink block */
188 lastentry->buffer[key] = entry->buffer[BLK_HASHCHAIN(volume)];
189 lastentry->buffer[BLK_CHECKSUM] = 0;
190 lastentry->buffer[BLK_CHECKSUM] =
191 OS_LONG2BE(0-calcChkSum(volume->SizeBlock, lastentry->buffer));
194 /********************************************
195 Name : deleteObject
196 Descr.: delete an object
197 Input : ah - filehandle name is relative to
198 name - name of object to delete
199 Output: 0 for success; error code otherwise
200 *********************************************/
201 ULONG deleteObject(struct AFSBase *afsbase, struct AfsHandle *ah, STRPTR name) {
202 ULONG lastblock,key;
203 struct BlockCache *blockbuffer, *priorbuffer;
205 D(bug("[afs] delete(ah,%s)\n", name));
207 * check disk validity *first*
208 * it may turn out, that during validation, invalid entry gets deleted either way.
210 if (0 == checkValid(afsbase, ah->volume))
211 return ERROR_DISK_WRITE_PROTECTED;
212 blockbuffer = findBlock(afsbase, ah, name, &lastblock);
213 if (blockbuffer == NULL)
214 return error;
215 blockbuffer = findBlock(afsbase, ah, name, &lastblock);
216 if (findHandle(ah->volume, blockbuffer->blocknum) != NULL)
217 return ERROR_OBJECT_IN_USE;
218 if (OS_BE2LONG(blockbuffer->buffer[BLK_PROTECT(ah->volume)]) & FIBF_DELETE)
219 return ERROR_DELETE_PROTECTED;
220 /* if we try to delete a directory, check if it is empty */
221 if (
222 OS_BE2LONG
223 (blockbuffer->buffer[BLK_SECONDARY_TYPE(ah->volume)]) == ST_USERDIR
226 for (key=BLK_TABLE_START; key<=BLK_TABLE_END(ah->volume); key++)
228 if (blockbuffer->buffer[key] != 0)
229 return ERROR_DIRECTORY_NOT_EMPTY;
232 blockbuffer->flags |= BCF_USED;
233 priorbuffer = getBlock(afsbase, ah->volume, lastblock);
234 if (priorbuffer == NULL)
236 blockbuffer->flags &= ~BCF_USED;
237 return ERROR_UNKNOWN;
239 if (calcChkSum(ah->volume->SizeBlock, priorbuffer->buffer) != 0)
241 blockbuffer->flags &= ~BCF_USED;
242 if (showError(afsbase, ERR_CHECKSUM, priorbuffer->blocknum))
243 launchValidator(afsbase, ah->volume);
244 return ERROR_UNKNOWN;
246 priorbuffer->flags |= BCF_USED;
247 unLinkBlock(afsbase, ah->volume, priorbuffer, blockbuffer);
248 invalidBitmap(afsbase, ah->volume);
249 writeBlock(afsbase, ah->volume, priorbuffer, -1);
250 markBlock(afsbase, ah->volume, blockbuffer->blocknum, -1);
251 if (
252 OS_BE2LONG
253 (blockbuffer->buffer[BLK_SECONDARY_TYPE(ah->volume)]) == ST_FILE
256 for (;;)
258 D(bug("[afs] extensionblock=%lu\n", blockbuffer->blocknum));
261 key = BLK_TABLE_END(ah->volume);
262 (key >= BLK_TABLE_START) && (blockbuffer->buffer[key]!=0);
263 key--
266 markBlock
267 (afsbase, ah->volume, OS_BE2LONG(blockbuffer->buffer[key]), -1);
269 if (blockbuffer->buffer[BLK_EXTENSION(ah->volume)] == 0)
270 break;
271 /* get next extensionblock */
272 blockbuffer->flags &= ~BCF_USED;
273 blockbuffer = getBlock
275 afsbase,
276 ah->volume,
277 OS_BE2LONG(blockbuffer->buffer[BLK_EXTENSION(ah->volume)])
279 if (blockbuffer == NULL)
281 priorbuffer->flags &= ~BCF_USED;
282 return ERROR_UNKNOWN;
284 if (calcChkSum(ah->volume->SizeBlock, blockbuffer->buffer))
286 priorbuffer->flags &= ~BCF_USED;
287 if (showError(afsbase, ERR_CHECKSUM))
288 launchValidator(afsbase, ah->volume);
289 return ERROR_UNKNOWN;
291 blockbuffer->flags |= BCF_USED;
292 markBlock(afsbase, ah->volume, blockbuffer->blocknum, -1);
295 validBitmap(afsbase, ah->volume);
296 blockbuffer->flags &= ~BCF_USED;
297 priorbuffer->flags &= ~BCF_USED;
298 return 0;
301 /********************************************
302 Name : linkNewBlock
303 Descr.: links a new entry into a directorylist
304 Input : dir - directory to link in
305 file - file to link
306 Output: the block which must be written to disk
307 -> if hashtable of directory changed it's the same
308 pointer as arg1; otherwise a HASHCHAIN pointer
309 changed so we don't have to write this block but
310 another one
311 NULL if error
312 *********************************************/
313 struct BlockCache *linkNewBlock
315 struct AFSBase *afsbase,
316 struct Volume *volume,
317 struct BlockCache *dir,
318 struct BlockCache *file
321 ULONG key; /* parent; */
322 UBYTE buffer[32];
323 STRPTR name;
325 file->buffer[BLK_PARENT(volume)] = OS_LONG2BE(dir->blocknum);
326 D(bug("[afs] linkNewBlock: linking block %ld\n", file->blocknum));
327 name = (STRPTR)((char *)file->buffer+(BLK_FILENAME_START(volume)*4));
328 StrCpyFromBstr(name, buffer);
329 key = getHashKey
330 (buffer, volume->SizeBlock-56, volume->dosflags)+BLK_TABLE_START;
331 /* sort in ascending order */
332 if (
333 (dir->buffer[key] != 0) &&
334 (OS_BE2LONG(dir->buffer[key]) < file->blocknum))
336 dir = getBlock(afsbase, volume, OS_BE2LONG(dir->buffer[key]));
337 if (dir == NULL)
338 return NULL;
339 key = BLK_HASHCHAIN(volume);
340 while (
341 (dir->buffer[key] != 0) &&
342 (OS_BE2LONG(dir->buffer[key]) < file->blocknum)
345 dir = getBlock(afsbase, volume, OS_BE2LONG(dir->buffer[key]));
346 if (dir == NULL)
347 return NULL;
350 file->buffer[BLK_HASHCHAIN(volume)] = dir->buffer[key];
351 dir->buffer[key] = OS_LONG2BE(file->blocknum);
352 file->buffer[BLK_CHECKSUM] = 0;
353 file->buffer[BLK_CHECKSUM] =
354 OS_LONG2BE(0-calcChkSum(volume->SizeBlock,file->buffer));
355 dir->buffer[BLK_CHECKSUM] = 0;
356 dir->buffer[BLK_CHECKSUM] =
357 OS_LONG2BE(0-calcChkSum(volume->SizeBlock,dir->buffer));
358 return dir;
361 /********************************************
362 Name : getDirBlockBuffer
363 Descr.: returns cacheblock of the block the
364 last component before "/" or ":" of
365 name refers to or cacheblock of ah
366 if there is no such component
367 Input : ah - filehandle name is relative to
368 name - name of object
369 entryname - will be filled with a copy
370 of the last component of
371 name
372 Output: NULL for error (global error will be set);
373 pointer to a struct BlockCache otherwise
374 *********************************************/
375 struct BlockCache *getDirBlockBuffer
377 struct AFSBase *afsbase,
378 struct AfsHandle *ah,
379 STRPTR name,
380 STRPTR entryname
383 ULONG block,len;
384 STRPTR end;
385 UBYTE buffer[256];
387 end = PathPart(name);
388 if (end[0] == '/')
389 end++;
390 CopyMem(name, buffer, end-name);
391 buffer[end-name] = 0;
392 len = strlen(name)+name-end;
393 CopyMem(end, entryname, len); /* skip backslash or colon */
394 entryname[len] = 0;
395 return findBlock(afsbase, ah, buffer, &block);
398 /********************************************
399 Name : renameObject
400 Descr.: rename an object
401 Input : dirah - filehandle names are relative to
402 oname - object to rename
403 newname - new name of the object
404 Output: 0 for success; error code otherwise
405 *********************************************/
406 ULONG renameObject
408 struct AFSBase *afsbase,
409 struct AfsHandle *dirah,
410 STRPTR oname,
411 STRPTR newname
414 struct BlockCache *lastlink,*oldfile, *dirblock;
415 ULONG block,dirblocknum,lastblock;
416 UBYTE newentryname[34];
418 D(bug("[afs] rename(%ld,%s,%s)\n", dirah->header_block, oname, newname));
419 if (0 == checkValid(afsbase, dirah->volume))
420 return ERROR_DISK_WRITE_PROTECTED;
421 dirblock = getDirBlockBuffer(afsbase, dirah, newname, newentryname);
422 if (dirblock == NULL)
423 return error;
424 dirblocknum = dirblock->blocknum;
425 D(bug("[afs] dir is on block %ld\n", dirblocknum));
426 if (getHeaderBlock(afsbase, dirah->volume, newentryname, dirblock, &block) != NULL)
428 dirblock->flags &= ~BCF_USED;
429 return ERROR_OBJECT_EXISTS;
431 oldfile = findBlock(afsbase, dirah, oname, &lastblock);
432 if (oldfile == NULL)
433 return error;
434 oldfile->flags |= BCF_USED;
435 /* do we move a directory? */
436 if (OS_BE2LONG(oldfile->buffer[BLK_SECONDARY_TYPE(dirah->volume)])==ST_USERDIR)
438 /* is newdirblock child of olock/oname */
439 dirblock = getBlock(afsbase, dirah->volume, dirblocknum);
440 if (dirblock == NULL)
442 oldfile->flags &= ~BCF_USED;
443 return ERROR_UNKNOWN;
445 while ((block = OS_BE2LONG(dirblock->buffer[BLK_PARENT(dirah->volume)])))
447 if (block == oldfile->blocknum)
449 oldfile->flags &= ~BCF_USED;
450 return ERROR_OBJECT_IN_USE;
452 dirblock = getBlock(afsbase, dirah->volume, block);
453 if (dirblock == NULL)
455 oldfile->flags &= ~BCF_USED;
456 return ERROR_UNKNOWN;
460 lastlink = getBlock(afsbase, dirah->volume, lastblock);
461 if (lastlink == NULL)
463 oldfile->flags &= ~BCF_USED;
464 return ERROR_UNKNOWN;
466 lastlink->flags |= BCF_USED;
467 unLinkBlock(afsbase, dirah->volume, lastlink, oldfile);
468 /* rename in same dir ? */
469 if (lastlink->blocknum == dirblocknum)
471 /* use same buffers! */
472 dirblock = lastlink;
474 /* otherwise we use different blocks */
475 else
477 dirblock = getBlock(afsbase, dirah->volume, dirblocknum);
478 if (dirblock == NULL)
480 oldfile->flags &= ~BCF_USED;
481 lastlink->flags &= ~BCF_USED;
482 return ERROR_UNKNOWN;
485 if (
487 OS_BE2LONG
489 dirblock->buffer[BLK_SECONDARY_TYPE(dirah->volume)]
490 ) != ST_USERDIR
491 ) &&
493 OS_BE2LONG
495 dirblock->buffer[BLK_SECONDARY_TYPE(dirah->volume)]
496 ) != ST_ROOT
500 oldfile->flags &= ~BCF_USED;
501 lastlink->flags &= ~BCF_USED;
502 return ERROR_OBJECT_WRONG_TYPE;
504 StrCpyToBstr
506 newentryname,
507 (APTR)((char *)oldfile->buffer+(BLK_FILENAME_START(dirah->volume)*4)),
508 MAX_NAME_LENGTH
510 dirblock = linkNewBlock(afsbase, dirah->volume, dirblock, oldfile);
511 if (dirblock == NULL)
513 oldfile->flags &= ~BCF_USED;
514 lastlink->flags &= ~BCF_USED;
515 return ERROR_UNKNOWN;
517 /* concurrent access if newdir=rootblock! */
518 dirblock->flags |= BCF_USED;
520 mark it as used, so that this buffer isn't
521 used in invalidating volume!
523 if (!setBitmapFlag(afsbase, dirah->volume, 0))
525 oldfile->flags &= ~BCF_USED;
526 lastlink->flags &= ~BCF_USED;
527 dirblock->flags &= ~BCF_USED;
528 return ERROR_UNKNOWN;
530 /* now we can release that buffer */
531 dirblock->flags &= ~BCF_USED;
533 syscrash after this: 2 dirs pointing to the same
534 dir and one wrong linked entry->recoverable
536 writeBlock(afsbase, dirah->volume, dirblock, -1);
538 syscrash after this: directory pointing is now
539 correct but one wrong linked entry->recoverable
541 writeBlock(afsbase, dirah->volume, lastlink, -1);
542 writeBlock(afsbase, dirah->volume, oldfile, -1);
543 oldfile->flags &= ~BCF_USED;
544 lastlink->flags &= ~BCF_USED;
546 if newdir=rootblock we now write the correct
547 (changed) buffer back
549 setBitmapFlag(afsbase, dirah->volume, -1);
550 return 0;
553 /********************************************
554 Name : createNewEntry
555 Descr.: create a new object on disk
556 Input : volume -
557 entrytype - ST_USERDIR/ST_FILE/...
558 entryname - name of object
559 dirblock - pointer to struct BlockCache
560 containing a directory in which
561 name shall be created in
562 protection - protection bit mask
563 Output: NULL for error (global error set);
564 pointer to struct BlockCache of the newly
565 created object otherwise
566 *********************************************/
567 struct BlockCache *createNewEntry
569 struct AFSBase *afsbase,
570 struct Volume *volume,
571 ULONG entrytype,
572 STRPTR entryname,
573 struct BlockCache *dirblock,
574 ULONG protection
577 struct BlockCache *newblock;
578 struct DateStamp ds;
579 ULONG i;
581 D(bug("[afs] createNewEntry(%ld, %s)\n", dirblock->blocknum, entryname));
582 dirblock->flags |= BCF_USED;
583 if (getHeaderBlock(afsbase, volume, entryname, dirblock, &i) != NULL)
585 dirblock->flags &= ~BCF_USED;
586 error = ERROR_OBJECT_EXISTS;
587 return NULL;
589 error = 0;
590 if (!invalidBitmap(afsbase, volume))
592 dirblock->flags &= ~BCF_USED;
593 return NULL;
595 i = allocBlock(afsbase, volume);
596 if (i == 0)
598 dirblock->flags &= ~BCF_USED;
599 validBitmap(afsbase, volume);
600 error = ERROR_DISK_FULL;
601 return NULL;
603 newblock = getFreeCacheBlock(afsbase, volume, i);
604 if (newblock == NULL)
606 dirblock->flags &= ~BCF_USED;
607 validBitmap(afsbase, volume);
608 error = ERROR_UNKNOWN;
609 return NULL;
611 newblock->flags |= BCF_USED;
612 newblock->buffer[BLK_PRIMARY_TYPE] = OS_LONG2BE(T_SHORT);
613 for (i=BLK_BLOCK_COUNT; i<=BLK_COMMENT_END(volume); i++)
614 newblock->buffer[i] = 0;
615 newblock->buffer[BLK_PROTECT(volume)] = OS_LONG2BE(protection);
616 DateStamp(&ds);
617 newblock->buffer[BLK_DAYS(volume)] = OS_LONG2BE(ds.ds_Days);
618 newblock->buffer[BLK_MINS(volume)] = OS_LONG2BE(ds.ds_Minute);
619 newblock->buffer[BLK_TICKS(volume)] = OS_LONG2BE(ds.ds_Tick);
620 StrCpyToBstr
622 entryname,
623 (APTR)((char *)newblock->buffer+(BLK_FILENAME_START(volume)*4)),
624 MAX_NAME_LENGTH
626 for (i=BLK_FILENAME_END(volume)+1; i<BLK_HASHCHAIN(volume); i++)
627 newblock->buffer[i] = 0;
628 newblock->buffer[BLK_PARENT(volume)] = OS_LONG2BE(dirblock->blocknum);
629 newblock->buffer[BLK_EXTENSION(volume)] = 0;
630 newblock->buffer[BLK_SECONDARY_TYPE(volume)] = OS_LONG2BE(entrytype);
631 newblock->buffer[BLK_OWN_KEY] = OS_LONG2BE(newblock->blocknum);
632 dirblock->flags &= ~BCF_USED;
633 dirblock = linkNewBlock(afsbase, volume, dirblock, newblock);
634 if (dirblock == NULL)
636 markBlock(afsbase, volume, newblock->blocknum, -1);
637 newblock->flags &= ~BCF_USED;
638 newblock->newness = 0;
639 validBitmap(afsbase, volume);
640 return NULL;
643 if crash after this block not yet linked->block
644 not written to disk, bitmap corrected
646 writeBlock(afsbase, volume, newblock, -1);
647 /* consistent after this */
648 writeBlock(afsbase, volume, dirblock, -1);
649 validBitmap(afsbase, volume);
650 newblock->flags &= ~BCF_USED;
651 return newblock;
655 /********************************************
656 Name : createDir
657 Descr.: create a directory object
658 Input : dirah - filehandle filename is relative to
659 filename - path to the new directory
660 protection - protection bit mask
661 Output: pointer to struct AfsHandle;
662 NULL otherwise (global error set)
663 *********************************************/
664 struct AfsHandle *createDir
666 struct AFSBase *afsbase,
667 struct AfsHandle *dirah,
668 STRPTR filename,
669 ULONG protection
672 struct AfsHandle *ah = NULL;
673 struct BlockCache *dirblock;
674 char dirname[34];
676 D(bug("[afs] createDir(ah,%s,%ld)\n", filename, protection));
677 if (0 == checkValid(afsbase, dirah->volume))
679 error = ERROR_DISK_WRITE_PROTECTED;
680 return NULL;
682 dirblock = getDirBlockBuffer(afsbase, dirah, filename, dirname);
683 if (dirblock != NULL)
685 D(bug("[afs] dir is on block %ld\n", dirblock->blocknum));
686 dirblock = createNewEntry
687 (afsbase, dirah->volume, ST_USERDIR, dirname, dirblock, protection);
688 if (dirblock != NULL)
689 ah = getHandle(afsbase, dirah->volume, dirblock, FMF_READ);
691 return ah;