5 Copyright (C) 2001-2008 Neil Cafferkey
7 This file is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
12 This file is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this file; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 #include "handler_protos.h"
28 static struct Block
*AddDataBlock(struct Handler
*handler
,
29 struct Object
*file
, UPINT length
);
30 static VOID
FreeDataBlock(struct Handler
*handler
, struct Object
*file
,
32 static struct Block
*GetLastBlock(struct Object
*file
);
36 /****i* ram.handler/DeleteHandler ******************************************
42 * DeleteHandler(handler)
44 * VOID DeleteHandler(struct Handler *);
60 ****************************************************************************
64 VOID
DeleteHandler(struct Handler
*handler
)
66 struct DosList
*volume
;
67 struct Object
*root_dir
;
68 struct Lock
*root_lock
;
73 root_dir
= handler
->root_dir
;
77 root_lock
= root_dir
->lock
;
79 CmdFreeLock(handler
, root_lock
);
80 DeleteObject(handler
, root_dir
);
83 volume
= handler
->volume
;
87 MyFreeDosEntry(handler
, volume
);
90 DeletePool(handler
->public_pool
);
91 DeletePool(handler
->muddy_pool
);
92 DeletePool(handler
->clear_pool
);
94 DeleteMsgPort(handler
->notify_port
);
101 CloseLocale(handler
->locale
);
109 FreeMem(handler
, sizeof(struct Handler
));
117 /****i* ram.handler/CreateObject *******************************************
123 * object = CreateObject(handler, name, type,
126 * struct Object *CreateObject(struct Handler *, TEXT *, BYTE,
130 * Creates a new filesystem object. The existence of a duplicate object
131 * must be checked for beforehand.
134 * name - The name of the new object, without a path prefixed.
135 * type - The type of object to create.
136 * parent - The new object's parent directory, or NULL for none.
139 * object - The newly created object, or NULL for failure.
149 ****************************************************************************
153 struct Object
*CreateObject(struct Handler
*handler
, const TEXT
*name
,
154 BYTE type
, struct Object
*parent
)
156 struct Object
*object
= NULL
;
159 /* Get the real parent in case it's a hard link */
162 parent
= GetRealObject(parent
);
164 /* Create a new object structure */
166 object
= AllocPooled(handler
->clear_pool
, sizeof(struct Object
));
168 error
= ERROR_DISK_FULL
;
172 object
->block_count
= MEMBLOCKS(sizeof(struct Object
));
173 handler
->block_count
+= MEMBLOCKS(sizeof(struct Object
));
175 NewList((struct List
*)&object
->elements
);
176 ((struct Node
*)object
)->ln_Pri
= type
;
177 object
->parent
= parent
;
178 DateStamp(&object
->date
);
179 NewList((struct List
*)&object
->notifications
);
182 AddTail((APTR
)&object
->elements
, (APTR
)&object
->start_block
);
186 if(!SetName(handler
, object
, name
))
192 AddTail((struct List
*)&parent
->elements
, (struct Node
*)object
);
193 CopyMem(&object
->date
, &parent
->date
, sizeof(struct DateStamp
));
198 MatchNotifyRequests(handler
);
202 DeleteObject(handler
, object
);
206 /* Return the new object */
214 /****i* ram.handler/AttemptDeleteObject ************************************
217 * AttemptDeleteObject -- Attempt to delete an object.
220 * success = AttemptDeleteObject(handler, object)
222 * BOOL AttemptDeleteObject(struct Handler *, struct Object *);
225 * Attempts to delete the specified object. Note that this function
226 * does not check permissions.
229 * object - the object to be deleted, or NULL for no action.
232 * success - success indicator.
242 ****************************************************************************
246 BOOL
AttemptDeleteObject(struct Handler
*handler
, struct Object
*object
,
254 /* Check for a non-empty, unlinked directory */
256 object_type
= ((struct Node
*)object
)->ln_Pri
;
257 if(object_type
== ST_USERDIR
&& object
->hard_link
.mln_Succ
== NULL
258 && !IsListEmpty(&object
->elements
))
259 error
= ERROR_DIRECTORY_NOT_EMPTY
;
261 /* Ensure the object either isn't in use or is only a link */
263 if(object
->lock
!= NULL
)
264 error
= ERROR_OBJECT_IN_USE
;
266 /* Delete object and notify anyone who's interested */
271 NotifyAll(handler
, object
, FALSE
);
272 UnmatchNotifyRequests(handler
, object
);
273 AdjustExaminations(handler
, object
);
274 DeleteObject(handler
, object
);
286 /****i* ram.handler/DeleteObject *******************************************
292 * success = DeleteObject(handler, object)
294 * BOOL DeleteObject(struct Handler *, struct Object *);
299 * object - the object to be deleted, or NULL for no action.
312 ****************************************************************************
316 VOID
DeleteObject(struct Handler
*handler
, struct Object
*object
)
320 struct MinNode
*node
;
321 struct Object
*real_object
, *master_link
, *heir
;
326 object_type
= ((struct Node
*)object
)->ln_Pri
;
327 real_object
= GetRealObject(object
);
329 /* Remove the object from its directory */
331 if(object
->parent
!= NULL
)
332 Remove((struct Node
*)object
);
334 /* Delete a hard link */
336 if(object_type
== ST_LINKFILE
|| object_type
== ST_LINKDIR
)
338 node
= real_object
->hard_link
.mln_Succ
;
339 master_link
= HARDLINK(node
);
340 node
= node
->mln_Succ
;
341 Remove((APTR
)&object
->hard_link
);
342 if(object
== master_link
)
344 if(node
->mln_Succ
!= NULL
)
346 master_link
= HARDLINK(node
);
347 while((node
= (APTR
)RemHead((APTR
)&object
->elements
))
349 AddTail((APTR
)&master_link
->elements
, (APTR
)node
);
353 real_object
->hard_link
.mln_Succ
= NULL
;
354 real_object
->hard_link
.mln_Pred
= NULL
;
359 /* Delete a linked object */
361 else if((node
= object
->hard_link
.mln_Succ
) != NULL
)
363 master_link
= HARDLINK(node
);
364 heir
= HARDLINK(RemTail((APTR
)&master_link
->elements
));
366 /* Swap names and comments */
368 block_diff
= SwapStrings((TEXT
**)&((struct Node
*)heir
)->ln_Name
,
369 (TEXT
**)&((struct Node
*)object
)->ln_Name
);
370 block_diff
+= SwapStrings(&heir
->comment
, &object
->comment
);
371 object
->block_count
+= block_diff
;
372 heir
->block_count
-= block_diff
;
374 /* Put object in its new directory */
376 object
->parent
= heir
->parent
;
377 AddTail((APTR
)&object
->parent
->elements
, (APTR
)object
);
379 if(heir
== master_link
)
381 real_object
->hard_link
.mln_Succ
= NULL
;
382 real_object
->hard_link
.mln_Pred
= NULL
;
385 /* Prepare to destroy "heir" link */
391 /* Delete an unlinked object */
395 /* Remove all blocks if the object is a file */
397 while((block
= (APTR
)RemTail((struct List
*)&object
->elements
))
400 if(block
->length
!= 0)
401 FreePooled(handler
->muddy_pool
, block
,
402 sizeof(struct Block
) + block
->length
);
406 /* Free object's memory */
408 SetString(handler
, (TEXT
**)&((struct Node
*)object
)->ln_Name
, NULL
);
409 SetString(handler
, &object
->comment
, NULL
);
410 handler
->block_count
-= object
->block_count
;
411 FreePooled(handler
->clear_pool
, object
, sizeof(struct Object
));
419 /****i* ram.handler/GetHardObject ******************************************
422 * GetHardObject -- Find a non-soft-link object given a lock and path.
425 * object = GetHardObject(handler, lock, name,
428 * struct Object *GetHardObject(struct Handler *, struct Lock *, TEXT *,
432 * Looks for the object corresponding to the specified lock and path
433 * combination. If any part of the path is a soft link, NULL is returned
434 * and the appropriate error code is set.
439 * parent - parent directory will be returned here (will be NULL if
440 * path is invalid or contains a soft link).
443 * object - The located object, or NULL if not found.
453 ****************************************************************************
457 struct Object
*GetHardObject(struct Handler
*handler
, struct Lock
*lock
,
458 const TEXT
*name
, struct Object
**parent
)
460 struct Object
*object
;
462 object
= GetObject(handler
, lock
, name
, parent
, NULL
);
463 if(IoErr() == ERROR_IS_SOFT_LINK
)
470 /****i* ram.handler/GetObject **********************************************
473 * GetObject -- Find an object given a lock and path.
476 * object = GetObject(handler, lock, name,
477 * parent, remainder_pos)
479 * struct Object *GetObject(struct Handler *, struct Lock *, TEXT *,
480 * struct Object **, LONG *);
483 * Looks for the object corresponding to the specified lock and path
484 * combination. If any part of the path is a soft link, the link object
485 * is returned and ERROR_IS_SOFT_LINK is set. IoErr() will be zero if a
486 * hard object is returned.
491 * parent - parent directory will be returned here (will be NULL if
492 * path is invalid or contains a soft link).
495 * object - The located object, or NULL if not found.
505 ****************************************************************************
509 struct Object
*GetObject(struct Handler
*handler
, struct Lock
*lock
,
510 const TEXT
*name
, struct Object
**parent
, LONG
*remainder_pos
)
513 TEXT ch
, buffer
[MAX_NAME_SIZE
+ 1];
514 LONG error
= 0, pos
= 0;
515 struct Object
*object
, *old_object
;
517 /* Skip device name */
519 for(ch
= *(p
= name
); ch
!= ':' && ch
!= '\0'; ch
= *(++p
));
523 /* Get object referenced by lock */
525 lock
= FIXLOCK(handler
, lock
);
526 object
= (APTR
)((struct FileLock
*)lock
)->fl_Key
;
527 old_object
= object
->parent
;
529 /* Traverse textual portion of path */
531 while(pos
!= -1 && error
== 0)
533 pos
= SplitName(name
, '/', buffer
, pos
, MAX_NAME_SIZE
);
536 if(((struct Node
*)object
)->ln_Pri
> 0)
539 object
= GetRealObject(object
);
540 object
= (struct Object
*)
541 FindNameNoCase(handler
, (struct List
*)&object
->elements
, buffer
);
544 /* Check for and handle a soft link */
546 if(((struct Node
*)object
)->ln_Pri
== ST_SOFTLINK
)
548 if(remainder_pos
!= NULL
)
549 *remainder_pos
= pos
;
550 error
= ERROR_IS_SOFT_LINK
;
554 error
= ERROR_OBJECT_NOT_FOUND
;
558 error
= ERROR_OBJECT_NOT_FOUND
;
565 object
= object
->parent
;
567 error
= ERROR_OBJECT_NOT_FOUND
;
571 /* Record the parent directory of the supplied path, if it exists */
575 if(pos
== -1 && error
!= ERROR_IS_SOFT_LINK
)
576 *parent
= old_object
;
581 /* Return the located object */
589 /****i* ram.handler/ChangeFileSize *****************************************
595 * new_size = ChangeFileSize(handler, opening, offset,
598 * PINT ChangeFileSize(struct Handler *, struct Opening *, PINT,
602 * If there is not enough space for the requested size, the file size
603 * will remain at its initial value and -1 will be returned.
617 ****************************************************************************
621 PINT
ChangeFileSize(struct Handler
*handler
, struct Opening
*opening
,
622 PINT offset
, LONG mode
)
624 PINT length
, new_length
, remainder
, end_length
, full_length
;
625 UPINT diff
, old_pos
, block_count
;
626 struct Block
*block
, *end_block
;
629 struct MinList
*openings
;
630 struct Opening
*tail
;
634 file
= opening
->file
;
636 if(mode
== OFFSET_BEGINNING
)
638 else if(mode
== OFFSET_CURRENT
)
639 new_length
= opening
->pos
;
641 new_length
= file
->length
;
643 /* Check new size won't be negative */
645 if(-offset
> new_length
)
647 SetIoErr(ERROR_SEEK_ERROR
);
653 new_length
+= offset
;
654 length
= file
->length
;
655 block_count
= file
->block_count
;
657 /* Get full length (including any unused area in last block) */
659 old_pos
= opening
->pos
;
660 full_length
= length
;
661 end_length
= file
->end_length
;
663 block
= GetLastBlock(file
);
664 full_length
+= block
->length
- end_length
;
668 if(new_length
> length
)
670 /* Add the required number of data bytes */
672 remainder
= new_length
- full_length
;
673 end_length
-= remainder
;
677 block
= AddDataBlock(handler
, file
, remainder
);
680 end_length
= remainder
;
681 remainder
-= block
->length
;
687 /* Remove new blocks upon failure */
693 ChangeFileSize(handler
, opening
, length
, OFFSET_BEGINNING
);
696 file
->end_length
= end_length
;
698 else if(length
!= new_length
)
700 /* Remove surplus blocks from the file */
703 while(full_length
> new_length
)
705 FreeDataBlock(handler
, file
, block
);
706 block
= (APTR
)RemTail((APTR
)&file
->elements
);
707 full_length
-= block
->length
;
709 end_block
= (APTR
)file
->elements
.mlh_TailPred
;
710 file
->end_length
= end_length
= end_block
->length
;
712 /* Allocate a suitably sized end block and copy old data to it */
714 diff
= new_length
- full_length
;
715 file
->length
= full_length
;
716 CmdSeek(handler
, opening
, 0, OFFSET_END
);
718 if(ChangeFileSize(handler
, opening
, diff
, OFFSET_END
) != -1)
720 WriteData(handler
, opening
,
721 ((UBYTE
*)block
) + sizeof(struct Block
), diff
);
722 FreeDataBlock(handler
, file
, block
);
725 AddTail((struct List
*)&file
->elements
, (APTR
)block
);
728 /* Store new file size */
731 file
->length
= new_length
;
732 handler
->block_count
+= file
->block_count
- block_count
;
734 /* Re-establish old seek position */
736 opening
->pos
= old_pos
;
738 /* Adjust all openings for this file to ensure that their position isn't
739 past the new EOF and that their block and block position are valid */
741 openings
= &file
->lock
->openings
;
742 opening
= (APTR
)openings
->mlh_Head
;
743 tail
= (APTR
)&openings
->mlh_Tail
;
745 while(opening
!= tail
)
747 if(opening
->pos
> file
->length
)
749 opening
->pos
= file
->length
;
751 CmdSeek(handler
, opening
, opening
->pos
, OFFSET_BEGINNING
);
752 opening
= (APTR
)((struct MinNode
*)opening
)->mln_Succ
;
761 /****i* ram.handler/ReadData ***********************************************
767 * read_length = ReadData(opening, buffer, length)
769 * UPINT ReadData(struct Opening *, UBYTE *, UPINT);
785 ****************************************************************************
789 UPINT
ReadData(struct Opening
*opening
, UBYTE
*buffer
, UPINT length
)
792 UPINT block_pos
, block_length
, read_length
= 0, remainder
;
795 /* Fill buffer until request has been fulfilled or EOF is reached */
797 block
= opening
->block
;
798 block_pos
= opening
->block_pos
;
799 file
= opening
->file
;
801 remainder
= file
->length
- opening
->pos
;
802 if(length
> remainder
)
808 /* Get number of remaining valid bytes in this block */
810 block_length
= block
->length
- block_pos
;
812 /* Get next block if end of current one has been reached */
814 if(block_length
== 0)
816 block
= (struct Block
*)((struct MinNode
*)block
)->mln_Succ
;
819 block_length
= block
->length
;
822 /* Copy block contents into the caller's buffer */
824 read_length
= MIN(remainder
, block_length
);
825 CopyMem(((UBYTE
*)block
) + sizeof(struct Block
) + block_pos
, buffer
,
827 remainder
-= read_length
;
828 buffer
+= read_length
;
829 block_pos
+= read_length
;
832 /* Record new position for next access */
834 opening
->block
= block
;
835 opening
->block_pos
= block_pos
;
836 opening
->pos
+= length
;
838 /* Return number of bytes read */
845 /****i* ram.handler/WriteData **********************************************
851 * write_length = WriteData(handler, opening, buffer, length)
853 * UPINT WriteData(struct Handler *, struct Opening *, UBYTE *, UPINT);
869 ****************************************************************************
873 UPINT
WriteData(struct Handler
*handler
, struct Opening
*opening
,
874 UBYTE
*buffer
, UPINT length
)
876 struct Block
*block
, *new_block
, *end_block
;
878 UPINT block_pos
, block_length
, write_length
, remainder
= length
,
879 old_block_count
, file_length
, pos
;
882 file
= opening
->file
;
883 file_length
= file
->length
;
884 old_block_count
= file
->block_count
;
886 block
= opening
->block
;
887 block_pos
= opening
->block_pos
;
889 while(remainder
> 0 && error
== 0)
891 block_length
= block
->length
- block_pos
;
893 /* Move on to next block if end of current block reached */
895 if(block_length
== 0)
897 block
= (struct Block
*)((struct MinNode
*)block
)->mln_Succ
;
900 /* Add another block to the file if required */
902 if(((struct MinNode
*)block
)->mln_Succ
== NULL
)
904 new_block
= AddDataBlock(handler
, opening
->file
, remainder
);
905 if(new_block
!= NULL
)
908 file
->end_length
= 0;
914 block_length
= block
->length
;
917 /* Write as much as possible to the current block */
921 write_length
= MIN(remainder
, block_length
);
923 ((UBYTE
*)block
) + sizeof(struct Block
) + block_pos
,
925 remainder
-= write_length
;
926 buffer
+= write_length
;
927 block_pos
+= write_length
;
931 /* Recalculate length of used portion of last block */
933 end_block
= GetLastBlock(file
);
934 if(block
== end_block
&& block_pos
>= file
->end_length
)
935 file
->end_length
= block_pos
;
937 /* Update file size, volume size and current position */
941 if(pos
> file_length
)
944 opening
->block
= block
;
945 opening
->block_pos
= block_pos
;
946 handler
->block_count
+= file
->block_count
- old_block_count
;
948 /* Return number of bytes written */
956 /****i* ram.handler/LockObject *********************************************
962 * lock = LockObject(handler, object,
965 * struct Lock *LockObject(struct Handler *handler, struct Object *,
982 ****************************************************************************
986 struct Lock
*LockObject(struct Handler
*handler
, struct Object
*object
,
990 LONG error
= 0, lock_access
;
992 object
= GetRealObject(object
);
997 lock
= AllocPooled(handler
->public_pool
, sizeof(struct Lock
));
1001 object
->lock
= lock
;
1003 ((struct FileLock
*)lock
)->fl_Key
= (PINT
)object
;
1004 ((struct FileLock
*)lock
)->fl_Access
= access
;
1005 ((struct FileLock
*)lock
)->fl_Task
= handler
->proc_port
;
1006 ((struct FileLock
*)lock
)->fl_Volume
= MKBADDR(handler
->volume
);
1008 NewList((struct List
*)&lock
->openings
);
1015 lock_access
= ((struct FileLock
*)lock
)->fl_Access
;
1016 if(access
== ACCESS_WRITE
|| lock_access
== ACCESS_WRITE
)
1019 error
= ERROR_OBJECT_IN_USE
;
1026 handler
->lock_count
++;
1036 /****i* ram.handler/ExamineObject ******************************************
1042 * success = ExamineObject(handler, object,
1045 * BOOL ExamineObject(struct Handler *, struct Object *,
1046 * struct FileInfoBlock *);
1062 ****************************************************************************
1066 BOOL
ExamineObject(struct Handler
*handler
, struct Object
*object
,
1067 struct FileInfoBlock
*info
)
1070 struct Object
*next_object
;
1076 object
= (struct Object
*)info
->fib_DiskKey
;
1077 next_object
= (APTR
)((struct Node
*)object
)->ln_Succ
;
1080 next_object
= (APTR
)object
->elements
.mlh_Head
;
1082 if(next_object
!= NULL
)
1084 /* Fill in information from object */
1086 entry_type
= ((struct Node
*)object
)->ln_Pri
;
1087 info
->fib_DirEntryType
= entry_type
;
1088 info
->fib_EntryType
= entry_type
;
1089 s
= ((struct Node
*)object
)->ln_Name
;
1090 info
->fib_FileName
[0] = StrSize(s
) - 1;
1091 CopyMem(s
, &info
->fib_FileName
[1], info
->fib_FileName
[0]);
1092 s
= object
->comment
;
1093 if(s
!= NULL
&& ((struct Node
*)object
)->ln_Pri
!= ST_SOFTLINK
) {
1094 info
->fib_Comment
[0] = StrSize(s
) - 1;
1095 CopyMem(s
, &info
->fib_Comment
[1], info
->fib_Comment
[0]);
1097 info
->fib_Comment
[0] = '\0';
1098 info
->fib_NumBlocks
= object
->block_count
;
1100 /* Fill in information from real object */
1102 object
= GetRealObject(object
);
1104 info
->fib_Protection
= object
->protection
;
1105 info
->fib_Size
= object
->length
;
1106 CopyMem(&object
->date
, &info
->fib_Date
, sizeof(struct DateStamp
));
1108 /* Prepare for next examination */
1111 info
->fib_DiskKey
= (PINT
)next_object
;
1116 SetIoErr(ERROR_NO_MORE_ENTRIES
);
1124 /****i* ram.handler/AdjustExaminations *************************************
1127 * AdjustExaminations -- Prevent ExAll() getting confused or crashing
1130 * AdjustExaminations(handler, object)
1132 * VOID AdjustExaminations(struct Handler *, struct Object *);
1148 ****************************************************************************
1152 VOID
AdjustExaminations(struct Handler
*handler
, struct Object
*object
)
1154 struct Examination
*examination
, *tail
;
1156 /* Adjust any ExAll()s that were due to examine the object */
1158 examination
= (APTR
)handler
->examinations
.mlh_Head
;
1159 tail
= (APTR
)&handler
->examinations
.mlh_Tail
;
1161 while(examination
!= tail
)
1163 if(examination
->next_object
== object
)
1164 examination
->next_object
= (APTR
)((struct Node
*)object
)->ln_Succ
;
1165 examination
= (APTR
)((struct MinNode
*)examination
)->mln_Succ
;
1172 /****i* ram.handler/SetName ************************************************
1178 * success = SetName(handler, object, name)
1180 * BOOL SetName(struct Handler *, struct Object *, TEXT *);
1196 ****************************************************************************
1200 BOOL
SetName(struct Handler
*handler
, struct Object
*object
,
1206 struct Locale
*locale
;
1209 /* Check name isn't too long */
1211 if(StrSize(name
) > MAX_NAME_SIZE
)
1212 error
= ERROR_INVALID_COMPONENT_NAME
;
1214 /* Check name doesn't have any strange characters in it */
1216 if ((locale
= handler
->locale
)) {
1217 for(p
= name
; (ch
= *p
) != '\0'; p
++)
1219 && (!IsPrint(locale
, ch
) || IsCntrl(locale
, ch
) || ch
== ':'))
1220 error
= ERROR_INVALID_COMPONENT_NAME
;
1223 /* Store new name */
1227 block_diff
= SetString(handler
,
1228 (TEXT
**)&((struct Node
*)object
)->ln_Name
, name
);
1234 object
->block_count
+= block_diff
;
1235 handler
->block_count
+= block_diff
;
1238 /* Return success indicator */
1246 /****i* ram.handler/AddDataBlock *******************************************
1252 * block = AddDataBlock(file, length)
1254 * struct Block *AddDataBlock(struct Object *, UPINT);
1265 * Attempts to allocate a smaller block if the requested size cannot be
1272 ****************************************************************************
1276 static struct Block
*AddDataBlock(struct Handler
*handler
,
1277 struct Object
*file
, UPINT length
)
1279 struct Block
*block
;
1283 /* Ensure block size is within limits */
1285 alloc_size
= sizeof(struct Block
) + length
;
1287 limit
= handler
->max_block_size
;
1288 if(alloc_size
> limit
)
1291 limit
= handler
->min_block_size
;
1292 if(alloc_size
< limit
)
1295 /* Allocate a multiple of the memory block size */
1298 while(block
== NULL
&& alloc_size
>= limit
)
1300 alloc_size
= ((alloc_size
- 1) & (~MEM_BLOCKMASK
)) + MEM_BLOCKSIZE
;
1301 block
= AllocPooled(handler
->muddy_pool
, alloc_size
);
1306 /* Add the block to the end of the file */
1310 AddTail((struct List
*)&file
->elements
, (struct Node
*)block
);
1311 block
->length
= alloc_size
- sizeof(struct Block
);
1312 file
->block_count
+= alloc_size
>> MEM_BLOCKSHIFT
;
1315 SetIoErr(ERROR_DISK_FULL
);
1317 /* Return the new block */
1324 /****i* ram.handler/FreeDataBlock ******************************************
1330 * FreeDataBlock(file, block)
1332 * VOID FreeDataBlock(struct Object *, struct Block *);
1348 ****************************************************************************
1352 static VOID
FreeDataBlock(struct Handler
*handler
, struct Object
*file
,
1353 struct Block
*block
)
1359 alloc_size
= sizeof(struct Block
) + block
->length
;
1360 file
->block_count
-= alloc_size
>> MEM_BLOCKSHIFT
;
1361 FreePooled(handler
->muddy_pool
, block
, alloc_size
);
1369 /****i* ram.handler/GetRealObject ******************************************
1372 * GetRealObject -- Dereference a hard link if necessary.
1375 * real_object = GetRealObject(object)
1377 * struct Object *GetRealObject(struct Object *);
1380 * If the specified object is a file, directory or soft link, the same
1381 * object is returned. If the object is a hard link, the link target is
1396 ****************************************************************************
1400 struct Object
*GetRealObject(struct Object
*object
)
1402 struct MinNode
*node
, *pred
;
1404 /* Get first node in list */
1406 node
= &object
->hard_link
;
1407 if(node
->mln_Pred
!= NULL
)
1409 while((pred
= node
->mln_Pred
) != NULL
)
1411 node
= node
->mln_Succ
;
1414 /* Get object from node address */
1416 object
= HARDLINK(node
);
1422 /****i* ram.handler/GetBlockLength *****************************************
1425 * GetBlockLength -- Get the number of utilised bytes in a block.
1428 * length = GetBlockLength(file, block)
1430 * UPINT GetBlockLength(struct Object *, struct Block *);
1446 ****************************************************************************
1450 UPINT
GetBlockLength(struct Object
*file
, struct Block
*block
)
1454 if(block
== (APTR
)file
->elements
.mlh_TailPred
)
1455 length
= file
->end_length
;
1457 length
= block
->length
;
1464 /****i* ram.handler/GetLastBlock *******************************************
1470 * block = GetLastBlock(file)
1472 * struct Block *GetLastBlock(struct Object *);
1488 ****************************************************************************
1492 static struct Block
*GetLastBlock(struct Object
*file
)
1494 struct Block
*block
;
1496 block
= (APTR
)file
->elements
.mlh_TailPred
;