2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
10 #include "filehandles1.h"
11 #include "filehandles2.h"
13 #include "extstrings.h"
14 #include "checksums.h"
17 #include "afsblocks.h"
18 #include "baseredef.h"
19 #include "validator.h"
21 /***********************************************
23 Descr.: search through blocks until header block found
24 Input : name - object we are searching for
25 blockbuffer - dirblock we are searching in
26 block - will be filled with the block number
27 prior to the entry we are using
28 Output: cache block of last object
29 See : locateObject, setDate, setComment, deleteObject
30 ************************************************/
31 struct BlockCache
*getHeaderBlock
33 struct AFSBase
*afsbase
,
34 struct Volume
*volume
,
36 struct BlockCache
*blockbuffer
,
43 D(bug("[afs] getHeaderBlock: searching for block of '%s'\n",name
));
44 key
= getHashKey(name
,volume
->SizeBlock
-56,volume
->dosflags
)+BLK_TABLE_START
;
45 *block
= blockbuffer
->blocknum
;
46 if (blockbuffer
->buffer
[key
] == 0)
48 *error
= ERROR_OBJECT_NOT_FOUND
;
51 blockbuffer
=getBlock(afsbase
, volume
,OS_BE2LONG(blockbuffer
->buffer
[key
]));
52 if (blockbuffer
== NULL
)
54 *error
= ERROR_UNKNOWN
;
61 name
= (char *)blockbuffer
->buffer
+(BLK_DIRECTORYNAME_START(volume
)*4);
62 kprintf("[afs] %.*s\n", name
[0], name
+1);
65 if (calcChkSum(volume
->SizeBlock
, blockbuffer
->buffer
) != 0)
68 * since we will not work on blockbuffer here any more,
69 * we don't have to preserve it.
71 if (showError(afsbase
, ERR_CHECKSUM
, blockbuffer
->blocknum
))
72 launchValidator(afsbase
, volume
);
74 *error
= ERROR_UNKNOWN
;
77 if (OS_BE2LONG(blockbuffer
->buffer
[BLK_PRIMARY_TYPE
]) != T_SHORT
)
80 * again, we don't work on blockbuffer any more
81 * no need to preserve BlockCache structure.
83 if (showError(afsbase
, ERR_BLOCKTYPE
, blockbuffer
->blocknum
))
84 launchValidator(afsbase
, volume
);
86 *error
= ERROR_OBJECT_WRONG_TYPE
;
90 while (!noCaseStrCmp(name
, (char *)blockbuffer
->buffer
+ (BLK_DIRECTORYNAME_START(volume
)*4),
91 volume
->dosflags
, MAX_NAME_LENGTH
))
93 *block
= blockbuffer
->blocknum
;
94 if (blockbuffer
->buffer
[BLK_HASHCHAIN(volume
)] == 0)
96 *error
=ERROR_OBJECT_NOT_FOUND
;
103 OS_BE2LONG(blockbuffer
->buffer
[BLK_HASHCHAIN(volume
)])
105 if (blockbuffer
== NULL
)
107 *error
= ERROR_UNKNOWN
;
110 if (calcChkSum(volume
->SizeBlock
, blockbuffer
->buffer
) != 0)
113 * we won't work on blockbuffer any more
114 * don't preserve the buffer.
116 if (showError(afsbase
, ERR_CHECKSUM
,blockbuffer
->blocknum
))
117 launchValidator(afsbase
, volume
);
119 *error
=ERROR_UNKNOWN
;
122 if (OS_BE2LONG(blockbuffer
->buffer
[BLK_PRIMARY_TYPE
]) != T_SHORT
)
125 * not working with blockbuffer :)
127 if (showError(afsbase
, ERR_BLOCKTYPE
, blockbuffer
->blocknum
))
128 launchValidator(afsbase
, volume
);
130 *error
= ERROR_OBJECT_WRONG_TYPE
;
137 /*******************************************
139 Descr.: find the header block of a file/dir
140 Input : dirah - directory lock as starting point
141 if NULL, start in root dir
142 name - path of file/dir
143 block - will be filled with the block number
144 prior to the entry we are using; rootblock
145 if we are searching for the root
146 Output: NULL=error (evtl. error=ERROR_...)
147 blockcache structure of found block otherwise
148 ********************************************/
149 struct BlockCache
*findBlock
151 struct AFSBase
*afsbase
,
152 struct AfsHandle
*dirah
,
159 struct BlockCache
*blockbuffer
;
162 if (dirah
->volume
->dostype
!= 0x444F5300)
164 D(bug("[afs] Unknown dostype 0x%08x\n", dirah
->volume
->dostype
));
165 *error
= ERROR_NOT_A_DOS_DISK
;
168 *block
= dirah
->header_block
;
170 D(bug("[afs] findBlock: startblock=%ld\n",*block
));
171 /* get first entry (root or filelock refers to) */
172 blockbuffer
= getBlock(afsbase
, dirah
->volume
, *block
);
173 if (blockbuffer
== NULL
)
175 *error
= ERROR_UNKNOWN
;
176 D(bug("[afs] error blockbuffer\n"));
179 if (calcChkSum(dirah
->volume
->SizeBlock
, blockbuffer
->buffer
) != 0)
182 * not working with blockbuffer any more.
183 * otherwise we would need to preserve it (BCF_USED or one more time getBlock)
185 if (showError(afsbase
, ERR_CHECKSUM
, *block
))
186 launchValidator(afsbase
, dirah
->volume
);
188 *error
= ERROR_UNKNOWN
;
189 D(bug("[afs] error checksum\n"));
192 if (OS_BE2LONG(blockbuffer
->buffer
[BLK_PRIMARY_TYPE
]) != T_SHORT
)
197 if (showError(afsbase
, ERR_BLOCKTYPE
, *block
))
198 launchValidator(afsbase
, dirah
->volume
);
200 *error
= ERROR_OBJECT_WRONG_TYPE
;
201 D(bug("[afs] error wrong type\n"));
206 if (*name
== '/') /* get parent entry ? */
208 if (blockbuffer
->buffer
[BLK_PARENT(dirah
->volume
)] == 0)
210 *error
= ERROR_OBJECT_NOT_FOUND
;
211 D(bug("[afs] object not found\n"));
214 D(bug("[afs] findBlock: getting parent\n"));
215 blockbuffer
= getBlock
219 OS_BE2LONG(blockbuffer
->buffer
[BLK_PARENT(dirah
->volume
)])
221 if (blockbuffer
== NULL
)
223 *error
= ERROR_UNKNOWN
;
224 D(bug("[afs] error no blockbuffer\n"));
234 blockbuffer
->buffer
[BLK_SECONDARY_TYPE(dirah
->volume
)]
238 blockbuffer
->buffer
[BLK_SECONDARY_TYPE(dirah
->volume
)]
242 blockbuffer
->buffer
[BLK_SECONDARY_TYPE(dirah
->volume
)]
245 *error
= ERROR_OBJECT_WRONG_TYPE
;
246 D(bug("[afs] error wrong type\n"));
250 while ((*name
!= 0) && (*name
!= '/'))
259 "[afs] findBlock: searching for header block of %s\n",
263 getHeaderBlock(afsbase
, dirah
->volume
, buffer
, blockbuffer
, block
, error
);
264 if (blockbuffer
== NULL
)
265 break; /* object not found or other error */
269 if (blockbuffer
!= NULL
)
270 bug("[afs] findBlock: block=%ld\n",blockbuffer
->blocknum
);
272 bug("[afs] findBlock: error\n");
277 /* add handle to locklist */
278 void addHandle(struct AfsHandle
*ah
) {
280 ah
->next
=ah
->volume
->locklist
;
281 ah
->volume
->locklist
=ah
;
284 /* remove handle from locklist */
285 void remHandle(struct AFSBase
*afsbase
, struct AfsHandle
*ah
) {
286 struct AfsHandle
*old
= NULL
;
288 D(bug("[afs 0x%08lX] Removing handle 0x%08lX\n", ah
->volume
, ah
));
289 if (ah
->volume
->volumenode
== ah
->volumenode
) {
290 D(bug("[afs 0x%08lX] Lock's volume is online\n", ah
->volume
));
291 if (ah
->volume
->locklist
==ah
)
292 ah
->volume
->locklist
=ah
->next
;
294 old
=ah
->volume
->locklist
;
298 D(bug("[afs 0x%08lX] Lock's volume is offline\n", ah
->volume
));
299 if (BADDR(ah
->volumenode
->dol_misc
.dol_volume
.dol_LockList
) == ah
)
301 ah
->volumenode
->dol_misc
.dol_volume
.dol_LockList
= MKBADDR(ah
->next
);
303 D(bug("[afs 0x%08lX] Last lock removed, removing VolumeNode\n", ah
->volume
));
304 remDosNode(afsbase
, ah
->volumenode
);
307 old
= BADDR(ah
->volumenode
->dol_misc
.dol_volume
.dol_LockList
);
321 /* find handle in locklist */
322 struct AfsHandle
*findHandle(struct Volume
*volume
, ULONG block
) {
323 struct AfsHandle
*ah
;
328 if (ah
->header_block
==block
)
335 /****************************************
337 Descr.: allocate a new handle
339 fileblock - block of the entry
341 hashtable - ptr to the (hash)table
342 Output: AfsHandle for success; NULL otherwise
343 ****************************************/
344 struct AfsHandle
*allocHandle
346 struct AFSBase
*afsbase
,
347 struct Volume
*volume
,
348 struct BlockCache
*fileblock
,
354 struct AfsHandle
*ah
;
356 ah
=(struct AfsHandle
*)AllocMem
357 (sizeof(struct AfsHandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
360 ah
->header_block
= fileblock
->blocknum
;
361 ah
->dirpos
= fileblock
->blocknum
;
363 ah
->current
.block
= fileblock
->blocknum
;
364 ah
->current
.filekey
= BLK_TABLE_END(volume
);
365 ah
->current
.byte
= 0;
366 ah
->current
.offset
= 0;
367 ah
->filesize
= OS_BE2LONG(fileblock
->buffer
[BLK_BYTE_SIZE(volume
)]);
369 ah
->volumenode
= volume
->volumenode
;
373 *error
= ERROR_NO_FREE_STORE
;
377 /****************************************
379 Descr.: check if a new handle can be
380 allocated and allocate one if
383 fileblock - block of the entry
385 Output: AfsHandle for success; NULL otherwise
386 ****************************************/
387 struct AfsHandle
*getHandle
389 struct AFSBase
*afsbase
,
390 struct Volume
*volume
,
391 struct BlockCache
*fileblock
,
396 struct AfsHandle
*ah
;
400 "[afs] getHandle: trying to get handle for block %lu\n",
406 ah
= findHandle(volume
, fileblock
->blocknum
);
409 if (ah
->mode
== MODE_READWRITE
||
410 ah
->mode
== MODE_NEWFILE
)
412 *error
= ERROR_OBJECT_IN_USE
;
425 (ULONG
*)((char *)fileblock
->buffer
+(BLK_TABLE_START
*4)),
433 /*****************************************
435 Descr.: open (lock) a file
436 Input : dirah - a handle filename is
438 filename - filename to lock
440 Output: AfsHandle for success; NULL otherwise
441 ******************************************/
442 struct AfsHandle
*openf
444 struct AFSBase
*afsbase
,
445 struct AfsHandle
*dirah
,
446 CONST_STRPTR filename
,
451 struct AfsHandle
*ah
= NULL
;
452 struct BlockCache
*fileblock
;
455 D(bug("[afs] openf(%ld,%s,0x%8lx)\n",dirah
->header_block
,filename
,mode
));
456 fileblock
= findBlock(afsbase
, dirah
, filename
, &block
, error
);
457 if (fileblock
!= NULL
)
458 ah
= getHandle(afsbase
, dirah
->volume
, fileblock
, mode
, error
);
462 /*****************************************
464 Descr.: open (lock) a file
465 Input : dirah - a handle filename is
467 name - filename to lock
469 protection - bits for new files
470 Output: AfsHandle for success; NULL otherwise
471 ******************************************/
472 struct AfsHandle
*openfile
474 struct AFSBase
*afsbase
,
475 struct AfsHandle
*dirah
,
482 struct AfsHandle
*ah
= NULL
;
483 struct BlockCache
*fileblock
, *dirblock
;
486 ULONG fileblocknum
= -1;
489 * nicely say what's going on
491 D(bug("[afs] openfile(%lu,%s,0x%lx,%lu)\n", dirah
->header_block
,name
,mode
,protection
));
495 * if user wants to delete or create a new file - make sure we can do that.
497 if ((mode
!= MODE_OLDFILE
) && (0 == checkValid(afsbase
, dirah
->volume
)))
498 *error
= ERROR_DISK_WRITE_PROTECTED
;
501 * get the directory the last component of "name" is in
503 dirblock
= getDirBlockBuffer(afsbase
, dirah
, name
, filename
, error
);
506 * if no error so far and directory block is found, move on.
508 if (*error
== 0 && dirblock
!= NULL
)
511 * only if the directory is of DIR or ROOT type
513 if ((OS_BE2LONG(dirblock
->buffer
[BLK_SECONDARY_TYPE(dirah
->volume
)]) == ST_USERDIR
) ||
514 (OS_BE2LONG(dirblock
->buffer
[BLK_SECONDARY_TYPE(dirah
->volume
)]) == ST_ROOT
))
516 D(bug("[afs] parent of %s is on block %lu\n", name
, dirblock
->blocknum
));
519 * get the header block of the file to open
521 fileblock
= getHeaderBlock(afsbase
, dirah
->volume
, filename
, dirblock
, &block
, error
);
524 * check if 'file' is really a FILE
526 if ((fileblock
!= NULL
) && (OS_BE2LONG(fileblock
->buffer
[BLK_SECONDARY_TYPE(dirah
->volume
)])!=ST_FILE
))
528 *error
= ERROR_OBJECT_WRONG_TYPE
;
533 * get file block, if there was (is) a file
535 if (fileblock
!= NULL
)
536 fileblocknum
= fileblock
->blocknum
;
539 * remove existing file if we are asked to clear its contents
541 if (mode
== MODE_NEWFILE
)
542 *error
= deleteObject(afsbase
, dirah
, name
);
545 * if we cleared the file or there was no file at all, move on
547 if ((*error
== 0) || (*error
== ERROR_OBJECT_NOT_FOUND
))
550 * in case we could not find existing file, or if we deleted this file previously,
553 if (mode
== MODE_NEWFILE
)
556 * please note that dirblock may become invalid here
558 fileblock
= createNewEntry(afsbase
, dirah
->volume
, ST_FILE
, filename
, dirblock
, protection
, error
);
563 * we should already have fileblock here
564 * again, dirblock may become invalid here
566 if (fileblock
!= NULL
)
567 fileblock
= getBlock(afsbase
, dirah
->volume
, fileblocknum
);
571 * create a handle for the file
573 if (fileblock
!= NULL
)
576 ah
= getHandle(afsbase
, dirah
->volume
, fileblock
, mode
, error
);
582 *error
= ERROR_OBJECT_WRONG_TYPE
;
587 /***********************************
589 Descr.: close a file/free a lock
590 Input : ah - the handle to close
592 ************************************/
593 void closef(struct AFSBase
*afsbase
, struct AfsHandle
*ah
) {
595 D(bug("[afs] closef(%lu)\n",ah
->header_block
));
596 remHandle(afsbase
, ah
);
597 FreeMem(ah
,sizeof(struct AfsHandle
));
600 /******************************************
602 Descr.: read data from file
603 Input : ah - handle (file) to read from
604 buffer - buffer to store data into
605 length - size of data to read
607 *******************************************/
610 struct AFSBase
*afsbase
,
611 struct AfsHandle
*ah
,
617 struct BlockCache
*extensionbuffer
;
618 struct BlockCache
*databuffer
;
623 if (ah
->current
.block
== 0)
624 return 0; /* we can't read beyond EOF so return EOF */
625 if (length
> (ah
->filesize
-ah
->current
.offset
))
627 length
= ah
->filesize
-ah
->current
.offset
; /* we can't read more bytes than left in file! */
629 D(bug("[afs] readData: offset=%ld\n", ah
->current
.offset
));
630 extensionbuffer
= getBlock(afsbase
, ah
->volume
, ah
->current
.block
);
631 if (extensionbuffer
== NULL
)
633 *error
= ERROR_UNKNOWN
;
636 extensionbuffer
->flags
|= BCF_USED
; /* don't overwrite that cache block! */
639 D(bug("[afs] readData: bytes left=%ld\n",length
));
641 block, filekey always point to the next block
642 so update them if we have read a whole block
644 /* do we have to read next extension block? */
645 if (ah
->current
.filekey
<BLK_TABLE_START
)
648 OS_BE2LONG(extensionbuffer
->buffer
[BLK_EXTENSION(ah
->volume
)]);
649 ah
->current
.filekey
= BLK_TABLE_END(ah
->volume
);
650 extensionbuffer
->flags
&= ~BCF_USED
; //we can now overwrite that cache block
651 D(bug("[afs] readData: reading extensionblock=%ld\n",ah
->current
.block
));
652 if (ah
->current
.block
!= 0)
654 extensionbuffer
= getBlock(afsbase
, ah
->volume
,ah
->current
.block
);
655 if (extensionbuffer
== 0)
657 *error
= ERROR_UNKNOWN
;
658 return ENDSTREAMCH
; //was readbytes;
660 extensionbuffer
->flags
|= BCF_USED
; //don't overwrite this cache block
667 "Shit, out of extensionblocks!\n"
669 "Last extensionblock: %ld\n",
670 length
,extensionbuffer
->blocknum
676 "[afs] readData: reading datablock %ld\n",
677 OS_BE2LONG(extensionbuffer
->buffer
[ah
->current
.filekey
]))
679 databuffer
= getBlock
683 OS_BE2LONG(extensionbuffer
->buffer
[ah
->current
.filekey
])
687 extensionbuffer
->flags
&= ~BCF_USED
; //free that block
688 *error
= ERROR_UNKNOWN
;
689 return ENDSTREAMCH
; //was readbytes;
691 source
= (char *)databuffer
->buffer
+ah
->current
.byte
;
692 if (ah
->volume
->dosflags
== 0)
694 size
= OS_BE2LONG(databuffer
->buffer
[BLK_DATA_SIZE
]);
695 source
+= (BLK_DATA_START
*4);
699 size
= BLOCK_SIZE(ah
->volume
);
701 size
-= ah
->current
.byte
;
705 ah
->current
.byte
+= size
;
709 ah
->current
.byte
= 0;
710 ah
->current
.filekey
--;
712 CopyMem((APTR
)source
, (APTR
)((char *)buffer
+readbytes
),size
);
716 extensionbuffer
->flags
&= ~BCF_USED
;
721 (struct AFSBase
*afsbase
, struct AfsHandle
*ah
, void *buffer
, ULONG length
, SIPTR
*error
)
725 D(bug("[afs] read(%ld,buffer,%ld)\n", ah
->header_block
, length
));
726 readbytes
= readData(afsbase
, ah
,buffer
,length
, error
);
727 if (readbytes
!= ENDSTREAMCH
)
728 ah
->current
.offset
= ah
->current
.offset
+readbytes
;
732 void newFileExtensionBlock
734 struct Volume
*volume
,
735 struct BlockCache
*extension
,
740 extension
->buffer
[BLK_PRIMARY_TYPE
] = OS_LONG2BE(T_LIST
);
741 extension
->buffer
[BLK_OWN_KEY
] = OS_LONG2BE(extension
->blocknum
);
742 for (i
=2; i
<BLK_PARENT(volume
); i
++)
743 extension
->buffer
[i
] = 0;
744 extension
->buffer
[BLK_PARENT(volume
)] = OS_LONG2BE(parent
);
745 extension
->buffer
[BLK_EXTENSION(volume
)] = 0;
746 extension
->buffer
[BLK_SECONDARY_TYPE(volume
)] = OS_LONG2BE(ST_FILE
);
749 void writeExtensionBlock
751 struct AFSBase
*afsbase
,
752 struct Volume
*volume
,
753 struct BlockCache
*extension
,
758 ULONG newcount
= BLK_TABLE_END(volume
)-(filekey
-1);
760 if (OS_BE2LONG(extension
->buffer
[BLK_BLOCK_COUNT
]) < newcount
)
761 extension
->buffer
[BLK_BLOCK_COUNT
] = OS_LONG2BE(newcount
);
763 extension
->buffer
[BLK_EXTENSION(volume
)] = OS_LONG2BE(next
);
764 writeBlockDeferred(afsbase
, volume
, extension
, BLK_CHECKSUM
);
769 struct AFSBase
*afsbase
,
770 struct AfsHandle
*ah
,
777 ULONG lastblock
= 0; /* 0 means: don't update BLK_NEXT_DATA */
778 struct BlockCache
*extensionbuffer
= NULL
;
779 struct BlockCache
*databuffer
= NULL
;
780 UWORD size
, blockCapacity
;
781 LONG writtenbytes
= 0, sumoffset
;
783 BOOL extensionModified
= FALSE
;
785 D(bug("[afs] writeData: offset=%ld\n", ah
->current
.offset
));
786 extensionbuffer
= getBlock(afsbase
, ah
->volume
, ah
->current
.block
);
787 if (extensionbuffer
== NULL
)
789 *error
= ERROR_UNKNOWN
;
792 extensionbuffer
->flags
|=BCF_USED
; /* don't overwrite that cache block! */
795 /* save last data block for OFS data */
797 (ah
->current
.byte
==0) && /* last block fully written */
798 (ah
->current
.filekey
!=BLK_TABLE_END(ah
->volume
)) /* this is not the first block of the file */
801 lastblock
= OS_BE2LONG(extensionbuffer
->buffer
[ah
->current
.filekey
+1]);
803 ("[afs] writeData: for OFS last datablock was %lu\n", lastblock
));
806 block, filekey always point to the last block
807 so update them if we have read a whole block
809 /* read next extension block? */
810 if (ah
->current
.filekey
< BLK_TABLE_START
)
812 extensionModified
= FALSE
;
813 if (extensionbuffer
->buffer
[BLK_EXTENSION(ah
->volume
)] != 0)
815 block
= OS_BE2LONG(extensionbuffer
->buffer
[BLK_EXTENSION(ah
->volume
)]);
816 extensionbuffer
->flags
&= ~BCF_USED
;
817 extensionbuffer
= getBlock(afsbase
, ah
->volume
, block
);
818 if (extensionbuffer
== NULL
)
820 *error
= ERROR_UNKNOWN
;
821 return ENDSTREAMCH
; // was writtenbytes;
826 D(bug("[afs] writeData: need new extensionblock\n"));
827 block
= allocBlock(afsbase
, ah
->volume
);
833 ah
->current
.filekey
+1,
836 extensionbuffer
->flags
&= ~BCF_USED
;
839 *error
= ERROR_NO_FREE_STORE
;
840 return ENDSTREAMCH
; /* was writtenbytes; */
842 extensionbuffer
= getFreeCacheBlock(afsbase
, ah
->volume
,block
);
843 if (extensionbuffer
== NULL
)
845 *error
= ERROR_UNKNOWN
;
846 return ENDSTREAMCH
; /* was writtenbytes; */
848 newFileExtensionBlock(ah
->volume
,extensionbuffer
, ah
->header_block
);
850 ah
->current
.filekey
= BLK_TABLE_END(ah
->volume
);
851 extensionbuffer
->flags
|= BCF_USED
; /* don't overwrite this cache block */
852 ah
->current
.block
= block
;
854 /* find a block to write data into */
855 if (extensionbuffer
->buffer
[ah
->current
.filekey
] != 0) /* do we already have that block? */
859 "[afs] writeData: using old datablock %lu\n",
860 OS_BE2LONG(extensionbuffer
->buffer
[ah
->current
.filekey
]))
862 /* Only get the block's old contents if some of it won't be overwritten
863 (except for OFS or a final, partially-used block) */
864 block
= OS_BE2LONG(extensionbuffer
->buffer
[ah
->current
.filekey
]);
865 if ((ah
->current
.byte
== 0) && (length
>= BLOCK_SIZE(ah
->volume
))
866 && (ah
->volume
->dosflags
!= 0))
867 databuffer
= getFreeCacheBlock(afsbase
, ah
->volume
, block
);
869 databuffer
= getBlock(afsbase
, ah
->volume
, block
);
870 if (databuffer
== NULL
)
880 extensionbuffer
->flags
&= ~BCF_USED
; //free that block
881 *error
= ERROR_UNKNOWN
;
882 return ENDSTREAMCH
; //was writtenbytes;
887 extensionModified
= TRUE
;
888 D(bug("[afs] writeData: need a new datablock\n"));
889 block
=allocBlock(afsbase
, ah
->volume
);
900 extensionbuffer
->flags
&= ~BCF_USED
;
901 *error
= ERROR_NO_FREE_STORE
;
902 return ENDSTREAMCH
; //was writtenbytes;
904 extensionbuffer
->buffer
[ah
->current
.filekey
] = OS_LONG2BE(block
);
905 if ((ah
->volume
->dosflags
==0) && (lastblock
!= 0))
907 D(bug("[afs] writeData: OFS->fill in %ld BLK_NEXT_DATA\n",lastblock
));
909 we allocated a new block
910 so there MUST be an initialized lastblock
912 databuffer
= getBlock(afsbase
, ah
->volume
,lastblock
);
913 if (databuffer
== NULL
)
923 extensionbuffer
->flags
&= ~BCF_USED
; //free that block
924 *error
= ERROR_UNKNOWN
;
925 return ENDSTREAMCH
; //was writtenbytes;
927 databuffer
->buffer
[BLK_NEXT_DATA
] = OS_LONG2BE(block
);
928 writeBlock(afsbase
, ah
->volume
,databuffer
, BLK_CHECKSUM
);
930 databuffer
= getFreeCacheBlock(afsbase
, ah
->volume
,block
);
931 if (databuffer
== NULL
)
934 (afsbase
, ah
->volume
, extensionbuffer
, ah
->current
.filekey
, 0);
935 extensionbuffer
->flags
&= ~BCF_USED
; //free that block
936 *error
= ERROR_UNKNOWN
;
937 return ENDSTREAMCH
; //was writtenbytes;
939 if (ah
->volume
->dosflags
== 0)
941 databuffer
->buffer
[BLK_PRIMARY_TYPE
] = OS_LONG2BE(T_DATA
);
942 databuffer
->buffer
[BLK_HEADER_KEY
] = OS_LONG2BE(ah
->header_block
);
943 blockCapacity
= (ah
->volume
->SizeBlock
-BLK_DATA_START
)*sizeof(ULONG
);
944 databuffer
->buffer
[BLK_SEQUENCE_NUMBER
] =
946 (((ah
->current
.offset
+writtenbytes
)/blockCapacity
)+1);
947 databuffer
->buffer
[BLK_DATA_SIZE
] = 0;
948 databuffer
->buffer
[BLK_NEXT_DATA
] = 0;
951 destination
= (char *)databuffer
->buffer
+ah
->current
.byte
;
952 size
= BLOCK_SIZE(ah
->volume
);
953 if (ah
->volume
->dosflags
== 0)
956 destination
+= (BLK_DATA_START
*4);
958 size
-= ah
->current
.byte
;
962 ah
->current
.byte
+= size
;
966 ah
->current
.byte
= 0;
967 ah
->current
.filekey
--;
970 CopyMem((APTR
)((char *)buffer
+writtenbytes
),(APTR
)destination
,size
);
971 if (ah
->volume
->dosflags
== 0)
973 if (ah
->current
.byte
== 0)
975 databuffer
->buffer
[BLK_DATA_SIZE
] =
976 OS_LONG2BE(BLOCK_SIZE(ah
->volume
)-(6*4));
978 else if (OS_BE2LONG(databuffer
->buffer
[BLK_DATA_SIZE
]) < ah
->current
.byte
)
980 databuffer
->buffer
[BLK_DATA_SIZE
] = OS_LONG2BE(ah
->current
.byte
);
982 sumoffset
= BLK_CHECKSUM
;
986 if (buffer
!= NULL
|| ah
->volume
->dosflags
== 0)
987 writeBlock(afsbase
, ah
->volume
, databuffer
, sumoffset
);
989 writtenbytes
+= size
;
991 if (extensionModified
)
998 ah
->current
.byte
==0 ? ah
->current
.filekey
+1 : ah
->current
.filekey
,
1002 extensionbuffer
->flags
&= ~BCF_USED
;
1003 D(bug("[afs] writeData=%ld\n", writtenbytes
));
1004 return writtenbytes
;
1008 (struct AFSBase
*afsbase
, struct AfsHandle
*ah
, void *buffer
, ULONG length
, SIPTR
*error
)
1010 struct BlockCache
*headerblock
;
1012 struct DateStamp ds
;
1014 D(bug("[afs] write(ah,buffer,%ld)\n", length
));
1015 if (0 == checkValid(afsbase
, ah
->volume
))
1017 *error
= ERROR_DISK_WRITE_PROTECTED
;
1021 invalidBitmap(afsbase
, ah
->volume
);
1022 writtenbytes
= writeData(afsbase
, ah
, buffer
, length
, error
);
1023 if (writtenbytes
!= ENDSTREAMCH
)
1025 ah
->current
.offset
+= writtenbytes
;
1026 headerblock
= getBlock(afsbase
, ah
->volume
,ah
->header_block
);
1027 if (headerblock
!= NULL
)
1029 headerblock
->buffer
[BLK_FIRST_DATA
] =
1030 headerblock
->buffer
[BLK_TABLE_END(ah
->volume
)];
1031 if (ah
->current
.offset
> ah
->filesize
)
1033 ah
->filesize
= ah
->current
.offset
;
1034 headerblock
->buffer
[BLK_BYTE_SIZE(ah
->volume
)] =
1035 OS_LONG2BE(ah
->filesize
);
1038 setHeaderDate(afsbase
, ah
->volume
, headerblock
, &ds
);
1041 validBitmap(afsbase
, ah
->volume
);
1042 return writtenbytes
;
1046 (struct AFSBase
* afsbase
, struct AfsHandle
*ah
, LONG offset
, LONG mode
, SIPTR
*error
)
1049 UWORD filekey
, byte
;
1050 ULONG block
, extblockindex
, newextblockindex
;
1051 UWORD blocksize
, tablesize
;
1053 struct BlockCache
*blockbuffer
;
1055 D(bug("[afs] seek(%ld,%ld,%ld)\n", ah
->header_block
, offset
, mode
));
1056 *error
= ERROR_SEEK_ERROR
;
1057 if (mode
== OFFSET_BEGINNING
)
1059 newoffset
= (ULONG
)offset
;
1061 else if (mode
== OFFSET_CURRENT
)
1066 return ah
->current
.offset
;
1068 newoffset
= ah
->current
.offset
+offset
;
1070 else if (mode
== OFFSET_END
)
1072 newoffset
= ah
->filesize
+offset
;
1076 if ((LONG
)newoffset
>= 0)
1078 blocksize
= BLOCK_SIZE(ah
->volume
);
1079 if (ah
->volume
->dosflags
== 0)
1080 blocksize
-= (BLK_DATA_START
*4);
1081 newextblockindex
= newoffset
/ blocksize
;
1082 tablesize
= BLK_TABLE_END(ah
->volume
)-BLK_TABLE_START
+1;
1083 filekey
= BLK_TABLE_END(ah
->volume
)-(newextblockindex
% tablesize
);
1084 newextblockindex
/= tablesize
; /* # of extensionblock we need */
1085 byte
= newoffset
% blocksize
;
1086 if (newoffset
!= 0 && byte
== 0 && filekey
== BLK_TABLE_END(ah
->volume
))
1089 filekey
= BLK_TABLE_START
- 1;
1092 /* Get index of current extension block */
1093 extblockindex
= (ah
->current
.offset
/ blocksize
) / tablesize
;
1094 if (ah
->current
.filekey
<BLK_TABLE_START
)
1097 /* Start at current extension block, unless we have to go back to
1098 a previous extension block */
1099 if (newextblockindex
>= extblockindex
)
1100 block
= ah
->current
.block
;
1103 block
= ah
->header_block
;
1107 while ((extblockindex
!= newextblockindex
) && (block
!= 0))
1109 blockbuffer
= getBlock(afsbase
, ah
->volume
, block
);
1110 if (blockbuffer
== NULL
)
1112 block
= OS_BE2LONG(blockbuffer
->buffer
[BLK_EXTENSION(ah
->volume
)]);
1118 old
= ah
->current
.offset
;
1119 ah
->current
.block
= block
;
1120 ah
->current
.filekey
= filekey
;
1121 ah
->current
.byte
= byte
;
1122 ah
->current
.offset
= newoffset
;
1129 (struct AFSBase
* afsbase
, struct AfsHandle
*ah
, LONG size
, LONG mode
, SIPTR
*error
)
1131 LONG pos
= -1, extra
, savederror
, newsize
;
1132 struct BlockCache
*headerblock
;
1133 struct DateStamp ds
;
1134 struct AfsHandle
*ah2
;
1136 if (0 == checkValid(afsbase
, ah
->volume
))
1138 *error
= ERROR_DISK_WRITE_PROTECTED
;
1142 /* Get absolute new length */
1143 D(bug("[afs] setfilesize(%ld,%ld,%ld)\n", ah
->header_block
, size
, mode
));
1144 *error
= ERROR_SEEK_ERROR
;
1145 if (mode
== OFFSET_BEGINNING
)
1149 else if (mode
== OFFSET_CURRENT
)
1151 newsize
= ah
->current
.offset
;
1153 else if (mode
== OFFSET_END
)
1155 newsize
= ah
->filesize
;
1160 /* Ensure new length isn't negative */
1161 if (-size
> newsize
)
1167 /* Ensure there aren't any other filehandles positioned after the new
1169 for (ah2
= ah
->volume
->locklist
; ah2
!= NULL
; ah2
= ah2
->next
)
1171 if (ah2
!= ah
&& ah2
->header_block
== ah
->header_block
1172 && ah2
->current
.offset
> newsize
)
1176 /* Lengthen or shorten file */
1177 pos
= ah
->current
.offset
;
1178 if (newsize
> ah
->filesize
)
1180 seek(afsbase
, ah
, 0, OFFSET_END
, error
);
1181 invalidBitmap(afsbase
, ah
->volume
);
1182 extra
= writeData(afsbase
, ah
, NULL
, newsize
- ah
->filesize
, error
);
1183 validBitmap(afsbase
, ah
->volume
);
1185 /* Revert to original size if we couldn't fully lengthen the file */
1186 if (extra
< newsize
- ah
->filesize
)
1188 savederror
= *error
;
1189 setFileSize(afsbase
, ah
, ah
->filesize
, OFFSET_BEGINNING
, error
);
1190 *error
= savederror
;
1196 seek(afsbase
, ah
, newsize
, OFFSET_BEGINNING
, error
);
1197 deleteFileRemainder(afsbase
, ah
);
1203 /* Update metadata */
1204 headerblock
= getBlock(afsbase
, ah
->volume
, ah
->header_block
);
1205 if (headerblock
!= NULL
)
1207 ah
->filesize
= newsize
;
1208 headerblock
->buffer
[BLK_BYTE_SIZE(ah
->volume
)] =
1209 OS_LONG2BE(ah
->filesize
);
1211 setHeaderDate(afsbase
, ah
->volume
, headerblock
, &ds
);
1213 seek(afsbase
, ah
, pos
, OFFSET_BEGINNING
, error
);