update copyright
[AROS.git] / rom / filesys / afs / filehandles1.c
blobc96f29b7293bf6d8ce59234e162ad4955435386b
1 /*
2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #undef DEBUG
7 #define DEBUG 0
9 #include "os.h"
10 #include "filehandles1.h"
11 #include "filehandles2.h"
12 #include "hashing.h"
13 #include "extstrings.h"
14 #include "checksums.h"
15 #include "bitmap.h"
16 #include "error.h"
17 #include "afsblocks.h"
18 #include "baseredef.h"
19 #include "validator.h"
21 /***********************************************
22 Name : getHeaderBlock
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,
35 CONST_STRPTR name,
36 struct BlockCache *blockbuffer,
37 ULONG *block,
38 SIPTR *error
41 ULONG key;
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;
49 return NULL;
51 blockbuffer=getBlock(afsbase, volume,OS_BE2LONG(blockbuffer->buffer[key]));
52 if (blockbuffer == NULL)
54 *error = ERROR_UNKNOWN;
55 return NULL;
60 char *name;
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;
75 return NULL;
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;
87 return NULL;
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;
97 return NULL;
99 blockbuffer=getBlock
101 afsbase,
102 volume,
103 OS_BE2LONG(blockbuffer->buffer[BLK_HASHCHAIN(volume)])
105 if (blockbuffer == NULL)
107 *error = ERROR_UNKNOWN;
108 return NULL;
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;
120 return NULL;
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;
131 return NULL;
134 return blockbuffer;
137 /*******************************************
138 Name : findBlock
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,
153 CONST_STRPTR name,
154 ULONG *block,
155 SIPTR *error
158 STRPTR pos;
159 struct BlockCache *blockbuffer;
160 UBYTE buffer[32];
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;
166 return 0;
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"));
177 return NULL;
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"));
190 return NULL;
192 if (OS_BE2LONG(blockbuffer->buffer[BLK_PRIMARY_TYPE]) != T_SHORT)
195 * read above comment
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"));
202 return NULL;
204 while (*name)
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"));
212 return NULL;
214 D(bug("[afs] findBlock: getting parent\n"));
215 blockbuffer = getBlock
217 afsbase,
218 dirah->volume,
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"));
225 return NULL;
227 name++;
229 else
231 if (
232 (OS_BE2LONG
234 blockbuffer->buffer[BLK_SECONDARY_TYPE(dirah->volume)]
235 ) != ST_ROOT) &&
236 (OS_BE2LONG
238 blockbuffer->buffer[BLK_SECONDARY_TYPE(dirah->volume)]
239 ) != ST_USERDIR) &&
240 (OS_BE2LONG
242 blockbuffer->buffer[BLK_SECONDARY_TYPE(dirah->volume)]
243 ) != ST_LINKDIR))
245 *error = ERROR_OBJECT_WRONG_TYPE;
246 D(bug("[afs] error wrong type\n"));
247 return NULL;
249 pos = buffer;
250 while ((*name != 0) && (*name != '/'))
252 *pos++ = *name++;
254 if (*name == '/')
255 name++;
256 *pos=0;
257 D(bug
259 "[afs] findBlock: searching for header block of %s\n",
260 buffer
262 blockbuffer =
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);
271 else
272 bug("[afs] findBlock: error\n");
274 return blockbuffer;
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;
293 else
294 old=ah->volume->locklist;
296 #ifdef __AROS__
297 else {
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)
300 if (ah->next)
301 ah->volumenode->dol_misc.dol_volume.dol_LockList = MKBADDR(ah->next);
302 else {
303 D(bug("[afs 0x%08lX] Last lock removed, removing VolumeNode\n", ah->volume));
304 remDosNode(afsbase, ah->volumenode);
306 else
307 old = BADDR(ah->volumenode->dol_misc.dol_volume.dol_LockList);
309 #endif
310 while (old)
312 if (old->next==ah)
314 old->next=ah->next;
315 return;
317 old=old->next;
321 /* find handle in locklist */
322 struct AfsHandle *findHandle(struct Volume *volume, ULONG block) {
323 struct AfsHandle *ah;
325 ah=volume->locklist;
326 while (ah)
328 if (ah->header_block==block)
329 return ah;
330 ah=ah->next;
332 return NULL;
335 /****************************************
336 Name : allocHandle
337 Descr.: allocate a new handle
338 Input : volume -
339 fileblock - block of the entry
340 mode - type of lock
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,
349 ULONG mode,
350 ULONG *hashtable,
351 SIPTR *error
354 struct AfsHandle *ah;
356 ah=(struct AfsHandle *)AllocMem
357 (sizeof(struct AfsHandle), MEMF_PUBLIC | MEMF_CLEAR);
358 if (ah != NULL)
360 ah->header_block = fileblock->blocknum;
361 ah->dirpos = fileblock->blocknum;
362 ah->mode = mode;
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)]);
368 ah->volume = volume;
369 ah->volumenode = volume->volumenode;
370 addHandle(ah);
372 else
373 *error = ERROR_NO_FREE_STORE;
374 return ah;
377 /****************************************
378 Name : getHandle
379 Descr.: check if a new handle can be
380 allocated and allocate one if
381 possible
382 Input : volume -
383 fileblock - block of the entry
384 mode - type of lock
385 Output: AfsHandle for success; NULL otherwise
386 ****************************************/
387 struct AfsHandle *getHandle
389 struct AFSBase *afsbase,
390 struct Volume *volume,
391 struct BlockCache *fileblock,
392 ULONG mode,
393 SIPTR *error
396 struct AfsHandle *ah;
398 D(bug
400 "[afs] getHandle: trying to get handle for block %lu\n",
401 fileblock->blocknum)
404 *error = 0;
406 ah = findHandle(volume, fileblock->blocknum);
407 if (ah != NULL)
409 if (ah->mode == MODE_READWRITE ||
410 ah->mode == MODE_NEWFILE)
412 *error = ERROR_OBJECT_IN_USE;
413 ah = NULL;
417 if (*error == 0)
419 ah = allocHandle
421 afsbase,
422 volume,
423 fileblock,
424 mode,
425 (ULONG *)((char *)fileblock->buffer+(BLK_TABLE_START*4)),
426 error
430 return ah;
433 /*****************************************
434 Name : openf
435 Descr.: open (lock) a file
436 Input : dirah - a handle filename is
437 relative to
438 filename - filename to lock
439 mode - lock type
440 Output: AfsHandle for success; NULL otherwise
441 ******************************************/
442 struct AfsHandle *openf
444 struct AFSBase *afsbase,
445 struct AfsHandle *dirah,
446 CONST_STRPTR filename,
447 ULONG mode,
448 SIPTR *error
451 struct AfsHandle *ah = NULL;
452 struct BlockCache *fileblock;
453 ULONG block;
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);
459 return ah;
462 /*****************************************
463 Name : openfile
464 Descr.: open (lock) a file
465 Input : dirah - a handle filename is
466 relative to
467 name - filename to lock
468 mode - MODE_...
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,
476 CONST_STRPTR name,
477 ULONG mode,
478 ULONG protection,
479 SIPTR *error
482 struct AfsHandle *ah = NULL;
483 struct BlockCache *fileblock, *dirblock;
484 UBYTE filename[34];
485 ULONG block;
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));
492 *error = 0;
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;
530 else
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,
551 * create a new one.
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);
560 else
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)
575 *error = 0;
576 ah = getHandle(afsbase, dirah->volume, fileblock, mode, error);
581 else
582 *error = ERROR_OBJECT_WRONG_TYPE;
584 return ah;
587 /***********************************
588 Name : closef
589 Descr.: close a file/free a lock
590 Input : ah - the handle to close
591 Output -
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 /******************************************
601 Name : readData
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
606 Output: read bytes
607 *******************************************/
608 LONG readData
610 struct AFSBase *afsbase,
611 struct AfsHandle *ah,
612 void *buffer,
613 ULONG length,
614 SIPTR *error
617 struct BlockCache *extensionbuffer;
618 struct BlockCache *databuffer;
619 UWORD size;
620 LONG readbytes=0;
621 char *source;
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;
634 return ENDSTREAMCH;
636 extensionbuffer->flags |= BCF_USED; /* don't overwrite that cache block! */
637 while (length != 0)
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)
647 ah->current.block=
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
663 else
664 if (length)
667 "Shit, out of extensionblocks!\n"
668 "Bytes left: %ld\n"
669 "Last extensionblock: %ld\n",
670 length,extensionbuffer->blocknum
674 D(bug
676 "[afs] readData: reading datablock %ld\n",
677 OS_BE2LONG(extensionbuffer->buffer[ah->current.filekey]))
679 databuffer = getBlock
681 afsbase,
682 ah->volume,
683 OS_BE2LONG(extensionbuffer->buffer[ah->current.filekey])
685 if (databuffer == 0)
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);
697 else
699 size = BLOCK_SIZE(ah->volume);
701 size -= ah->current.byte;
702 if (size > length)
704 size = length;
705 ah->current.byte += size;
707 else
709 ah->current.byte = 0;
710 ah->current.filekey--;
712 CopyMem((APTR)source, (APTR)((char *)buffer+readbytes),size);
713 length -= size;
714 readbytes += size;
716 extensionbuffer->flags &= ~BCF_USED;
717 return readbytes;
720 LONG readf
721 (struct AFSBase *afsbase, struct AfsHandle *ah, void *buffer, ULONG length, SIPTR *error)
723 LONG readbytes;
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;
729 return readbytes;
732 void newFileExtensionBlock
734 struct Volume *volume,
735 struct BlockCache *extension,
736 ULONG parent)
738 UWORD i;
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,
754 ULONG filekey,
755 ULONG next
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);
762 if (next != 0)
763 extension->buffer[BLK_EXTENSION(volume)] = OS_LONG2BE(next);
764 writeBlockDeferred(afsbase, volume, extension, BLK_CHECKSUM);
767 LONG writeData
769 struct AFSBase *afsbase,
770 struct AfsHandle *ah,
771 void *buffer,
772 ULONG length,
773 SIPTR *error
776 ULONG block = 0;
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;
782 char *destination;
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;
790 return ENDSTREAMCH;
792 extensionbuffer->flags |=BCF_USED; /* don't overwrite that cache block! */
793 while (length != 0)
795 /* save last data block for OFS data */
796 if (
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]);
802 D(bug
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;
824 else
826 D(bug("[afs] writeData: need new extensionblock\n"));
827 block = allocBlock(afsbase, ah->volume);
828 writeExtensionBlock
830 afsbase,
831 ah->volume,
832 extensionbuffer,
833 ah->current.filekey+1,
834 block
836 extensionbuffer->flags &= ~BCF_USED;
837 if (block == 0)
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? */
857 D(bug
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);
868 else
869 databuffer = getBlock(afsbase, ah->volume, block);
870 if (databuffer == NULL)
872 writeExtensionBlock
874 afsbase,
875 ah->volume,
876 extensionbuffer,
877 ah->current.filekey,
880 extensionbuffer->flags &= ~BCF_USED; //free that block
881 *error = ERROR_UNKNOWN;
882 return ENDSTREAMCH; //was writtenbytes;
885 else
887 extensionModified = TRUE;
888 D(bug("[afs] writeData: need a new datablock\n"));
889 block=allocBlock(afsbase, ah->volume);
890 if (block == 0)
892 writeExtensionBlock
894 afsbase,
895 ah->volume,
896 extensionbuffer,
897 ah->current.filekey,
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)
915 writeExtensionBlock
917 afsbase,
918 ah->volume,
919 extensionbuffer,
920 ah->current.filekey,
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)
933 writeExtensionBlock
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] =
945 OS_LONG2BE
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)
955 size -= (6*4);
956 destination += (BLK_DATA_START*4);
958 size -= ah->current.byte;
959 if (size > length)
961 size = length;
962 ah->current.byte += size;
964 else
966 ah->current.byte = 0;
967 ah->current.filekey--;
969 if (buffer != NULL)
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;
984 else
985 sumoffset = -1;
986 if (buffer != NULL || ah->volume->dosflags == 0)
987 writeBlock(afsbase, ah->volume, databuffer, sumoffset);
988 length -= size;
989 writtenbytes += size;
991 if (extensionModified)
993 writeExtensionBlock
995 afsbase,
996 ah->volume,
997 extensionbuffer,
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;
1007 LONG writef
1008 (struct AFSBase *afsbase, struct AfsHandle *ah, void *buffer, ULONG length, SIPTR *error)
1010 struct BlockCache *headerblock;
1011 LONG writtenbytes;
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;
1018 return 0;
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);
1037 DateStamp(&ds);
1038 setHeaderDate(afsbase, ah->volume, headerblock, &ds);
1041 validBitmap(afsbase, ah->volume);
1042 return writtenbytes;
1045 LONG seek
1046 (struct AFSBase* afsbase, struct AfsHandle *ah, LONG offset, LONG mode, SIPTR *error)
1048 LONG old = -1;
1049 UWORD filekey, byte;
1050 ULONG block, extblockindex, newextblockindex;
1051 UWORD blocksize, tablesize;
1052 ULONG newoffset;
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)
1063 if (offset == 0)
1065 *error = 0;
1066 return ah->current.offset;
1068 newoffset = ah->current.offset+offset;
1070 else if (mode == OFFSET_END)
1072 newoffset = ah->filesize+offset;
1074 else
1075 return -1;
1076 if ((signed)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))
1088 newextblockindex--;
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)
1095 extblockindex--;
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;
1101 else
1103 block = ah->header_block;
1104 extblockindex = 0;
1107 while ((extblockindex != newextblockindex) && (block != 0))
1109 blockbuffer = getBlock(afsbase, ah->volume, block);
1110 if (blockbuffer == NULL)
1111 return -1;
1112 block = OS_BE2LONG(blockbuffer->buffer[BLK_EXTENSION(ah->volume)]);
1113 extblockindex++;
1115 if (block != 0)
1117 *error = 0;
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;
1125 return old;
1128 LONG setFileSize
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;
1139 return -1;
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)
1147 newsize = 0;
1149 else if (mode == OFFSET_CURRENT)
1151 newsize = ah->current.offset;
1153 else if (mode == OFFSET_END)
1155 newsize = ah->filesize;
1157 else
1158 return -1;
1160 /* Ensure new length isn't negative */
1161 if (-size > newsize)
1163 return -1;
1165 newsize += size;
1167 /* Ensure there aren't any other filehandles positioned after the new
1168 length */
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)
1173 return -1;
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;
1191 return -1;
1194 else
1196 seek(afsbase, ah, newsize, OFFSET_BEGINNING, error);
1197 deleteFileRemainder(afsbase, ah);
1198 if (pos < newsize)
1199 pos = newsize;
1201 *error = 0;
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);
1210 DateStamp(&ds);
1211 setHeaderDate(afsbase, ah->volume, headerblock, &ds);
1213 seek(afsbase, ah, pos, OFFSET_BEGINNING, error);
1215 return newsize;