added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / workbench / devs / afs / filehandles1.c
blob5ee59069e39849feb1f157f594e7e8b188a65887
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /*
7 * -date------ -name------------------- -description-----------------------------
8 * 02-jan-2008 [Tomasz Wiszkowski] added disk validation
9 * 03-jan-2008 [Tomasz Wiszkowski] fixed procedures to allow validation prior to disk write
10 * 04-jan-2008 [Tomasz Wiszkowski] corrected tabulation
13 #undef DEBUG
14 #define DEBUG 0
16 #include "os.h"
17 #include "filehandles1.h"
18 #include "filehandles2.h"
19 #include "hashing.h"
20 #include "extstrings.h"
21 #include "checksums.h"
22 #include "bitmap.h"
23 #include "error.h"
24 #include "afsblocks.h"
25 #include "baseredef.h"
26 #include "validator.h"
28 extern ULONG error;
30 /***********************************************
31 Name : getHeaderBlock
32 Descr.: search through blocks until header block found
33 Input : name - object we are searching for
34 blockbuffer - dirblock we are searching in
35 block - will be filled with the block number
36 prior to the entry we are using
37 Output: cache block of last object
38 See : locateObject, setDate, setComment, deleteObject
39 ************************************************/
40 struct BlockCache *getHeaderBlock
42 struct AFSBase *afsbase,
43 struct Volume *volume,
44 STRPTR name,
45 struct BlockCache *blockbuffer,
46 ULONG *block
49 ULONG key;
51 D(bug("[afs] getHeaderBlock: searching for block of '%s'\n",name));
52 key = getHashKey(name,volume->SizeBlock-56,volume->dosflags)+BLK_TABLE_START;
53 *block = blockbuffer->blocknum;
54 if (blockbuffer->buffer[key] == 0)
56 error = ERROR_OBJECT_NOT_FOUND;
57 return NULL;
59 blockbuffer=getBlock(afsbase, volume,OS_BE2LONG(blockbuffer->buffer[key]));
60 if (blockbuffer == NULL)
62 error = ERROR_UNKNOWN;
63 return NULL;
68 char *name;
69 name = (char *)blockbuffer->buffer+(BLK_DIRECTORYNAME_START(volume)*4);
70 kprintf("[afs] %.*s\n", name[0], name+1);
73 if (calcChkSum(volume->SizeBlock, blockbuffer->buffer) != 0)
76 * since we will not work on blockbuffer here any more,
77 * we don't have to preserve it.
79 if (showError(afsbase, ERR_CHECKSUM, blockbuffer->blocknum))
80 launchValidator(afsbase, volume);
82 error = ERROR_UNKNOWN;
83 return NULL;
85 if (OS_BE2LONG(blockbuffer->buffer[BLK_PRIMARY_TYPE]) != T_SHORT)
88 * again, we don't work on blockbuffer any more
89 * no need to preserve BlockCache structure.
91 if (showError(afsbase, ERR_BLOCKTYPE, blockbuffer->blocknum))
92 launchValidator(afsbase, volume);
94 error = ERROR_OBJECT_WRONG_TYPE;
95 return NULL;
97 while (
98 !noCaseStrCmp
100 name,
101 (char *)
103 (ULONG)blockbuffer->buffer+
104 (BLK_DIRECTORYNAME_START(volume)*4)
106 volume->dosflags,
107 MAX_NAME_LENGTH
111 *block = blockbuffer->blocknum;
112 if (blockbuffer->buffer[BLK_HASHCHAIN(volume)] == 0)
114 error=ERROR_OBJECT_NOT_FOUND;
115 return NULL;
117 blockbuffer=getBlock
119 afsbase,
120 volume,
121 OS_BE2LONG(blockbuffer->buffer[BLK_HASHCHAIN(volume)])
123 if (blockbuffer == NULL)
125 error = ERROR_UNKNOWN;
126 return NULL;
128 if (calcChkSum(volume->SizeBlock, blockbuffer->buffer) != 0)
131 * we won't work on blockbuffer any more
132 * don't preserve the buffer.
134 if (showError(afsbase, ERR_CHECKSUM,blockbuffer->blocknum))
135 launchValidator(afsbase, volume);
137 error=ERROR_UNKNOWN;
138 return NULL;
140 if (OS_BE2LONG(blockbuffer->buffer[BLK_PRIMARY_TYPE]) != T_SHORT)
143 * not working with blockbuffer :)
145 if (showError(afsbase, ERR_BLOCKTYPE, blockbuffer->blocknum))
146 launchValidator(afsbase, volume);
148 error = ERROR_OBJECT_WRONG_TYPE;
149 return NULL;
152 return blockbuffer;
155 /*******************************************
156 Name : findBlock
157 Descr.: find the header block of a file/dir
158 Input : dirah - directory lock as starting point
159 if NULL, start in root dir
160 name - path of file/dir
161 block - will be filled with the block number
162 prior the entry we are using; rootblock
163 if we are searching for the root
164 Output: NULL=error (evtl. error=ERROR_...)
165 blockcache structure of found block otherwise
166 ********************************************/
167 struct BlockCache *findBlock
169 struct AFSBase *afsbase,
170 struct AfsHandle *dirah,
171 STRPTR name,
172 ULONG *block
175 STRPTR pos;
176 struct BlockCache *blockbuffer;
177 UBYTE buffer[32];
179 if (dirah->volume->dostype != 0x444F5300)
181 error = ERROR_NOT_A_DOS_DISK;
182 return 0;
184 *block = dirah->header_block;
186 D(bug("[afs] findBlock: startblock=%ld\n",*block));
187 /* get first entry (root or filelock refers to) */
188 blockbuffer = getBlock(afsbase, dirah->volume, *block);
189 if (blockbuffer == NULL)
191 error = ERROR_UNKNOWN;
192 D(bug("[afs] error blockbuffer\n"));
193 return NULL;
195 if (calcChkSum(dirah->volume->SizeBlock, blockbuffer->buffer) != 0)
198 * not working with blockbuffer any more.
199 * otherwise we would need to preserve it (BCF_USED or one more time getBlock)
201 if (showError(afsbase, ERR_CHECKSUM, *block))
202 launchValidator(afsbase, dirah->volume);
204 error = ERROR_UNKNOWN;
205 D(bug("[afs] error checksum\n"));
206 return NULL;
208 if (OS_BE2LONG(blockbuffer->buffer[BLK_PRIMARY_TYPE]) != T_SHORT)
211 * read above comment
213 if (showError(afsbase, ERR_BLOCKTYPE, *block))
214 launchValidator(afsbase, dirah->volume);
216 error = ERROR_OBJECT_WRONG_TYPE;
217 D(bug("[afs] error wrong type\n"));
218 return NULL;
220 while (*name)
222 if (*name == '/') /* get parent entry ? */
224 if (blockbuffer->buffer[BLK_PARENT(dirah->volume)] == 0)
226 error = ERROR_OBJECT_NOT_FOUND;
227 D(bug("[afs] object not found\n"));
228 return NULL;
230 D(bug("[afs] findBlock: getting parent\n"));
231 blockbuffer = getBlock
233 afsbase,
234 dirah->volume,
235 OS_BE2LONG(blockbuffer->buffer[BLK_PARENT(dirah->volume)])
237 if (blockbuffer == NULL)
239 error = ERROR_UNKNOWN;
240 D(bug("[afs] error no blockbuffer\n"));
241 return NULL;
243 name++;
245 else
247 if (
248 (OS_BE2LONG
250 blockbuffer->buffer[BLK_SECONDARY_TYPE(dirah->volume)]
251 ) != ST_ROOT) &&
252 (OS_BE2LONG
254 blockbuffer->buffer[BLK_SECONDARY_TYPE(dirah->volume)]
255 ) != ST_USERDIR) &&
256 (OS_BE2LONG
258 blockbuffer->buffer[BLK_SECONDARY_TYPE(dirah->volume)]
259 ) != ST_LINKDIR))
261 error = ERROR_OBJECT_WRONG_TYPE;
262 D(bug("[afs] error wrong type\n"));
263 return NULL;
265 pos = buffer;
266 while ((*name != 0) && (*name != '/'))
268 *pos++ = *name++;
270 if (*name == '/')
271 name++;
272 *pos=0;
273 D(bug
275 "[afs] findBlock: searching for header block of %s\n",
276 buffer
278 blockbuffer =
279 getHeaderBlock(afsbase, dirah->volume, buffer, blockbuffer, block);
280 if (blockbuffer == NULL)
281 break; /* object not found or other error */
285 if (blockbuffer != NULL)
286 bug("[afs] findBlock: block=%ld\n",blockbuffer->blocknum);
287 else
288 bug("[afs] findBlock: error\n");
290 return blockbuffer;
293 /* add handle to locklist */
294 void addHandle(struct AfsHandle *ah) {
296 ah->next=ah->volume->locklist;
297 ah->volume->locklist=ah;
300 /* remove handle from locklist */
301 void remHandle(struct AfsHandle *ah) {
302 struct AfsHandle *old;
304 if (ah->volume->locklist==ah)
305 ah->volume->locklist=ah->next;
306 else
308 old=ah->volume->locklist;
309 while (old)
311 if (old->next==ah)
313 old->next=ah->next;
314 return;
316 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 0;
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
353 struct AfsHandle *ah;
355 ah=(struct AfsHandle *)AllocMem
356 (sizeof(struct AfsHandle), MEMF_PUBLIC | MEMF_CLEAR);
357 if (ah != NULL)
359 ah->header_block = fileblock->blocknum;
360 ah->dirpos = fileblock->blocknum;
361 ah->mode = mode;
362 ah->current.block = fileblock->blocknum;
363 ah->current.filekey = BLK_TABLE_END(volume);
364 ah->current.byte = 0;
365 ah->current.offset = 0;
366 ah->filesize = OS_BE2LONG(fileblock->buffer[BLK_BYTE_SIZE(volume)]);
367 ah->volume = volume;
368 addHandle(ah);
370 else
371 error = ERROR_NO_FREE_STORE;
372 return ah;
375 /****************************************
376 Name : getHandle
377 Descr.: check if a new handle can be
378 allocated and allocate one if
379 possible
380 Input : volume -
381 fileblock - block of the entry
382 mode - type of lock
383 Output: AfsHandle for success; NULL otherwise
384 ****************************************/
385 struct AfsHandle *getHandle
387 struct AFSBase *afsbase,
388 struct Volume *volume,
389 struct BlockCache *fileblock,
390 ULONG mode
393 struct AfsHandle *ah;
395 D(bug
397 "[afs] getHandle: trying to get handle for block %lu\n",
398 fileblock->blocknum)
401 error = 0;
403 ah = findHandle(volume, fileblock->blocknum);
404 if (ah != NULL)
406 if (ah->mode & FMF_LOCK)
408 error = ERROR_OBJECT_IN_USE;
409 ah = NULL;
413 if (error == 0)
415 ah = allocHandle
417 afsbase,
418 volume,
419 fileblock,
420 mode,
421 (ULONG *)((char *)fileblock->buffer+(BLK_TABLE_START*4))
425 return ah;
428 /*****************************************
429 Name : openf
430 Descr.: open (lock) a file
431 Input : dirah - a handle filename is
432 relative to
433 filename - filename to lock
434 mode - lock type
435 Output: AfsHandle for success; NULL otherwise
436 ******************************************/
437 struct AfsHandle *openf
439 struct AFSBase *afsbase,
440 struct AfsHandle *dirah,
441 STRPTR filename,
442 ULONG mode
445 struct AfsHandle *ah = NULL;
446 struct BlockCache *fileblock;
447 ULONG block;
449 D(bug("[afs] openf(%ld,%s,%ld)\n",dirah->header_block,filename,mode));
450 fileblock = findBlock(afsbase, dirah, filename, &block);
451 if (fileblock != NULL)
452 ah = getHandle(afsbase, dirah->volume, fileblock, mode);
453 return ah;
456 /*****************************************
457 Name : openfile
458 Descr.: open (lock) a file
459 Input : dirah - a handle filename is
460 relative to
461 filename - filename to lock
462 mode - FMF_...
463 protection - bits for new files
464 Output: AfsHandle for success; NULL otherwise
465 ******************************************/
466 struct AfsHandle *openfile
468 struct AFSBase *afsbase,
469 struct AfsHandle *dirah,
470 STRPTR name,
471 ULONG mode,
472 ULONG protection
475 struct AfsHandle *ah = NULL;
476 struct BlockCache *fileblock, *dirblock;
477 UBYTE filename[34];
478 ULONG block;
479 ULONG dirblocknum;
480 ULONG fileblocknum = -1;
483 * nicely say what's going on
485 D(bug("[afs] openfile(%lu,%s,0x%lx,%lu)\n", dirah->header_block,name,mode,protection));
486 error = 0;
489 * if user wants to delete or create a new file - make sure we can do that.
491 if (((mode & FMF_CLEAR) || (mode & FMF_CREATE)) && (0 == checkValid(afsbase, dirah->volume)))
492 error = ERROR_DISK_WRITE_PROTECTED;
495 * get the directory the last component of "name" is in
497 dirblock = getDirBlockBuffer(afsbase, dirah, name, filename);
500 * if no error so far and directory block is found, move on.
502 if (error == 0 && dirblock != NULL)
505 * only if the directory is of DIR or ROOT type
507 if ((OS_BE2LONG(dirblock->buffer[BLK_SECONDARY_TYPE(dirah->volume)]) == ST_USERDIR) ||
508 (OS_BE2LONG(dirblock->buffer[BLK_SECONDARY_TYPE(dirah->volume)]) == ST_ROOT))
510 D(bug("[afs] parent of %s is on block %lu\n", name, dirblock->blocknum));
511 dirblocknum = dirblock->blocknum;
514 * get the header block of the file to open
516 fileblock = getHeaderBlock(afsbase, dirah->volume, filename, dirblock, &block);
519 * check if 'file' is really a FILE
521 if ((fileblock != NULL) && (OS_BE2LONG(fileblock->buffer[BLK_SECONDARY_TYPE(dirah->volume)])!=ST_FILE))
523 error = ERROR_OBJECT_WRONG_TYPE;
525 else
528 * get file block, if there was (is) a file
530 if (fileblock != NULL)
531 fileblocknum = fileblock->blocknum;
534 * remove existing file if we are asked to clear its contents
536 if (mode & FMF_CLEAR)
537 error = deleteObject(afsbase, dirah, name);
540 * if we cleared the file or there was no file at all, move on
542 if ((error == 0) || (error == ERROR_OBJECT_NOT_FOUND))
545 * in case we could not find existing file, or if we deleted this file previously,
546 * create a new one.
548 if ((mode & FMF_CREATE) && ((fileblock == NULL) || (mode & FMF_CLEAR)))
551 * please note that dirblock may become invalid here
553 fileblock = createNewEntry(afsbase, dirah->volume, ST_FILE, filename, dirblock, protection);
555 else
558 * we should already have fileblock here
559 * again, dirblock may become invalid here
561 if (fileblock != NULL)
562 fileblock = getBlock(afsbase, dirah->volume, fileblocknum);
566 * create a handle for the file
568 if (fileblock != NULL)
570 error = 0;
571 ah = getHandle(afsbase, dirah->volume, fileblock, mode);
576 else
577 error = ERROR_OBJECT_WRONG_TYPE;
579 return ah;
582 /***********************************
583 Name : closef
584 Descr.: close a file/free a lock
585 Input : ah - the handle to close
586 Output -
587 ************************************/
588 void closef(struct AFSBase *afsbase, struct AfsHandle *ah) {
590 D(bug("[afs] closef(%lu)\n",ah->header_block));
591 remHandle(ah);
592 FreeMem(ah,sizeof(struct AfsHandle));
595 /******************************************
596 Name : readData
597 Descr.: read data from file
598 Input : ah - handle (file) to read from
599 buffer - buffer to store data into
600 length - size of data to read
601 Output: read bytes
602 *******************************************/
603 LONG readData
605 struct AFSBase *afsbase,
606 struct AfsHandle *ah,
607 void *buffer,
608 ULONG length
611 struct BlockCache *extensionbuffer;
612 struct BlockCache *databuffer;
613 UWORD size;
614 LONG readbytes=0;
615 char *source;
617 if (ah->current.block == 0)
618 return 0; /* we can't read beyond EOF so return EOF */
619 if (length > (ah->filesize-ah->current.offset))
621 length = ah->filesize-ah->current.offset; /* we can't read more bytes than left in file! */
623 D(bug("[afs] readData: offset=%ld\n", ah->current.offset));
624 extensionbuffer = getBlock(afsbase, ah->volume, ah->current.block);
625 if (extensionbuffer == NULL)
627 error = ERROR_UNKNOWN;
628 return ENDSTREAMCH;
630 extensionbuffer->flags |= BCF_USED; /* don't overwrite that cache block! */
631 while (length != 0)
633 D(bug("[afs] readData: bytes left=%ld\n",length));
635 block, filekey always point to the next block
636 so update them if we have read a whole block
638 /* do we have to read next extension block? */
639 if (ah->current.filekey<BLK_TABLE_START)
641 ah->current.block=
642 OS_BE2LONG(extensionbuffer->buffer[BLK_EXTENSION(ah->volume)]);
643 ah->current.filekey = BLK_TABLE_END(ah->volume);
644 extensionbuffer->flags &= ~BCF_USED; //we can now overwrite that cache block
645 D(bug("[afs] readData: reading extensionblock=%ld\n",ah->current.block));
646 if (ah->current.block != 0)
648 extensionbuffer = getBlock(afsbase, ah->volume,ah->current.block);
649 if (extensionbuffer == 0)
651 error = ERROR_UNKNOWN;
652 return ENDSTREAMCH; //was readbytes;
654 extensionbuffer->flags |= BCF_USED; //don't overwrite this cache block
657 else
658 if (length)
661 "Shit, out of extensionblocks!\n"
662 "Bytes left: %ld\n"
663 "Last extensionblock: %ld\n",
664 length,extensionbuffer->blocknum
668 D(bug
670 "[afs] readData: reading datablock %ld\n",
671 OS_BE2LONG(extensionbuffer->buffer[ah->current.filekey]))
673 databuffer = getBlock
675 afsbase,
676 ah->volume,
677 OS_BE2LONG(extensionbuffer->buffer[ah->current.filekey])
679 if (databuffer == 0)
681 extensionbuffer->flags &= ~BCF_USED; //free that block
682 error = ERROR_UNKNOWN;
683 return ENDSTREAMCH; //was readbytes;
685 source = (char *)databuffer->buffer+ah->current.byte;
686 if (ah->volume->dosflags == 0)
688 size = OS_BE2LONG(databuffer->buffer[BLK_DATA_SIZE]);
689 source += (BLK_DATA_START*4);
691 else
693 size = BLOCK_SIZE(ah->volume);
695 size -= ah->current.byte;
696 if (size > length)
698 size = length;
699 ah->current.byte += size;
701 else
703 ah->current.byte = 0;
704 ah->current.filekey--;
706 CopyMem((APTR)source, (APTR)((char *)buffer+readbytes),size);
707 length -= size;
708 readbytes += size;
710 extensionbuffer->flags &= ~BCF_USED;
711 return readbytes;
714 LONG readf
715 (struct AFSBase *afsbase, struct AfsHandle *ah, void *buffer, ULONG length)
717 LONG readbytes;
719 D(bug("[afs] read(%ld,buffer,%ld)\n", ah->header_block, length));
720 readbytes = readData(afsbase, ah,buffer,length);
721 if (readbytes != ENDSTREAMCH)
722 ah->current.offset = ah->current.offset+readbytes;
723 return readbytes;
726 void newFileExtensionBlock
728 struct Volume *volume,
729 struct BlockCache *extension,
730 ULONG parent)
732 UWORD i;
734 extension->buffer[BLK_PRIMARY_TYPE] = OS_LONG2BE(T_LIST);
735 extension->buffer[BLK_OWN_KEY ] = OS_LONG2BE(extension->blocknum);
736 for (i=2; i<BLK_PARENT(volume); i++)
737 extension->buffer[i] = 0;
738 extension->buffer[BLK_PARENT(volume)] = OS_LONG2BE(parent);
739 extension->buffer[BLK_EXTENSION(volume)] = 0;
740 extension->buffer[BLK_SECONDARY_TYPE(volume)] = OS_LONG2BE(ST_FILE);
743 void writeExtensionBlock
745 struct AFSBase *afsbase,
746 struct Volume *volume,
747 struct BlockCache *extension,
748 ULONG filekey,
749 ULONG next
752 ULONG newcount = BLK_TABLE_END(volume)-(filekey-1);
754 if (OS_BE2LONG(extension->buffer[BLK_BLOCK_COUNT]) < newcount)
755 extension->buffer[BLK_BLOCK_COUNT] = OS_LONG2BE(newcount);
756 if (next != 0)
757 extension->buffer[BLK_EXTENSION(volume)] = OS_LONG2BE(next);
758 writeBlockDeferred(afsbase, volume, extension, BLK_CHECKSUM);
761 LONG writeData
763 struct AFSBase *afsbase,
764 struct AfsHandle *ah,
765 void *buffer,
766 ULONG length
769 ULONG block = 0;
770 ULONG lastblock = 0; /* 0 means: don't update BLK_NEXT_DATA */
771 struct BlockCache *extensionbuffer = NULL;
772 struct BlockCache *databuffer = NULL;
773 UWORD size, blockCapacity;
774 LONG writtenbytes = 0, sumoffset;
775 char *destination;
776 BOOL extensionModified = FALSE;
778 D(bug("[afs] writeData: offset=%ld\n", ah->current.offset));
779 extensionbuffer = getBlock(afsbase, ah->volume, ah->current.block);
780 if (extensionbuffer == NULL)
782 error = ERROR_UNKNOWN;
783 return ENDSTREAMCH;
785 extensionbuffer->flags |=BCF_USED; /* don't overwrite that cache block! */
786 while (length != 0)
788 /* save last data block for OFS data */
789 if (
790 (ah->current.byte==0) && /* last block fully written */
791 (ah->current.filekey!=BLK_TABLE_END(ah->volume)) /* this is not the first block of the file */
794 lastblock = OS_BE2LONG(extensionbuffer->buffer[ah->current.filekey+1]);
795 D(bug
796 ("[afs] writeData: for OFS last datablock was %lu\n", lastblock));
799 block, filekey always point to the last block
800 so update them if we have read a whole block
802 /* read next extension block? */
803 if (ah->current.filekey < BLK_TABLE_START)
805 extensionModified = FALSE;
806 if (extensionbuffer->buffer[BLK_EXTENSION(ah->volume)] != 0)
808 block = OS_BE2LONG(extensionbuffer->buffer[BLK_EXTENSION(ah->volume)]);
809 extensionbuffer->flags &= ~BCF_USED;
810 extensionbuffer = getBlock(afsbase, ah->volume, block);
811 if (extensionbuffer == NULL)
813 error = ERROR_UNKNOWN;
814 return ENDSTREAMCH; // was writtenbytes;
817 else
819 D(bug("[afs] writeData: need new extensionblock\n"));
820 block = allocBlock(afsbase, ah->volume);
821 writeExtensionBlock
823 afsbase,
824 ah->volume,
825 extensionbuffer,
826 ah->current.filekey+1,
827 block
829 extensionbuffer->flags &= ~BCF_USED;
830 if (block == 0)
832 error = ERROR_NO_FREE_STORE;
833 return ENDSTREAMCH; /* was writtenbytes; */
835 extensionbuffer = getFreeCacheBlock(afsbase, ah->volume,block);
836 if (extensionbuffer == NULL)
838 error = ERROR_UNKNOWN;
839 return ENDSTREAMCH; /* was writtenbytes; */
841 newFileExtensionBlock(ah->volume,extensionbuffer, ah->header_block);
843 ah->current.filekey = BLK_TABLE_END(ah->volume);
844 extensionbuffer->flags |= BCF_USED; /* don't overwrite this cache block */
845 ah->current.block = block;
847 /* find a block to write data into */
848 if (extensionbuffer->buffer[ah->current.filekey] != 0) /* do we already have that block? */
850 D(bug
852 "[afs] writeData: using old datablock %lu\n",
853 OS_BE2LONG(extensionbuffer->buffer[ah->current.filekey]))
855 /* Only get the block's old contents if some of it won't be overwritten
856 (except for OFS or a final, partially-used block) */
857 block = OS_BE2LONG(extensionbuffer->buffer[ah->current.filekey]);
858 if ((ah->current.byte == 0) && (length >= BLOCK_SIZE(ah->volume))
859 && (ah->volume->dosflags != 0))
860 databuffer = getFreeCacheBlock(afsbase, ah->volume, block);
861 else
862 databuffer = getBlock(afsbase, ah->volume, block);
863 if (databuffer == NULL)
865 writeExtensionBlock
867 afsbase,
868 ah->volume,
869 extensionbuffer,
870 ah->current.filekey,
873 extensionbuffer->flags &= ~BCF_USED; //free that block
874 error = ERROR_UNKNOWN;
875 return ENDSTREAMCH; //was writtenbytes;
878 else
880 extensionModified = TRUE;
881 D(bug("[afs] writeData: need a new datablock\n"));
882 block=allocBlock(afsbase, ah->volume);
883 if (block == 0)
885 writeExtensionBlock
887 afsbase,
888 ah->volume,
889 extensionbuffer,
890 ah->current.filekey,
893 extensionbuffer->flags &= ~BCF_USED;
894 error = ERROR_NO_FREE_STORE;
895 return ENDSTREAMCH; //was writtenbytes;
897 extensionbuffer->buffer[ah->current.filekey] = OS_LONG2BE(block);
898 if ((ah->volume->dosflags==0) && (lastblock != 0))
900 D(bug("[afs] writeData: OFS->fill in %ld BLK_NEXT_DATA\n",lastblock));
902 we allocated a new block
903 so there MUST be an initialized lastblock
905 databuffer = getBlock(afsbase, ah->volume,lastblock);
906 if (databuffer == NULL)
908 writeExtensionBlock
910 afsbase,
911 ah->volume,
912 extensionbuffer,
913 ah->current.filekey,
916 extensionbuffer->flags &= ~BCF_USED; //free that block
917 error = ERROR_UNKNOWN;
918 return ENDSTREAMCH; //was writtenbytes;
920 databuffer->buffer[BLK_NEXT_DATA] = OS_LONG2BE(block);
921 writeBlock(afsbase, ah->volume,databuffer, BLK_CHECKSUM);
923 databuffer = getFreeCacheBlock(afsbase, ah->volume,block);
924 if (databuffer == NULL)
926 writeExtensionBlock
927 (afsbase, ah->volume, extensionbuffer, ah->current.filekey, 0);
928 extensionbuffer->flags &= ~BCF_USED; //free that block
929 error = ERROR_UNKNOWN;
930 return ENDSTREAMCH; //was writtenbytes;
932 if (ah->volume->dosflags == 0)
934 databuffer->buffer[BLK_PRIMARY_TYPE] = OS_LONG2BE(T_DATA);
935 databuffer->buffer[BLK_HEADER_KEY] = OS_LONG2BE(ah->header_block);
936 blockCapacity = (ah->volume->SizeBlock-BLK_DATA_START)*sizeof(ULONG);
937 databuffer->buffer[BLK_SEQUENCE_NUMBER] =
938 OS_LONG2BE
939 (((ah->current.offset+writtenbytes)/blockCapacity)+1);
940 databuffer->buffer[BLK_DATA_SIZE] = 0;
941 databuffer->buffer[BLK_NEXT_DATA] = 0;
944 destination = (char *)databuffer->buffer+ah->current.byte;
945 size = BLOCK_SIZE(ah->volume);
946 if (ah->volume->dosflags == 0)
948 size -= (6*4);
949 destination += (BLK_DATA_START*4);
951 size -= ah->current.byte;
952 if (size > length)
954 size = length;
955 ah->current.byte += size;
957 else
959 ah->current.byte = 0;
960 ah->current.filekey--;
962 CopyMem((APTR)((char *)buffer+writtenbytes),(APTR)destination,size);
963 if (ah->volume->dosflags == 0)
965 if (ah->current.byte == 0)
967 databuffer->buffer[BLK_DATA_SIZE] =
968 OS_LONG2BE(BLOCK_SIZE(ah->volume)-(6*4));
970 else if (OS_BE2LONG(databuffer->buffer[BLK_DATA_SIZE]) < ah->current.byte)
972 databuffer->buffer[BLK_DATA_SIZE] = OS_LONG2BE(ah->current.byte);
974 sumoffset = BLK_CHECKSUM;
976 else
977 sumoffset = -1;
978 writeBlock(afsbase, ah->volume, databuffer, sumoffset);
979 length -= size;
980 writtenbytes += size;
982 if (extensionModified)
984 writeExtensionBlock
986 afsbase,
987 ah->volume,
988 extensionbuffer,
989 ah->current.byte==0 ? ah->current.filekey+1 : ah->current.filekey,
993 extensionbuffer->flags &= ~BCF_USED;
994 D(bug("[afs] writeData=%ld\n", writtenbytes));
995 return writtenbytes;
998 LONG writef
999 (struct AFSBase *afsbase, struct AfsHandle *ah, void *buffer, ULONG length)
1001 struct BlockCache *headerblock;
1002 LONG writtenbytes;
1003 struct DateStamp ds;
1005 D(bug("[afs] write(ah,buffer,%ld)\n", length));
1006 if (0 == checkValid(afsbase, ah->volume))
1008 error = ERROR_DISK_WRITE_PROTECTED;
1009 return 0;
1012 invalidBitmap(afsbase, ah->volume);
1013 writtenbytes = writeData(afsbase, ah, buffer, length);
1014 if (writtenbytes != ENDSTREAMCH)
1016 ah->current.offset += writtenbytes;
1017 headerblock = getBlock(afsbase, ah->volume,ah->header_block);
1018 if (headerblock != NULL)
1020 headerblock->buffer[BLK_FIRST_DATA] =
1021 headerblock->buffer[BLK_TABLE_END(ah->volume)];
1022 if (ah->current.offset > ah->filesize)
1024 ah->filesize = ah->current.offset;
1025 headerblock->buffer[BLK_BYTE_SIZE(ah->volume)] =
1026 OS_LONG2BE(ah->filesize);
1028 DateStamp(&ds);
1029 setHeaderDate(afsbase, ah->volume, headerblock, &ds);
1032 validBitmap(afsbase, ah->volume);
1033 return writtenbytes;
1036 LONG seek
1037 (struct AFSBase* afsbase, struct AfsHandle *ah, LONG offset, LONG mode)
1039 LONG old = -1;
1040 UWORD filekey, byte;
1041 ULONG block, extblockindex, newextblockindex;
1042 UWORD blocksize, tablesize;
1043 ULONG newoffset;
1044 struct BlockCache *blockbuffer;
1046 D(bug("[afs] seek(%ld,%ld,%ld)\n", ah->header_block, offset, mode));
1047 error = ERROR_SEEK_ERROR;
1048 if (mode == OFFSET_BEGINNING)
1050 newoffset = (ULONG)offset;
1052 else if (mode == OFFSET_CURRENT)
1054 if (offset == 0)
1056 error = 0;
1057 return ah->current.offset;
1059 newoffset = ah->current.offset+offset;
1061 else if (mode == OFFSET_END)
1063 newoffset = ah->filesize+offset;
1065 else
1066 return -1;
1067 if (newoffset >= 0)
1069 blocksize = BLOCK_SIZE(ah->volume);
1070 if (ah->volume->dosflags == 0)
1071 blocksize -= (BLK_DATA_START*4);
1072 newextblockindex = newoffset / blocksize;
1073 tablesize = BLK_TABLE_END(ah->volume)-BLK_TABLE_START+1; /* hashtable size */
1074 filekey = BLK_TABLE_END(ah->volume)-(newextblockindex % tablesize);
1075 newextblockindex /= tablesize; /* # of extensionblock we need */
1076 byte = newoffset % blocksize;
1078 /* Get index of current extension block */
1079 extblockindex = (ah->current.offset / blocksize) / tablesize;
1080 if (ah->current.filekey<BLK_TABLE_START)
1081 extblockindex--;
1083 /* Start at current extension block, unless we have to go back to
1084 a previous extension block */
1085 if (newextblockindex >= extblockindex)
1086 block = ah->current.block;
1087 else
1089 block = ah->header_block;
1090 extblockindex = 0;
1093 while ((extblockindex != newextblockindex) && (block != 0))
1095 blockbuffer = getBlock(afsbase, ah->volume, block);
1096 if (blockbuffer == NULL)
1097 return -1;
1098 block = OS_BE2LONG(blockbuffer->buffer[BLK_EXTENSION(ah->volume)]);
1099 extblockindex++;
1101 if (block != 0)
1103 error = 0;
1104 old = ah->current.offset;
1105 ah->current.block = block;
1106 ah->current.filekey = filekey;
1107 ah->current.byte = byte;
1108 ah->current.offset = newoffset;
1111 return old;
1114 /* vim: set noet ts=3 ai fdm=marker fmr={,} :*/