Indentation fix, cleanup.
[AROS.git] / rom / filesys / ram / filesystem.c
blobe7d4fc049ce40d89b94398066a22a47cb894a310
1 /*
3 File: filesystem.c
4 Author: Neil Cafferkey
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,
20 MA 02111-1307, USA.
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,
31 struct Block *block);
32 static struct Block *GetLastBlock(struct Object *file);
36 /****i* ram.handler/DeleteHandler ******************************************
38 * NAME
39 * DeleteHandler --
41 * SYNOPSIS
42 * DeleteHandler(handler)
44 * VOID DeleteHandler(struct Handler *);
46 * FUNCTION
48 * INPUTS
50 * RESULT
52 * EXAMPLE
54 * NOTES
56 * BUGS
58 * SEE ALSO
60 ****************************************************************************
64 VOID DeleteHandler(struct Handler *handler)
66 struct DosList *volume;
67 struct Object *root_dir;
68 struct Lock *root_lock;
69 APTR base;
71 if(handler != NULL)
73 root_dir = handler->root_dir;
75 if(root_dir != NULL)
77 root_lock = root_dir->lock;
78 if(root_lock != NULL)
79 CmdFreeLock(handler, root_lock);
80 DeleteObject(handler, root_dir);
83 volume = handler->volume;
84 if(volume != NULL)
86 RemDosEntry(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);
96 /* Close libraries */
98 base = LocaleBase;
99 if(base != NULL) {
100 if (handler->locale)
101 CloseLocale(handler->locale);
102 CloseLibrary(base);
105 base = UtilityBase;
106 if(base != NULL)
107 CloseLibrary(base);
109 FreeMem(handler, sizeof(struct Handler));
112 return;
117 /****i* ram.handler/CreateObject *******************************************
119 * NAME
120 * CreateObject --
122 * SYNOPSIS
123 * object = CreateObject(handler, name, type,
124 * parent)
126 * struct Object *CreateObject(struct Handler *, TEXT *, BYTE,
127 * struct Object *);
129 * FUNCTION
130 * Creates a new filesystem object. The existence of a duplicate object
131 * must be checked for beforehand.
133 * INPUTS
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.
138 * RESULT
139 * object - The newly created object, or NULL for failure.
141 * EXAMPLE
143 * NOTES
145 * BUGS
147 * SEE ALSO
149 ****************************************************************************
153 struct Object *CreateObject(struct Handler *handler, const TEXT *name,
154 BYTE type, struct Object *parent)
156 struct Object *object = NULL;
157 LONG error = 0;
159 /* Get the real parent in case it's a hard link */
161 if(parent != NULL)
162 parent = GetRealObject(parent);
164 /* Create a new object structure */
166 object = AllocPooled(handler->clear_pool, sizeof(struct Object));
167 if(object == NULL)
168 error = ERROR_DISK_FULL;
170 if(error == 0)
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);
181 if(type == ST_FILE)
182 AddTail((APTR)&object->elements, (APTR)&object->start_block);
184 if(name != NULL)
186 if(!SetName(handler, object, name))
187 error = IoErr();
190 if(parent != NULL)
192 AddTail((struct List *)&parent->elements, (struct Node *)object);
193 CopyMem(&object->date, &parent->date, sizeof(struct DateStamp));
197 if(error == 0)
198 MatchNotifyRequests(handler);
200 if(error != 0)
202 DeleteObject(handler, object);
203 object = NULL;
206 /* Return the new object */
208 SetIoErr(error);
209 return object;
214 /****i* ram.handler/AttemptDeleteObject ************************************
216 * NAME
217 * AttemptDeleteObject -- Attempt to delete an object.
219 * SYNOPSIS
220 * success = AttemptDeleteObject(handler, object)
222 * BOOL AttemptDeleteObject(struct Handler *, struct Object *);
224 * FUNCTION
225 * Attempts to delete the specified object. Note that this function
226 * does not check permissions.
228 * INPUTS
229 * object - the object to be deleted, or NULL for no action.
231 * RESULT
232 * success - success indicator.
234 * EXAMPLE
236 * NOTES
238 * BUGS
240 * SEE ALSO
242 ****************************************************************************
246 BOOL AttemptDeleteObject(struct Handler *handler, struct Object *object,
247 BOOL notify)
249 LONG error = 0;
250 BYTE object_type;
252 if(object != NULL)
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 */
268 if(error == 0)
270 if(notify)
271 NotifyAll(handler, object, FALSE);
272 UnmatchNotifyRequests(handler, object);
273 AdjustExaminations(handler, object);
274 DeleteObject(handler, object);
278 /* Return result */
280 SetIoErr(error);
281 return error == 0;
286 /****i* ram.handler/DeleteObject *******************************************
288 * NAME
289 * DeleteObject --
291 * SYNOPSIS
292 * success = DeleteObject(handler, object)
294 * BOOL DeleteObject(struct Handler *, struct Object *);
296 * FUNCTION
298 * INPUTS
299 * object - the object to be deleted, or NULL for no action.
301 * RESULT
302 * None.
304 * EXAMPLE
306 * NOTES
308 * BUGS
310 * SEE ALSO
312 ****************************************************************************
316 VOID DeleteObject(struct Handler *handler, struct Object *object)
318 BYTE object_type;
319 struct Block *block;
320 struct MinNode *node;
321 struct Object *real_object, *master_link, *heir;
322 PINT block_diff;
324 if(object != NULL)
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))
348 != NULL)
349 AddTail((APTR)&master_link->elements, (APTR)node);
351 else
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 */
387 Remove((APTR)heir);
388 object = heir;
391 /* Delete an unlinked object */
393 else
395 /* Remove all blocks if the object is a file */
397 while((block = (APTR)RemTail((struct List *)&object->elements))
398 != NULL)
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));
414 return;
419 /****i* ram.handler/GetHardObject ******************************************
421 * NAME
422 * GetHardObject -- Find a non-soft-link object given a lock and path.
424 * SYNOPSIS
425 * object = GetHardObject(handler, lock, name,
426 * parent)
428 * struct Object *GetHardObject(struct Handler *, struct Lock *, TEXT *,
429 * struct Object **);
431 * FUNCTION
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.
436 * INPUTS
437 * lock - .
438 * name - .
439 * parent - parent directory will be returned here (will be NULL if
440 * path is invalid or contains a soft link).
442 * RESULT
443 * object - The located object, or NULL if not found.
445 * EXAMPLE
447 * NOTES
449 * BUGS
451 * SEE ALSO
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)
464 object = NULL;
466 return object;
470 /****i* ram.handler/GetObject **********************************************
472 * NAME
473 * GetObject -- Find an object given a lock and path.
475 * SYNOPSIS
476 * object = GetObject(handler, lock, name,
477 * parent, remainder_pos)
479 * struct Object *GetObject(struct Handler *, struct Lock *, TEXT *,
480 * struct Object **, LONG *);
482 * FUNCTION
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.
488 * INPUTS
489 * lock - .
490 * name - .
491 * parent - parent directory will be returned here (will be NULL if
492 * path is invalid or contains a soft link).
494 * RESULT
495 * object - The located object, or NULL if not found.
497 * EXAMPLE
499 * NOTES
501 * BUGS
503 * SEE ALSO
505 ****************************************************************************
509 struct Object *GetObject(struct Handler *handler, struct Lock *lock,
510 const TEXT *name, struct Object **parent, LONG *remainder_pos)
512 const TEXT *p;
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));
520 if(ch == ':')
521 pos = p - name + 1;
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);
534 if(*buffer != '\0')
536 if(((struct Node *)object)->ln_Pri > 0)
538 old_object = object;
539 object = GetRealObject(object);
540 object = (struct Object *)
541 FindNameNoCase(handler, (struct List *)&object->elements, buffer);
542 if(object != NULL)
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;
553 else
554 error = ERROR_OBJECT_NOT_FOUND;
556 else
558 error = ERROR_OBJECT_NOT_FOUND;
559 object = NULL;
560 old_object = NULL;
563 else if(pos != -1)
565 object = object->parent;
566 if(object == NULL)
567 error = ERROR_OBJECT_NOT_FOUND;
571 /* Record the parent directory of the supplied path, if it exists */
573 if(parent != NULL)
575 if(pos == -1 && error != ERROR_IS_SOFT_LINK)
576 *parent = old_object;
577 else
578 *parent = NULL;
581 /* Return the located object */
583 SetIoErr(error);
584 return object;
589 /****i* ram.handler/ChangeFileSize *****************************************
591 * NAME
592 * ChangeFileSize --
594 * SYNOPSIS
595 * new_size = ChangeFileSize(handler, opening, offset,
596 * mode)
598 * PINT ChangeFileSize(struct Handler *, struct Opening *, PINT,
599 * LONG);
601 * FUNCTION
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.
605 * INPUTS
607 * RESULT
609 * EXAMPLE
611 * NOTES
613 * BUGS
615 * SEE ALSO
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;
627 struct Object *file;
628 LONG error = 0;
629 struct MinList *openings;
630 struct Opening *tail;
632 /* Get origin */
634 file = opening->file;
636 if(mode == OFFSET_BEGINNING)
637 new_length = 0;
638 else if(mode == OFFSET_CURRENT)
639 new_length = opening->pos;
640 else
641 new_length = file->length;
643 /* Check new size won't be negative */
645 if(-offset > new_length)
647 SetIoErr(ERROR_SEEK_ERROR);
648 return -1;
651 /* Get new length */
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;
666 /* Change size */
668 if(new_length > length)
670 /* Add the required number of data bytes */
672 remainder = new_length - full_length;
673 end_length -= remainder;
675 while(remainder > 0)
677 block = AddDataBlock(handler, file, remainder);
678 if(block != NULL)
680 end_length = remainder;
681 remainder -= block->length;
683 else
684 remainder = 0;
687 /* Remove new blocks upon failure */
689 if(block == NULL)
691 new_length = -1;
692 error = IoErr();
693 ChangeFileSize(handler, opening, length, OFFSET_BEGINNING);
695 else
696 file->end_length = end_length;
698 else if(length != new_length)
700 /* Remove surplus blocks from the file */
702 block = NULL;
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);
724 else
725 AddTail((struct List *)&file->elements, (APTR)block);
728 /* Store new file size */
730 if(new_length != -1)
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;
755 SetIoErr(error);
756 return new_length;
761 /****i* ram.handler/ReadData ***********************************************
763 * NAME
764 * ReadData --
766 * SYNOPSIS
767 * read_length = ReadData(opening, buffer, length)
769 * UPINT ReadData(struct Opening *, UBYTE *, UPINT);
771 * FUNCTION
773 * INPUTS
775 * RESULT
777 * EXAMPLE
779 * NOTES
781 * BUGS
783 * SEE ALSO
785 ****************************************************************************
789 UPINT ReadData(struct Opening *opening, UBYTE *buffer, UPINT length)
791 struct Block *block;
792 UPINT block_pos, block_length, read_length = 0, remainder;
793 struct Object *file;
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)
803 length = remainder;
804 remainder = length;
806 while(remainder > 0)
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;
817 block_pos = 0;
818 /*read_length = 0;*/
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,
826 read_length);
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 */
840 return length;
845 /****i* ram.handler/WriteData **********************************************
847 * NAME
848 * WriteData --
850 * SYNOPSIS
851 * write_length = WriteData(handler, opening, buffer, length)
853 * UPINT WriteData(struct Handler *, struct Opening *, UBYTE *, UPINT);
855 * FUNCTION
857 * INPUTS
859 * RESULT
861 * EXAMPLE
863 * NOTES
865 * BUGS
867 * SEE ALSO
869 ****************************************************************************
873 UPINT WriteData(struct Handler *handler, struct Opening *opening,
874 UBYTE *buffer, UPINT length)
876 struct Block *block, *new_block, *end_block;
877 struct Object *file;
878 UPINT block_pos, block_length, write_length, remainder = length,
879 old_block_count, file_length, pos;
880 LONG error = 0;
882 file = opening->file;
883 file_length = file->length;
884 old_block_count = file->block_count;
885 pos = opening->pos;
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;
898 block_pos = 0;
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)
907 block = new_block;
908 file->end_length = 0;
910 else
911 error = IoErr();
914 block_length = block->length;
917 /* Write as much as possible to the current block */
919 if(error == 0)
921 write_length = MIN(remainder, block_length);
922 CopyMem(buffer,
923 ((UBYTE *)block) + sizeof(struct Block) + block_pos,
924 write_length);
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 */
939 length -= remainder;
940 pos += length;
941 if(pos > file_length)
942 file->length = pos;
943 opening->pos = pos;
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 */
950 SetIoErr(error);
951 return length;
956 /****i* ram.handler/LockObject *********************************************
958 * NAME
959 * LockObject --
961 * SYNOPSIS
962 * lock = LockObject(handler, object,
963 * access)
965 * struct Lock *LockObject(struct Handler *handler, struct Object *,
966 * LONG);
968 * FUNCTION
970 * INPUTS
972 * RESULT
974 * EXAMPLE
976 * NOTES
978 * BUGS
980 * SEE ALSO
982 ****************************************************************************
986 struct Lock *LockObject(struct Handler *handler, struct Object *object,
987 LONG access)
989 struct Lock *lock;
990 LONG error = 0, lock_access;
992 object = GetRealObject(object);
993 lock = object->lock;
995 if(lock == NULL)
997 lock = AllocPooled(handler->public_pool, sizeof(struct Lock));
999 if(lock != NULL)
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);
1010 else
1011 error = IoErr();
1013 else
1015 lock_access = ((struct FileLock *)lock)->fl_Access;
1016 if(access == ACCESS_WRITE || lock_access == ACCESS_WRITE)
1018 lock = NULL;
1019 error = ERROR_OBJECT_IN_USE;
1023 if(lock != NULL)
1025 lock->lock_count++;
1026 handler->lock_count++;
1029 SetIoErr(error);
1031 return lock;
1036 /****i* ram.handler/ExamineObject ******************************************
1038 * NAME
1039 * ExamineObject --
1041 * SYNOPSIS
1042 * success = ExamineObject(handler, object,
1043 * info)
1045 * BOOL ExamineObject(struct Handler *, struct Object *,
1046 * struct FileInfoBlock *);
1048 * FUNCTION
1050 * INPUTS
1052 * RESULT
1054 * EXAMPLE
1056 * NOTES
1058 * BUGS
1060 * SEE ALSO
1062 ****************************************************************************
1066 BOOL ExamineObject(struct Handler *handler, struct Object *object,
1067 struct FileInfoBlock *info)
1069 BOOL success;
1070 struct Object *next_object;
1071 TEXT *s;
1072 LONG entry_type;
1074 if(object == NULL)
1076 object = (struct Object *)info->fib_DiskKey;
1077 next_object = (APTR)((struct Node *)object)->ln_Succ;
1079 else
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]);
1096 } else
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 */
1110 success = TRUE;
1111 info->fib_DiskKey = (PINT)next_object;
1113 else
1115 success = FALSE;
1116 SetIoErr(ERROR_NO_MORE_ENTRIES);
1119 return success;
1124 /****i* ram.handler/AdjustExaminations *************************************
1126 * NAME
1127 * AdjustExaminations -- Prevent ExAll() getting confused or crashing
1129 * SYNOPSIS
1130 * AdjustExaminations(handler, object)
1132 * VOID AdjustExaminations(struct Handler *, struct Object *);
1134 * FUNCTION
1136 * INPUTS
1138 * RESULT
1140 * EXAMPLE
1142 * NOTES
1144 * BUGS
1146 * SEE ALSO
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;
1168 return;
1172 /****i* ram.handler/SetName ************************************************
1174 * NAME
1175 * SetName --
1177 * SYNOPSIS
1178 * success = SetName(handler, object, name)
1180 * BOOL SetName(struct Handler *, struct Object *, TEXT *);
1182 * FUNCTION
1184 * INPUTS
1186 * RESULT
1188 * EXAMPLE
1190 * NOTES
1192 * BUGS
1194 * SEE ALSO
1196 ****************************************************************************
1200 BOOL SetName(struct Handler *handler, struct Object *object,
1201 const TEXT *name)
1203 LONG error = 0;
1204 const TEXT *p;
1205 TEXT ch;
1206 struct Locale *locale;
1207 PINT block_diff;
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++)
1218 if((ch & 0x80) == 0
1219 && (!IsPrint(locale, ch) || IsCntrl(locale, ch) || ch == ':'))
1220 error = ERROR_INVALID_COMPONENT_NAME;
1223 /* Store new name */
1225 if(error == 0)
1227 block_diff = SetString(handler,
1228 (TEXT **)&((struct Node *)object)->ln_Name, name);
1229 error = IoErr();
1232 if(error == 0)
1234 object->block_count += block_diff;
1235 handler->block_count += block_diff;
1238 /* Return success indicator */
1240 SetIoErr(error);
1241 return error == 0;
1246 /****i* ram.handler/AddDataBlock *******************************************
1248 * NAME
1249 * AddDataBlock --
1251 * SYNOPSIS
1252 * block = AddDataBlock(file, length)
1254 * struct Block *AddDataBlock(struct Object *, UPINT);
1256 * FUNCTION
1258 * INPUTS
1260 * RESULT
1262 * EXAMPLE
1264 * NOTES
1265 * Attempts to allocate a smaller block if the requested size cannot be
1266 * obtained.
1268 * BUGS
1270 * SEE ALSO
1272 ****************************************************************************
1276 static struct Block *AddDataBlock(struct Handler *handler,
1277 struct Object *file, UPINT length)
1279 struct Block *block;
1280 UPINT alloc_size;
1281 ULONG limit;
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)
1289 alloc_size = limit;
1291 limit = handler->min_block_size;
1292 if(alloc_size < limit)
1293 alloc_size = limit;
1295 /* Allocate a multiple of the memory block size */
1297 block = NULL;
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);
1302 if(block == NULL)
1303 alloc_size >>= 1;
1306 /* Add the block to the end of the file */
1308 if(block != NULL)
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;
1314 else
1315 SetIoErr(ERROR_DISK_FULL);
1317 /* Return the new block */
1319 return block;
1324 /****i* ram.handler/FreeDataBlock ******************************************
1326 * NAME
1327 * FreeDataBlock --
1329 * SYNOPSIS
1330 * FreeDataBlock(file, block)
1332 * VOID FreeDataBlock(struct Object *, struct Block *);
1334 * FUNCTION
1336 * INPUTS
1338 * RESULT
1340 * EXAMPLE
1342 * NOTES
1344 * BUGS
1346 * SEE ALSO
1348 ****************************************************************************
1352 static VOID FreeDataBlock(struct Handler *handler, struct Object *file,
1353 struct Block *block)
1355 UPINT alloc_size;
1357 if(block != NULL)
1359 alloc_size = sizeof(struct Block) + block->length;
1360 file->block_count -= alloc_size >> MEM_BLOCKSHIFT;
1361 FreePooled(handler->muddy_pool, block, alloc_size);
1364 return;
1369 /****i* ram.handler/GetRealObject ******************************************
1371 * NAME
1372 * GetRealObject -- Dereference a hard link if necessary.
1374 * SYNOPSIS
1375 * real_object = GetRealObject(object)
1377 * struct Object *GetRealObject(struct Object *);
1379 * FUNCTION
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
1382 * returned instead.
1384 * INPUTS
1386 * RESULT
1388 * EXAMPLE
1390 * NOTES
1392 * BUGS
1394 * SEE ALSO
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)
1410 node = pred;
1411 node = node->mln_Succ;
1414 /* Get object from node address */
1416 object = HARDLINK(node);
1417 return object;
1422 /****i* ram.handler/GetBlockLength *****************************************
1424 * NAME
1425 * GetBlockLength -- Get the number of utilised bytes in a block.
1427 * SYNOPSIS
1428 * length = GetBlockLength(file, block)
1430 * UPINT GetBlockLength(struct Object *, struct Block *);
1432 * FUNCTION
1434 * INPUTS
1436 * RESULT
1438 * EXAMPLE
1440 * NOTES
1442 * BUGS
1444 * SEE ALSO
1446 ****************************************************************************
1450 UPINT GetBlockLength(struct Object *file, struct Block *block)
1452 UPINT length;
1454 if(block == (APTR)file->elements.mlh_TailPred)
1455 length = file->end_length;
1456 else
1457 length = block->length;
1459 return length;
1464 /****i* ram.handler/GetLastBlock *******************************************
1466 * NAME
1467 * GetLastBlock --
1469 * SYNOPSIS
1470 * block = GetLastBlock(file)
1472 * struct Block *GetLastBlock(struct Object *);
1474 * FUNCTION
1476 * INPUTS
1478 * RESULT
1480 * EXAMPLE
1482 * NOTES
1484 * BUGS
1486 * SEE ALSO
1488 ****************************************************************************
1492 static struct Block *GetLastBlock(struct Object *file)
1494 struct Block *block;
1496 block = (APTR)file->elements.mlh_TailPred;
1498 return block;