2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
6 * -date------ -name------------------- -description-----------------------------
7 * 02-jan-2008 [Tomasz Wiszkowski] added disk validation
8 * 04-jan-2008 [Tomasz Wiszkowski] corrected tabulation
17 #include "filehandles2.h"
18 #include "afsblocks.h"
20 #include "checksums.h"
22 #include "extstrings.h"
23 #include "filehandles1.h"
26 #include "baseredef.h"
27 #include "validator.h"
31 /********************************************
33 Descr.: set actual date for an object
35 blockbuffer - header block of object
37 Output: 0 for success; error code otherwise
38 *********************************************/
41 struct AFSBase
*afsbase
,
42 struct Volume
*volume
,
43 struct BlockCache
*blockbuffer
,
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
)
61 return writeHeader(afsbase
, volume
, blockbuffer
);
65 /********************************************
67 Descr.: set actual date for an object
68 Input : ah - filehandle name is relative to
71 Output: 0 for success; error code otherwise
72 *********************************************/
75 struct AFSBase
*afsbase
,
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
)
91 return setHeaderDate(afsbase
, ah
->volume
, blockbuffer
, ds
);
94 /********************************************
96 Descr.: set protection bits for an object
97 Input : ah - filehandle name is relative to
99 mask - protection bit mask
100 Output: 0 for success; error code otherwise
101 *********************************************/
104 struct AFSBase
*afsbase
,
105 struct AfsHandle
*ah
,
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
)
119 blockbuffer
->buffer
[BLK_PROTECT(ah
->volume
)] = OS_LONG2BE(mask
);
120 return writeHeader(afsbase
, ah
->volume
, blockbuffer
);
123 /********************************************
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 *********************************************/
132 (struct AFSBase
*afsbase
, struct AfsHandle
*ah
, STRPTR name
, STRPTR comment
)
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
)
148 (APTR
)((char *)blockbuffer
->buffer
+(BLK_COMMENT_START(ah
->volume
)*4)),
151 return writeHeader(afsbase
, ah
->volume
, blockbuffer
);
154 /************************************************
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
162 Note : unlink is only done in buffers
163 nothing is written to disk!
164 ************************************************/
167 struct AFSBase
*afsbase
,
168 struct Volume
*volume
,
169 struct BlockCache
*lastentry
,
170 struct BlockCache
*entry
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
)
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 /********************************************
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
) {
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
)
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 */
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);
253 (blockbuffer
->buffer
[BLK_SECONDARY_TYPE(ah
->volume
)]) == ST_FILE
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);
267 (afsbase
, ah
->volume
, OS_BE2LONG(blockbuffer
->buffer
[key
]), -1);
269 if (blockbuffer
->buffer
[BLK_EXTENSION(ah
->volume
)] == 0)
271 /* get next extensionblock */
272 blockbuffer
->flags
&= ~BCF_USED
;
273 blockbuffer
= getBlock
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
;
301 /********************************************
303 Descr.: links a new entry into a directorylist
304 Input : dir - directory to link in
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
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; */
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
);
330 (buffer
, volume
->SizeBlock
-56, volume
->dosflags
)+BLK_TABLE_START
;
331 /* sort in ascending order */
333 (dir
->buffer
[key
] != 0) &&
334 (OS_BE2LONG(dir
->buffer
[key
]) < file
->blocknum
))
336 dir
= getBlock(afsbase
, volume
, OS_BE2LONG(dir
->buffer
[key
]));
339 key
= BLK_HASHCHAIN(volume
);
341 (dir
->buffer
[key
] != 0) &&
342 (OS_BE2LONG(dir
->buffer
[key
]) < file
->blocknum
)
345 dir
= getBlock(afsbase
, volume
, OS_BE2LONG(dir
->buffer
[key
]));
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
));
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
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
,
387 end
= PathPart(name
);
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 */
395 return findBlock(afsbase
, ah
, buffer
, &block
);
398 /********************************************
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 *********************************************/
408 struct AFSBase
*afsbase
,
409 struct AfsHandle
*dirah
,
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
)
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
);
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! */
474 /* otherwise we use different blocks */
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
;
489 dirblock
->buffer
[BLK_SECONDARY_TYPE(dirah
->volume
)]
495 dirblock
->buffer
[BLK_SECONDARY_TYPE(dirah
->volume
)]
500 oldfile
->flags
&= ~BCF_USED
;
501 lastlink
->flags
&= ~BCF_USED
;
502 return ERROR_OBJECT_WRONG_TYPE
;
507 (APTR
)((char *)oldfile
->buffer
+(BLK_FILENAME_START(dirah
->volume
)*4)),
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);
553 /********************************************
554 Name : createNewEntry
555 Descr.: create a new object on disk
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
,
573 struct BlockCache
*dirblock
,
577 struct BlockCache
*newblock
;
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
;
590 if (!invalidBitmap(afsbase
, volume
))
592 dirblock
->flags
&= ~BCF_USED
;
595 i
= allocBlock(afsbase
, volume
);
598 dirblock
->flags
&= ~BCF_USED
;
599 validBitmap(afsbase
, volume
);
600 error
= ERROR_DISK_FULL
;
603 newblock
= getFreeCacheBlock(afsbase
, volume
, i
);
604 if (newblock
== NULL
)
606 dirblock
->flags
&= ~BCF_USED
;
607 validBitmap(afsbase
, volume
);
608 error
= ERROR_UNKNOWN
;
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
);
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
);
623 (APTR
)((char *)newblock
->buffer
+(BLK_FILENAME_START(volume
)*4)),
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
);
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
;
655 /********************************************
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
,
672 struct AfsHandle
*ah
= NULL
;
673 struct BlockCache
*dirblock
;
676 D(bug("[afs] createDir(ah,%s,%ld)\n", filename
, protection
));
677 if (0 == checkValid(afsbase
, dirah
->volume
))
679 error
= ERROR_DISK_WRITE_PROTECTED
;
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
);