2 Copyright © 1995-2010, 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"
29 /********************************************
31 Descr.: set actual date for an object
33 blockbuffer - header block of object
35 Output: 0 for success; error code otherwise
36 *********************************************/
39 struct AFSBase
*afsbase
,
40 struct Volume
*volume
,
41 struct BlockCache
*blockbuffer
,
48 "[afs] setHeaderDate: for headerblock %lu\n",
49 blockbuffer
->blocknum
)
51 blockbuffer
->buffer
[BLK_DAYS(volume
)] = OS_LONG2BE(ds
->ds_Days
);
52 blockbuffer
->buffer
[BLK_MINS(volume
)] = OS_LONG2BE(ds
->ds_Minute
);
53 blockbuffer
->buffer
[BLK_TICKS(volume
)] = OS_LONG2BE(ds
->ds_Tick
);
54 writeBlockDeferred(afsbase
, volume
, blockbuffer
, BLK_CHECKSUM
);
55 blockbuffer
= getBlock
56 (afsbase
, volume
, OS_BE2LONG(blockbuffer
->buffer
[BLK_PARENT(volume
)]));
57 if (blockbuffer
== NULL
)
59 return writeHeader(afsbase
, volume
, blockbuffer
);
63 /********************************************
65 Descr.: set actual date for an object
66 Input : ah - filehandle name is relative to
69 Output: 0 for success; error code otherwise
70 *********************************************/
73 struct AFSBase
*afsbase
,
80 struct BlockCache
*blockbuffer
;
83 D(bug("[afs] setData()\n"));
84 if (0 == checkValid(afsbase
, ah
->volume
))
85 return ERROR_DISK_WRITE_PROTECTED
;
87 blockbuffer
= findBlock(afsbase
, ah
, name
, &block
, &error
);
88 if (blockbuffer
== NULL
)
90 return setHeaderDate(afsbase
, ah
->volume
, blockbuffer
, ds
);
93 /********************************************
95 Descr.: set protection bits for an object
96 Input : ah - filehandle name is relative to
98 mask - protection bit mask
99 Output: 0 for success; error code otherwise
100 *********************************************/
103 struct AFSBase
*afsbase
,
104 struct AfsHandle
*ah
,
110 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
, &error
);
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
, CONST_STRPTR name
,
133 CONST_STRPTR comment
)
136 struct BlockCache
*blockbuffer
;
139 D(bug("[afs] setComment(ah,%s,%s)\n", name
, comment
));
140 if (0 == checkValid(afsbase
, ah
->volume
))
141 return ERROR_DISK_WRITE_PROTECTED
;
142 if (strlen(comment
) >= MAXCOMMENTLENGTH
)
143 return ERROR_COMMENT_TOO_BIG
;
144 blockbuffer
= findBlock(afsbase
, ah
, name
, &block
, &error
);
145 if (blockbuffer
== NULL
)
150 (APTR
)((char *)blockbuffer
->buffer
+(BLK_COMMENT_START(ah
->volume
)*4)),
153 return writeHeader(afsbase
, ah
->volume
, blockbuffer
);
156 /************************************************
158 Descr.: unlinks an entry from the directorylist
159 Input : lastentry - node before entry to unlink
160 (directory itself (head) or last block
161 which HASHCHAIN points to the entry to unlink
162 entry - entry to unlink
164 Note : unlink is only done in buffers
165 nothing is written to disk!
166 ************************************************/
169 struct AFSBase
*afsbase
,
170 struct Volume
*volume
,
171 struct BlockCache
*lastentry
,
172 struct BlockCache
*entry
177 D(bug("[afs] unlinkBlock: unlinking %lu\n", entry
->blocknum
));
178 /* find the "member" where entry is linked
179 ->linked into hashchain or hashtable */
180 key
= BLK_HASHCHAIN(volume
);
181 if (OS_BE2LONG(lastentry
->buffer
[key
])!=entry
->blocknum
)
183 for (key
= BLK_TABLE_START
; key
<=BLK_TABLE_END(volume
); key
++)
185 if (OS_BE2LONG(lastentry
->buffer
[key
]) == entry
->blocknum
)
190 lastentry
->buffer
[key
] = entry
->buffer
[BLK_HASHCHAIN(volume
)];
191 lastentry
->buffer
[BLK_CHECKSUM
] = 0;
192 lastentry
->buffer
[BLK_CHECKSUM
] =
193 OS_LONG2BE(0-calcChkSum(volume
->SizeBlock
, lastentry
->buffer
));
196 /********************************************
198 Descr.: delete an object
199 Input : ah - filehandle name is relative to
200 name - name of object to delete
201 Output: 0 for success; error code otherwise
202 *********************************************/
203 ULONG
deleteObject(struct AFSBase
*afsbase
, struct AfsHandle
*ah
,
207 struct BlockCache
*blockbuffer
, *priorbuffer
;
210 D(bug("[afs] delete(ah,%s)\n", name
));
212 * check disk validity *first*
213 * it may turn out, that during validation, invalid entry gets deleted either way.
215 if (0 == checkValid(afsbase
, ah
->volume
))
216 return ERROR_DISK_WRITE_PROTECTED
;
217 blockbuffer
= findBlock(afsbase
, ah
, name
, &lastblock
, &error
);
218 if (blockbuffer
== NULL
)
220 blockbuffer
= findBlock(afsbase
, ah
, name
, &lastblock
, &error
);
221 if (findHandle(ah
->volume
, blockbuffer
->blocknum
) != NULL
)
222 return ERROR_OBJECT_IN_USE
;
223 if (OS_BE2LONG(blockbuffer
->buffer
[BLK_PROTECT(ah
->volume
)]) & FIBF_DELETE
)
224 return ERROR_DELETE_PROTECTED
;
225 /* if we try to delete a directory, check if it is empty */
228 (blockbuffer
->buffer
[BLK_SECONDARY_TYPE(ah
->volume
)]) == ST_USERDIR
231 for (key
=BLK_TABLE_START
; key
<=BLK_TABLE_END(ah
->volume
); key
++)
233 if (blockbuffer
->buffer
[key
] != 0)
234 return ERROR_DIRECTORY_NOT_EMPTY
;
237 blockbuffer
->flags
|= BCF_USED
;
238 priorbuffer
= getBlock(afsbase
, ah
->volume
, lastblock
);
239 if (priorbuffer
== NULL
)
241 blockbuffer
->flags
&= ~BCF_USED
;
242 return ERROR_UNKNOWN
;
244 if (calcChkSum(ah
->volume
->SizeBlock
, priorbuffer
->buffer
) != 0)
246 blockbuffer
->flags
&= ~BCF_USED
;
247 if (showError(afsbase
, ERR_CHECKSUM
, priorbuffer
->blocknum
))
248 launchValidator(afsbase
, ah
->volume
);
249 return ERROR_UNKNOWN
;
251 priorbuffer
->flags
|= BCF_USED
;
252 unLinkBlock(afsbase
, ah
->volume
, priorbuffer
, blockbuffer
);
253 invalidBitmap(afsbase
, ah
->volume
);
254 writeBlock(afsbase
, ah
->volume
, priorbuffer
, -1);
255 markBlock(afsbase
, ah
->volume
, blockbuffer
->blocknum
, -1);
258 (blockbuffer
->buffer
[BLK_SECONDARY_TYPE(ah
->volume
)]) == ST_FILE
263 D(bug("[afs] extensionblock=%lu\n", blockbuffer
->blocknum
));
266 key
= BLK_TABLE_END(ah
->volume
);
267 (key
>= BLK_TABLE_START
) && (blockbuffer
->buffer
[key
]!=0);
272 (afsbase
, ah
->volume
, OS_BE2LONG(blockbuffer
->buffer
[key
]), -1);
274 if (blockbuffer
->buffer
[BLK_EXTENSION(ah
->volume
)] == 0)
276 /* get next extensionblock */
277 blockbuffer
->flags
&= ~BCF_USED
;
278 blockbuffer
= getBlock
282 OS_BE2LONG(blockbuffer
->buffer
[BLK_EXTENSION(ah
->volume
)])
284 if (blockbuffer
== NULL
)
286 priorbuffer
->flags
&= ~BCF_USED
;
287 return ERROR_UNKNOWN
;
289 if (calcChkSum(ah
->volume
->SizeBlock
, blockbuffer
->buffer
))
291 priorbuffer
->flags
&= ~BCF_USED
;
292 if (showError(afsbase
, ERR_CHECKSUM
))
293 launchValidator(afsbase
, ah
->volume
);
294 return ERROR_UNKNOWN
;
296 blockbuffer
->flags
|= BCF_USED
;
297 markBlock(afsbase
, ah
->volume
, blockbuffer
->blocknum
, -1);
300 validBitmap(afsbase
, ah
->volume
);
301 blockbuffer
->flags
&= ~BCF_USED
;
302 priorbuffer
->flags
&= ~BCF_USED
;
306 /********************************************
307 Name : deleteFileRemainder
308 Descr.: delete all data blocks in a file after the current position
309 Input : ah - filehandle to delete from
310 Output: 0 for success; error code otherwise
311 *********************************************/
312 ULONG
deleteFileRemainder(struct AFSBase
*afsbase
, struct AfsHandle
*ah
)
315 struct BlockCache
*blockbuffer
;
317 invalidBitmap(afsbase
, ah
->volume
);
319 blockbuffer
= getBlock(afsbase
, ah
->volume
, ah
->current
.block
);
320 blockbuffer
->flags
|= BCF_USED
;
322 /* Start with the first block that will be wholly unused afterwards */
323 key
= ah
->current
.filekey
;
324 if (ah
->current
.byte
!= 0)
329 D(bug("[afs] extensionblock=%lu\n", blockbuffer
->blocknum
));
330 while (key
>= BLK_TABLE_START
&& blockbuffer
->buffer
[key
] != 0)
332 markBlock(afsbase
, ah
->volume
,
333 OS_BE2LONG(blockbuffer
->buffer
[key
]), -1);
336 if (blockbuffer
->buffer
[BLK_EXTENSION(ah
->volume
)] == 0)
338 /* get next extensionblock */
339 blockbuffer
->flags
&= ~BCF_USED
;
340 blockbuffer
= getBlock
344 OS_BE2LONG(blockbuffer
->buffer
[BLK_EXTENSION(ah
->volume
)])
346 if (blockbuffer
== NULL
)
348 return ERROR_UNKNOWN
;
350 if (calcChkSum(ah
->volume
->SizeBlock
, blockbuffer
->buffer
))
352 if (showError(afsbase
, ERR_CHECKSUM
))
353 launchValidator(afsbase
, ah
->volume
);
354 return ERROR_UNKNOWN
;
356 blockbuffer
->flags
|= BCF_USED
;
357 markBlock(afsbase
, ah
->volume
, blockbuffer
->blocknum
, -1);
358 key
= BLK_TABLE_END(ah
->volume
);
361 validBitmap(afsbase
, ah
->volume
);
362 blockbuffer
->flags
&= ~BCF_USED
;
366 /********************************************
368 Descr.: links a new entry into a directorylist
369 Input : dir - directory to link in
371 Output: the block which must be written to disk
372 -> if hashtable of directory changed it's the same
373 pointer as arg1; otherwise a HASHCHAIN pointer
374 changed so we don't have to write this block but
377 *********************************************/
378 struct BlockCache
*linkNewBlock
380 struct AFSBase
*afsbase
,
381 struct Volume
*volume
,
382 struct BlockCache
*dir
,
383 struct BlockCache
*file
386 ULONG key
; /* parent; */
390 file
->buffer
[BLK_PARENT(volume
)] = OS_LONG2BE(dir
->blocknum
);
391 D(bug("[afs] linkNewBlock: linking block %ld\n", file
->blocknum
));
392 name
= (STRPTR
)((char *)file
->buffer
+(BLK_FILENAME_START(volume
)*4));
393 StrCpyFromBstr(name
, buffer
);
395 (buffer
, volume
->SizeBlock
-56, volume
->dosflags
)+BLK_TABLE_START
;
396 /* sort in ascending order */
398 (dir
->buffer
[key
] != 0) &&
399 (OS_BE2LONG(dir
->buffer
[key
]) < file
->blocknum
))
401 dir
= getBlock(afsbase
, volume
, OS_BE2LONG(dir
->buffer
[key
]));
404 key
= BLK_HASHCHAIN(volume
);
406 (dir
->buffer
[key
] != 0) &&
407 (OS_BE2LONG(dir
->buffer
[key
]) < file
->blocknum
)
410 dir
= getBlock(afsbase
, volume
, OS_BE2LONG(dir
->buffer
[key
]));
415 file
->buffer
[BLK_HASHCHAIN(volume
)] = dir
->buffer
[key
];
416 dir
->buffer
[key
] = OS_LONG2BE(file
->blocknum
);
417 file
->buffer
[BLK_CHECKSUM
] = 0;
418 file
->buffer
[BLK_CHECKSUM
] =
419 OS_LONG2BE(0-calcChkSum(volume
->SizeBlock
,file
->buffer
));
420 dir
->buffer
[BLK_CHECKSUM
] = 0;
421 dir
->buffer
[BLK_CHECKSUM
] =
422 OS_LONG2BE(0-calcChkSum(volume
->SizeBlock
,dir
->buffer
));
426 /********************************************
427 Name : getDirBlockBuffer
428 Descr.: returns cacheblock of the block the
429 last component before "/" or ":" of
430 name refers to or cacheblock of ah
431 if there is no such component
432 Input : ah - filehandle name is relative to
433 name - name of object
434 entryname - will be filled with a copy
435 of the last component of
437 Output: NULL for error (global error will be set);
438 pointer to a struct BlockCache otherwise
439 *********************************************/
440 struct BlockCache
*getDirBlockBuffer
442 struct AFSBase
*afsbase
,
443 struct AfsHandle
*ah
,
453 end
= PathPart(name
);
456 CopyMem(name
, buffer
, end
-name
);
457 buffer
[end
-name
] = 0;
458 len
= strlen(name
)+name
-end
;
459 CopyMem(end
, entryname
, len
); /* skip slash or colon */
461 return findBlock(afsbase
, ah
, buffer
, &block
, error
);
464 /********************************************
466 Descr.: rename an object
467 Input : dirah - filehandle names are relative to
468 oname - object to rename
469 newname - new name of the object
470 Output: 0 for success; error code otherwise
471 *********************************************/
474 struct AFSBase
*afsbase
,
475 struct AfsHandle
*dirah
,
480 struct BlockCache
*lastlink
,*oldfile
,*existingfile
,*dirblock
;
481 ULONG block
,dirblocknum
,lastblock
;
482 UBYTE newentryname
[34];
485 D(bug("[afs] rename(%ld,%s,%s)\n", dirah
->header_block
, oname
, newname
));
486 if (0 == checkValid(afsbase
, dirah
->volume
))
487 return ERROR_DISK_WRITE_PROTECTED
;
488 dirblock
= getDirBlockBuffer(afsbase
, dirah
, newname
, newentryname
, &error
);
489 if (dirblock
== NULL
)
491 dirblocknum
= dirblock
->blocknum
;
492 D(bug("[afs] dir is on block %ld\n", dirblocknum
));
493 oldfile
= findBlock(afsbase
, dirah
, oname
, &lastblock
, &error
);
496 oldfile
->flags
|= BCF_USED
;
497 existingfile
= getHeaderBlock(afsbase
, dirah
->volume
, newentryname
,
498 dirblock
, &block
, &error
);
499 if (existingfile
!= NULL
&& existingfile
->blocknum
!= oldfile
->blocknum
)
501 dirblock
->flags
&= ~BCF_USED
;
502 return ERROR_OBJECT_EXISTS
;
504 /* do we move a directory? */
505 if (OS_BE2LONG(oldfile
->buffer
[BLK_SECONDARY_TYPE(dirah
->volume
)])==ST_USERDIR
)
507 /* is newdirblock child of olock/oname */
508 dirblock
= getBlock(afsbase
, dirah
->volume
, dirblocknum
);
509 if (dirblock
== NULL
)
511 oldfile
->flags
&= ~BCF_USED
;
512 return ERROR_UNKNOWN
;
514 while ((block
= OS_BE2LONG(dirblock
->buffer
[BLK_PARENT(dirah
->volume
)])))
516 if (block
== oldfile
->blocknum
)
518 oldfile
->flags
&= ~BCF_USED
;
519 return ERROR_OBJECT_IN_USE
;
521 dirblock
= getBlock(afsbase
, dirah
->volume
, block
);
522 if (dirblock
== NULL
)
524 oldfile
->flags
&= ~BCF_USED
;
525 return ERROR_UNKNOWN
;
529 lastlink
= getBlock(afsbase
, dirah
->volume
, lastblock
);
530 if (lastlink
== NULL
)
532 oldfile
->flags
&= ~BCF_USED
;
533 return ERROR_UNKNOWN
;
535 lastlink
->flags
|= BCF_USED
;
536 unLinkBlock(afsbase
, dirah
->volume
, lastlink
, oldfile
);
537 /* rename in same dir ? */
538 if (lastlink
->blocknum
== dirblocknum
)
540 /* use same buffers! */
543 /* otherwise we use different blocks */
546 dirblock
= getBlock(afsbase
, dirah
->volume
, dirblocknum
);
547 if (dirblock
== NULL
)
549 oldfile
->flags
&= ~BCF_USED
;
550 lastlink
->flags
&= ~BCF_USED
;
551 return ERROR_UNKNOWN
;
558 dirblock
->buffer
[BLK_SECONDARY_TYPE(dirah
->volume
)]
564 dirblock
->buffer
[BLK_SECONDARY_TYPE(dirah
->volume
)]
569 oldfile
->flags
&= ~BCF_USED
;
570 lastlink
->flags
&= ~BCF_USED
;
571 return ERROR_OBJECT_WRONG_TYPE
;
576 (APTR
)((char *)oldfile
->buffer
+(BLK_FILENAME_START(dirah
->volume
)*4)),
579 dirblock
= linkNewBlock(afsbase
, dirah
->volume
, dirblock
, oldfile
);
580 if (dirblock
== NULL
)
582 oldfile
->flags
&= ~BCF_USED
;
583 lastlink
->flags
&= ~BCF_USED
;
584 return ERROR_UNKNOWN
;
586 /* concurrent access if newdir=rootblock! */
587 dirblock
->flags
|= BCF_USED
;
589 mark it as used, so that this buffer isn't
590 used in invalidating volume!
592 if (!setBitmapFlag(afsbase
, dirah
->volume
, 0))
594 oldfile
->flags
&= ~BCF_USED
;
595 lastlink
->flags
&= ~BCF_USED
;
596 dirblock
->flags
&= ~BCF_USED
;
597 return ERROR_UNKNOWN
;
599 /* now we can release that buffer */
600 dirblock
->flags
&= ~BCF_USED
;
602 syscrash after this: 2 dirs pointing to the same
603 dir and one wrong linked entry->recoverable
605 writeBlock(afsbase
, dirah
->volume
, dirblock
, -1);
607 syscrash after this: directory pointing is now
608 correct but one wrong linked entry->recoverable
610 writeBlock(afsbase
, dirah
->volume
, lastlink
, -1);
611 writeBlock(afsbase
, dirah
->volume
, oldfile
, -1);
612 oldfile
->flags
&= ~BCF_USED
;
613 lastlink
->flags
&= ~BCF_USED
;
615 if newdir=rootblock we now write the correct
616 (changed) buffer back
618 setBitmapFlag(afsbase
, dirah
->volume
, -1);
622 /********************************************
623 Name : createNewEntry
624 Descr.: create a new object on disk
626 entrytype - ST_USERDIR/ST_FILE/...
627 entryname - name of object
628 dirblock - pointer to struct BlockCache
629 containing a directory in which
630 name shall be created in
631 protection - protection bit mask
632 Output: NULL for error (global error set);
633 pointer to struct BlockCache of the newly
634 created object otherwise
635 *********************************************/
636 struct BlockCache
*createNewEntry
638 struct AFSBase
*afsbase
,
639 struct Volume
*volume
,
641 CONST_STRPTR entryname
,
642 struct BlockCache
*dirblock
,
647 struct BlockCache
*newblock
;
651 D(bug("[afs] createNewEntry(%ld, %s)\n", dirblock
->blocknum
, entryname
));
652 dirblock
->flags
|= BCF_USED
;
653 if (getHeaderBlock(afsbase
, volume
, entryname
, dirblock
, &i
, error
) != NULL
)
655 dirblock
->flags
&= ~BCF_USED
;
656 *error
= ERROR_OBJECT_EXISTS
;
660 if (!invalidBitmap(afsbase
, volume
))
662 dirblock
->flags
&= ~BCF_USED
;
665 i
= allocBlock(afsbase
, volume
);
668 dirblock
->flags
&= ~BCF_USED
;
669 validBitmap(afsbase
, volume
);
670 *error
= ERROR_DISK_FULL
;
673 newblock
= getFreeCacheBlock(afsbase
, volume
, i
);
674 if (newblock
== NULL
)
676 dirblock
->flags
&= ~BCF_USED
;
677 validBitmap(afsbase
, volume
);
678 *error
= ERROR_UNKNOWN
;
681 newblock
->flags
|= BCF_USED
;
682 newblock
->buffer
[BLK_PRIMARY_TYPE
] = OS_LONG2BE(T_SHORT
);
683 for (i
=BLK_BLOCK_COUNT
; i
<=BLK_COMMENT_END(volume
); i
++)
684 newblock
->buffer
[i
] = 0;
685 newblock
->buffer
[BLK_PROTECT(volume
)] = OS_LONG2BE(protection
);
687 newblock
->buffer
[BLK_DAYS(volume
)] = OS_LONG2BE(ds
.ds_Days
);
688 newblock
->buffer
[BLK_MINS(volume
)] = OS_LONG2BE(ds
.ds_Minute
);
689 newblock
->buffer
[BLK_TICKS(volume
)] = OS_LONG2BE(ds
.ds_Tick
);
693 (APTR
)((char *)newblock
->buffer
+(BLK_FILENAME_START(volume
)*4)),
696 for (i
=BLK_FILENAME_END(volume
)+1; i
<BLK_HASHCHAIN(volume
); i
++)
697 newblock
->buffer
[i
] = 0;
698 newblock
->buffer
[BLK_PARENT(volume
)] = OS_LONG2BE(dirblock
->blocknum
);
699 newblock
->buffer
[BLK_EXTENSION(volume
)] = 0;
700 newblock
->buffer
[BLK_SECONDARY_TYPE(volume
)] = OS_LONG2BE(entrytype
);
701 newblock
->buffer
[BLK_OWN_KEY
] = OS_LONG2BE(newblock
->blocknum
);
702 dirblock
->flags
&= ~BCF_USED
;
703 dirblock
= linkNewBlock(afsbase
, volume
, dirblock
, newblock
);
704 if (dirblock
== NULL
)
706 markBlock(afsbase
, volume
, newblock
->blocknum
, -1);
707 newblock
->flags
&= ~BCF_USED
;
708 newblock
->newness
= 0;
709 validBitmap(afsbase
, volume
);
713 if crash after this block not yet linked->block
714 not written to disk, bitmap corrected
716 writeBlock(afsbase
, volume
, newblock
, -1);
717 /* consistent after this */
718 writeBlock(afsbase
, volume
, dirblock
, -1);
719 validBitmap(afsbase
, volume
);
720 newblock
->flags
&= ~BCF_USED
;
725 /********************************************
727 Descr.: create a directory object
728 Input : dirah - filehandle filename is relative to
729 filename - path to the new directory
730 protection - protection bit mask
731 Output: pointer to struct AfsHandle;
732 NULL otherwise (global error set)
733 *********************************************/
734 struct AfsHandle
*createDir
736 struct AFSBase
*afsbase
,
737 struct AfsHandle
*dirah
,
738 CONST_STRPTR filename
,
743 struct AfsHandle
*ah
= NULL
;
744 struct BlockCache
*dirblock
;
747 D(bug("[afs] createDir(ah,%s,%ld)\n", filename
, protection
));
748 if (0 == checkValid(afsbase
, dirah
->volume
))
750 *error
= ERROR_DISK_WRITE_PROTECTED
;
753 dirblock
= getDirBlockBuffer(afsbase
, dirah
, filename
, dirname
, error
);
754 if (dirblock
!= NULL
)
756 D(bug("[afs] dir is on block %ld\n", dirblock
->blocknum
));
757 dirblock
= createNewEntry
758 (afsbase
, dirah
->volume
, ST_USERDIR
, dirname
, dirblock
, protection
, error
);
759 if (dirblock
!= NULL
)
760 ah
= getHandle(afsbase
, dirah
->volume
, dirblock
, MODE_OLDFILE
, error
);