added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / workbench / devs / ram_handler / ram_handler.c
blobdbf5cc43256b63cc3ababc63e4b04fb22d574b94
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 RAM: handler.
6 */
8 #define DEBUG 0
9 #include <aros/debug.h>
11 #include <exec/errors.h>
12 #include <exec/types.h>
13 #include <exec/resident.h>
14 #include <exec/memory.h>
15 #include <exec/semaphores.h>
16 #include <utility/tagitem.h>
17 #include <utility/utility.h>
18 #include <proto/exec.h>
19 #include <proto/utility.h>
20 #include <proto/alib.h>
21 #include <proto/dos.h>
22 #include <dos/dos.h>
23 #include <dos/dosextens.h>
24 #include <dos/dosasl.h>
25 #include <dos/exall.h>
26 #include <dos/filesystem.h>
27 #include <aros/libcall.h>
28 #include <aros/symbolsets.h>
30 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
31 #include "ram_handler_gcc.h"
32 #endif
33 #include <stddef.h>
34 #include <string.h>
36 #include "HashTable.h"
38 static void deventry();
40 #include LC_LIBDEFS_FILE
42 #define NRF_NOT_REPLIED NRF_MAGIC
45 /* Device node */
46 struct cnode
48 struct MinNode node;
49 LONG type; /* ST_LINKDIR */
50 STRPTR name; /* Link's name */
51 struct cnode *self; /* Pointer to top of structure */
52 struct hnode *link; /* NULL */
53 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
54 ULONG protect; /* 0 */
55 STRPTR comment; /* NULL */
56 struct vnode *volume; /* Pointer to volume */
57 struct DosList *doslist; /* Pointer to doslist entry */
60 /* Volume node */
61 struct vnode
63 struct MinNode node;
64 LONG type; /* ST_USERDIR */
65 STRPTR name; /* Directory name */
66 struct vnode *self; /* Points to top of structure */
67 struct hnode *link; /* This one is linked to me */
68 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
69 ULONG protect; /* 0 */
70 STRPTR comment; /* NULL */
71 struct MinList receivers;
72 struct DateStamp date;
73 struct MinList list; /* Contents of directory */
74 ULONG volcount; /* number of handles on this volume */
75 struct DosList *doslist; /* Pointer to doslist entry */
78 /* Directory node */
79 struct dnode
81 struct MinNode node;
82 LONG type; /* ST_USERDIR */
83 STRPTR name; /* Directory name */
84 struct vnode *volume; /* Volume's root directory */
85 struct hnode *link; /* This one is linked to me */
86 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
87 ULONG protect; /* protection bits */
88 STRPTR comment; /* Some comment */
89 struct MinList receivers;
90 struct DateStamp date;
91 struct MinList list; /* Contents of directory */
94 /* File node */
95 struct fnode
97 struct MinNode node;
98 LONG type; /* ST_FILE */
99 STRPTR name; /* Filename */
100 struct vnode *volume; /* Volume's root directory */
101 struct hnode *link; /* This one is linked to me */
102 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
103 ULONG protect; /* protection bits */
104 STRPTR comment; /* Some file comment */
105 struct MinList receivers;
106 struct DateStamp date;
107 ULONG flags;
108 LONG size; /* Filesize */
109 UBYTE *blocks[16]; /* Upto 0x1000 bytes */
110 UBYTE **iblocks[4]; /* Upto 0x41000 bytes */
111 UBYTE ***i2block; /* Upto 0x1041000 bytes */
112 UBYTE ****i3block; /* Upto 0x101041000 bytes */
115 /* Softlink node */
116 struct snode
118 struct MinNode node;
119 LONG type; /* ST_SOFTLINK */
120 STRPTR name; /* Link's name */
121 struct vnode *volume; /* Volume's root directory */
122 struct hnode *link; /* This one is hardlinked to me */
123 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
124 ULONG protect; /* protection bits */
125 STRPTR comment; /* Some file comment */
126 char *contents; /* Contents of soft link */
129 /* Hardlink node */
130 struct hnode
132 struct MinNode node;
133 LONG type; /* ST_LINKDIR */
134 STRPTR name; /* Link's name */
135 struct vnode *volume; /* Volume's root directory */
136 struct hnode *link; /* This one is hardlinked to me */
137 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
138 ULONG protect; /* protection bits */
139 STRPTR comment; /* Some file comment */
140 struct hnode *orig; /* original object */
143 /*****************************************************************************/
145 #define FILEFLAGS_Changed 1
147 static STRPTR getName(struct rambase *rambase, struct dnode *dn);
149 typedef enum
151 NOTIFY_Add,
152 NOTIFY_Delete,
153 NOTIFY_Write,
154 NOTIFY_Close,
155 NOTIFY_Open,
156 } NType;
158 void Notify_notifyTasks(struct rambase *rambase,
159 struct MinList *notifications);
161 BOOL Notify_initialize(struct rambase *rambase);
162 void Notify_fileChange(struct rambase *rambase, NType type,
163 struct fnode *file);
164 void Notify_directoryChange(struct rambase *rambase, NType type,
165 struct dnode *dir);
168 BOOL Notify_addNotification(struct rambase *rambase, struct dnode *dn,
169 struct NotifyRequest *nr);
170 void Notify_removeNotification(struct rambase *rambase,
171 struct NotifyRequest *nr);
173 /****************************************************************************/
176 #define BLOCKSIZE 256
177 #define PBLOCKSIZE (256*sizeof(UBYTE *))
179 struct filehandle
181 struct dnode *node;
182 IPTR position;
185 /* Use This from now on */
186 #ifdef DOSBase
187 #undef DOSBase
188 #endif
189 #define DOSBase rambase->dosbase
191 static int OpenDev(LIBBASETYPEPTR rambase, struct IOFileSys *iofs);
193 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR rambase)
195 /* This function is single-threaded by exec by calling Forbid. */
197 struct MsgPort *port;
198 struct Task *task;
199 struct SignalSemaphore *semaphore;
200 APTR stack;
202 rambase->dosbase = (struct DosLibrary *)OpenLibrary(DOSNAME, 39);
204 if (rambase->dosbase != NULL)
206 rambase->utilitybase = (struct UtilityBase *)OpenLibrary(UTILITYNAME, 39);
208 if (rambase->utilitybase != NULL)
210 port = (struct MsgPort *)AllocMem(sizeof(struct MsgPort),
211 MEMF_PUBLIC | MEMF_CLEAR);
212 if (port != NULL)
214 rambase->port = port;
215 NewList(&port->mp_MsgList);
216 port->mp_Node.ln_Type = NT_MSGPORT;
217 port->mp_SigBit = SIGB_SINGLE;
219 task = (struct Task *)AllocMem(sizeof(struct Task),
220 MEMF_PUBLIC | MEMF_CLEAR);
222 if (task != NULL)
224 port->mp_SigTask = task;
225 port->mp_Flags = PA_IGNORE;
226 NewList(&task->tc_MemEntry);
227 task->tc_Node.ln_Type = NT_TASK;
228 task->tc_Node.ln_Name = "ram.handler task";
230 stack = AllocMem(AROS_STACKSIZE, MEMF_PUBLIC);
232 if (stack != NULL)
234 struct TagItem tasktags[] =
236 {TASKTAG_ARG1, (IPTR)rambase},
237 {TAG_DONE }
240 task->tc_SPLower = stack;
241 task->tc_SPUpper = (BYTE *)stack + AROS_STACKSIZE;
242 #if AROS_STACK_GROWS_DOWNWARDS
243 task->tc_SPReg = (BYTE *)task->tc_SPUpper - SP_OFFSET;
244 #else
245 task->tc_SPReg = (BYTE *)task->tc_SPLower + SP_OFFSET;
246 #endif
248 semaphore = (struct SignalSemaphore *)AllocMem(sizeof(struct SignalSemaphore),
249 MEMF_PUBLIC | MEMF_CLEAR);
251 if (semaphore != NULL)
253 rambase->sigsem = semaphore;
254 InitSemaphore(semaphore);
256 if (rambase->seglist==NULL) /* Are we a ROM module? */
258 struct DeviceNode *dn;
259 /* Install RAM: handler into device list
261 * KLUDGE: ram.handler should create only one device node, depending on
262 * the startup packet it gets. The mountlists for RAM: should be into dos.library bootstrap
263 * routines.
266 if((dn = AllocMem(sizeof (struct DeviceNode) + 4 + 3 + 2, MEMF_CLEAR|MEMF_PUBLIC)))
268 struct IOFileSys dummyiofs;
270 if (OpenDev(rambase, &dummyiofs))
272 BSTR s = MKBADDR(((IPTR)dn + sizeof(struct DeviceNode) + 3) & ~3);
274 rambase->device.dd_Library.lib_OpenCnt++;
276 AROS_BSTR_putchar(s, 0, 'R');
277 AROS_BSTR_putchar(s, 1, 'A');
278 AROS_BSTR_putchar(s, 2, 'M');
279 AROS_BSTR_setstrlen(s, 3);
281 dn->dn_Type = DLT_DEVICE;
282 dn->dn_Ext.dn_AROS.dn_Unit = dummyiofs.IOFS.io_Unit;
283 dn->dn_Ext.dn_AROS.dn_Device = dummyiofs.IOFS.io_Device;
284 dn->dn_Handler = NULL;
285 dn->dn_Startup = NULL;
286 dn->dn_Name = s;
287 dn->dn_Ext.dn_AROS.dn_DevName = AROS_BSTR_ADDR(dn->dn_Name);
289 if (AddDosEntry((struct DosList *)dn))
290 if (NewAddTask(task, deventry, NULL, tasktags) != NULL)
291 return TRUE;
294 FreeMem(dn, sizeof (struct DeviceNode));
297 else
298 if (NewAddTask(task, deventry, NULL, tasktags) != NULL)
299 return TRUE;
301 FreeMem(semaphore, sizeof(struct SignalSemaphore));
304 FreeMem(stack, AROS_STACKSIZE);
307 FreeMem(task, sizeof(struct Task));
310 FreeMem(port, sizeof(struct MsgPort));
313 CloseLibrary((struct Library *)rambase->utilitybase);
316 CloseLibrary((struct Library *)rambase->dosbase);
319 return FALSE;
322 #ifdef UtilityBase
323 #undef UtilityBase
324 #endif
325 #define UtilityBase rambase->utilitybase
328 /***************************************************************************/
330 void nullDelete(struct rambase *rambase, void *key, struct List *list)
332 // struct Receiver *rr;
333 // struct Node *tempNode;
335 // ForeachNodeSafe(list, rr, tempNode)
336 // {
337 // Remove(&rr->node);
338 // FreeVec(rr);
339 // }
341 FreeVec(key);
343 /* The list is part of the HashNode so we shouldn't free that */
347 ULONG stringHash(struct rambase *rambase, const void *key)
349 STRPTR str = (STRPTR)key;
350 ULONG val = 1;
352 while (*str != 0)
354 val *= ToLower(*str++);
355 val <<= 2;
358 return val;
361 static int
362 my_strcasecmp(struct rambase *rambase, const void *s1, const void *s2)
364 return strcasecmp(s1, s2);
367 /****************************************************************************/
370 STRPTR Strdup(struct rambase *rambase, CONST_STRPTR string)
372 CONST_STRPTR s2 = string;
373 STRPTR s3;
375 while(*s2++)
378 s3 = (STRPTR)AllocVec(s2 - string, MEMF_ANY);
380 if (s3 != NULL)
382 CopyMem(string, s3, s2 - string);
385 return s3;
389 void Strfree(struct rambase *rambase, STRPTR string)
391 FreeVec(string);
395 static int GM_UNIQUENAME(Open)
397 LIBBASETYPEPTR rambase,
398 struct IOFileSys *iofs,
399 ULONG unitnum,
400 ULONG flags
403 /* Mark Message as recently used. */
404 iofs->IOFS.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
406 return OpenDev(rambase, iofs);
410 static int OpenDev(LIBBASETYPEPTR rambase, struct IOFileSys *iofs)
412 struct filehandle *fhv, *fhc;
413 struct vnode *vol;
414 struct cnode *dev;
415 struct DosList *dlv;
417 iofs->IOFS.io_Error = ERROR_NO_FREE_STORE;
419 fhv = (struct filehandle*)AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
421 if (fhv != NULL)
423 fhc = (struct filehandle*)AllocMem(sizeof(struct filehandle),
424 MEMF_CLEAR);
426 if (fhc != NULL)
428 vol = (struct vnode *)AllocMem(sizeof(struct vnode), MEMF_CLEAR);
430 if (vol != NULL)
432 dev = (struct cnode *)AllocMem(sizeof(struct cnode),
433 MEMF_CLEAR);
435 if (dev != NULL)
437 vol->name = Strdup(rambase, "Ram Disk");
439 if (vol->name != NULL)
441 dlv = MakeDosEntry("Ram Disk", DLT_VOLUME);
443 if (dlv != NULL)
445 vol->type = ST_USERDIR;
446 vol->self = vol;
447 vol->doslist = dlv;
448 vol->protect = 0UL;
449 NewList((struct List *)&vol->list);
450 NewList((struct List *)&vol->receivers);
451 fhv->node = (struct dnode *)vol;
452 dlv->dol_Ext.dol_AROS.dol_Unit = (struct Unit *)fhv;
453 dlv->dol_Ext.dol_AROS.dol_Device = &rambase->device;
454 dev->type = ST_LINKDIR;
455 dev->self = dev;
456 dev->volume=vol;
457 fhc->node = (struct dnode *)dev;
458 iofs->IOFS.io_Unit = (struct Unit *)fhc;
459 iofs->IOFS.io_Device = &rambase->device;
460 AddDosEntry(dlv);
461 rambase->root = vol;
462 iofs->IOFS.io_Error = 0;
464 rambase->notifications =
465 HashTable_new(rambase, 100, stringHash,
466 my_strcasecmp, nullDelete);
468 return TRUE;
471 Strfree(rambase, vol->name);
474 FreeMem(dev, sizeof(struct cnode));
477 FreeMem(vol, sizeof(struct vnode));
480 FreeMem(fhc, sizeof(struct filehandle));
483 FreeMem(fhv, sizeof(struct filehandle));
486 iofs->IOFS.io_Error = IOERR_OPENFAIL;
488 return FALSE;
491 static int GM_UNIQUENAME(Expunge)(LIBBASETYPEPTR rambase)
494 This function is single-threaded by exec by calling Forbid.
495 Never break the Forbid() or strange things might happen.
498 /* Kill device task and free all resources */
499 RemTask(rambase->port->mp_SigTask);
500 FreeMem(rambase->sigsem, sizeof(struct SignalSemaphore));
501 FreeMem(((struct Task *)rambase->port->mp_SigTask)->tc_SPLower,
502 AROS_STACKSIZE);
503 FreeMem(rambase->port->mp_SigTask, sizeof(struct Task));
504 FreeMem(rambase->port, sizeof(struct MsgPort));
505 CloseLibrary((struct Library *)rambase->utilitybase);
506 CloseLibrary((struct Library *)rambase->dosbase);
508 return TRUE;
512 AROS_LH1(void, beginio,
513 AROS_LHA(struct IOFileSys *, iofs, A1),
514 struct rambase *, rambase, 5, Ram)
516 AROS_LIBFUNC_INIT
518 /* WaitIO will look into this */
519 iofs->IOFS.io_Message.mn_Node.ln_Type = NT_MESSAGE;
521 /* Nothing is done quick */
522 iofs->IOFS.io_Flags &= ~IOF_QUICK;
524 /* So let the device task do it */
525 PutMsg(rambase->port, &iofs->IOFS.io_Message);
527 AROS_LIBFUNC_EXIT
531 AROS_LH1(LONG, abortio,
532 AROS_LHA(struct IOFileSys *, iofs, A1),
533 struct rambase *, rambase, 6, Ram)
535 AROS_LIBFUNC_INIT
536 return 0;
537 AROS_LIBFUNC_EXIT
541 static LONG getblock(struct rambase *rambase, struct fnode *file, LONG block,
542 int mode, UBYTE **result)
544 ULONG a, i;
545 UBYTE **p, **p2;
547 if (block < 0x10)
549 p = &file->blocks[block];
550 block= 0 ;
551 i = 0;
553 else if (block < 0x410)
555 block -= 0x10;
556 p = (UBYTE **)&file->iblocks[block/0x100];
557 block &= 0xff;
558 i = 1;
560 else if(block < 0x10410)
562 block -= 0x410;
563 p = (UBYTE **)&file->i2block;
564 i = 2;
566 else
568 block -= 0x10410;
569 p = (UBYTE **)&file->i3block;
570 i = 3;
573 switch (mode)
575 case -1:
576 p2 = (UBYTE **)*p;
578 if (!block)
580 *p = NULL;
583 p = p2;
585 while (i-- && p != NULL)
587 a = (block >> i*8) & 0xff;
588 p2 = (UBYTE **)p[a];
590 if (!(block & ((1 << i*8) - 1)))
592 p[a] = NULL;
594 if (!a)
596 FreeMem(p, PBLOCKSIZE);
600 p = p2;
603 if (p != NULL)
605 FreeMem(p, BLOCKSIZE);
608 break;
610 case 0:
611 p = (UBYTE **)*p;
613 while (i-- && p != NULL)
615 p = ((UBYTE ***)p)[(block >> i*8) & 0xff];
618 *result = (UBYTE *)p;
619 break;
621 case 1:
622 while (i--)
624 if (*p == NULL)
626 *p= AllocMem(PBLOCKSIZE, MEMF_CLEAR);
628 if (*p == NULL)
630 return ERROR_NO_FREE_STORE;
634 p = (UBYTE **)*p + ((block >> i*8) & 0xff);
637 if (*p == NULL)
639 *p = AllocMem(BLOCKSIZE, MEMF_CLEAR);
641 if (*p == NULL)
643 return ERROR_NO_FREE_STORE;
647 *result = *p;
648 break;
649 } /* switch (mode) */
651 return 0;
655 static void zerofill(UBYTE *address, ULONG size)
657 while (size--)
659 *address++ = 0;
664 static void shrinkfile(struct rambase *rambase, struct fnode *file, LONG size)
666 ULONG blocks, block;
667 UBYTE *p;
669 blocks = (size + BLOCKSIZE - 1)/BLOCKSIZE;
670 block = (file->size + BLOCKSIZE - 1)/BLOCKSIZE;
672 for(;block-- > blocks;)
674 (void)getblock(rambase, file, block, -1, &p);
677 if (size & 0xff)
679 (void)getblock(rambase, file, size, 0, &p);
681 if (p != NULL)
683 zerofill(p + (size & 0xff), -size & 0xff);
687 file->size = size;
691 static void delete(struct rambase *rambase, struct fnode *file)
693 struct hnode *link, *new, *more;
694 struct Node *node;
696 Strfree(rambase, file->name);
697 Strfree(rambase, file->comment);
698 Remove((struct Node *)file);
700 if (file->type == ST_LINKDIR)
702 /* It is a link. Remove it from the chain. */
704 link = ((struct hnode *)file)->orig;
705 ((struct hnode *)file)->orig = NULL;
706 file->type = link->type;
708 while((struct fnode *)link->link != file)
710 link = link->link;
713 link->link = file->link;
715 else if (file->link != NULL)
717 /* If there is a hard link to the object make the link the original */
719 link = file->link;
720 link->type = file->type;
721 more = new->link;
723 while (more != NULL)
725 more->orig = new;
726 more = more->link;
729 switch (file->type)
731 case ST_USERDIR:
732 while((node = RemHead((struct List *)&((struct dnode *)file)->list)) != NULL)
733 AddTail((struct List *)&((struct dnode *)file)->list, node);
734 break;
736 case ST_FILE:
737 CopyMemQuick(&file->size, &((struct fnode *)new)->size,
738 sizeof(struct fnode) - offsetof(struct fnode, size));
739 zerofill((UBYTE *)&file->size,
740 sizeof(struct fnode) - offsetof(struct fnode, size));
741 break;
743 case ST_SOFTLINK:
744 ((struct snode *)new)->contents = ((struct snode *)file)->contents;
745 ((struct snode *)file)->contents = NULL;
746 break;
748 } /* else if (file->link != NULL) */
750 switch (file->type)
752 case ST_USERDIR:
753 Notify_directoryChange(rambase, NOTIFY_Delete, (struct dnode *)file);
755 FreeMem(file, sizeof(struct dnode));
757 return;
759 case ST_FILE:
760 Notify_fileChange(rambase, NOTIFY_Delete, file);
762 shrinkfile(rambase, file, 0);
763 FreeMem(file, sizeof(struct fnode));
765 return;
767 case ST_SOFTLINK:
768 Strfree(rambase, ((struct snode *)file)->contents);
769 FreeMem(file, sizeof(struct snode));
771 return;
776 static int fstrcmp(struct rambase *rambase, CONST_STRPTR s1, CONST_STRPTR s2)
778 for (;;)
780 if (ToLower(*s1) != ToLower(*s2))
782 return *s1 || *s2 != '/';
785 if (!*s1)
787 return 0;
790 s1++;
791 s2++;
796 /* Find a node for a given name */
797 static LONG findname(struct rambase *rambase, CONST_STRPTR *name,
798 struct dnode **dnode)
800 struct dnode *cur = *dnode;
801 CONST_STRPTR rest = *name;
803 for (;;)
805 if (cur->type == ST_LINKDIR)
807 cur = (struct dnode *)((struct hnode *)cur)->orig;
810 if (!*rest)
812 break;
815 if (*rest == '/')
817 if ((struct dnode *)cur->volume == cur)
819 return ERROR_OBJECT_NOT_FOUND;
822 while (cur->node.mln_Pred != NULL)
824 cur = (struct dnode *)cur->node.mln_Pred;
827 cur = (struct dnode *)((BYTE *)cur - offsetof(struct dnode, list));
829 else
831 if (cur->type == ST_SOFTLINK)
833 *dnode = cur;
834 *name = rest;
836 return ERROR_IS_SOFT_LINK;
839 if (cur->type != ST_USERDIR)
841 return ERROR_DIR_NOT_FOUND;
844 *dnode = cur;
845 cur = (struct dnode *)cur->list.mlh_Head;
847 for (;;)
849 if (cur->node.mln_Succ == NULL)
851 *name = rest;
853 return ERROR_OBJECT_NOT_FOUND;
856 if (!fstrcmp(rambase, cur->name, rest))
858 break;
861 cur = (struct dnode *)cur->node.mln_Succ;
865 while (*rest)
867 if (*rest++ == '/')
869 break;
874 *dnode = cur;
876 return 0;
880 static LONG set_file_size(struct rambase *rambase, struct filehandle *handle,
881 QUAD *offp, LONG mode)
883 struct fnode *file = (struct fnode *)handle->node;
884 QUAD size = *offp;
886 if (file->type != ST_FILE)
888 return ERROR_OBJECT_WRONG_TYPE;
891 switch(mode)
893 case OFFSET_BEGINNING:
894 break;
896 case OFFSET_CURRENT:
897 size += handle->position;
898 break;
900 case OFFSET_END:
901 size += file->size;
902 break;
904 default:
905 return ERROR_NOT_IMPLEMENTED;
908 if (size < 0)
910 return ERROR_SEEK_ERROR;
913 if (size < file->size)
915 shrinkfile(rambase, file, size);
918 file->size = *offp = size;
920 return 0;
924 static LONG read(struct rambase *rambase, struct filehandle *handle,
925 APTR buffer, LONG *numbytes)
927 struct fnode *file = (struct fnode *)handle->node;
928 ULONG num = *numbytes;
929 ULONG size = file->size;
930 ULONG block, offset;
931 UBYTE *buf = buffer, *p;
933 if (handle->position >= size)
935 num = 0;
937 else if (handle->position + num > size)
939 num = size - handle->position;
942 block = handle->position/BLOCKSIZE;
943 offset = handle->position & (BLOCKSIZE - 1);
944 size = BLOCKSIZE - offset;
946 while (num)
948 if (size > num)
950 size = num;
953 (void)getblock(rambase, file, block, 0, &p);
955 if (p != NULL)
957 CopyMem(p + offset, buffer, size);
959 else
961 zerofill(buffer, size);
964 buffer += size;
965 num -= size;
966 block++;
967 offset = 0;
968 size = BLOCKSIZE;
971 *numbytes = (UBYTE *)buffer - buf;
972 handle->position += *numbytes;
974 return 0;
978 static LONG write(struct rambase *rambase, struct filehandle *handle,
979 UBYTE *buffer, LONG *numbytes)
981 struct fnode *file = (struct fnode *)handle->node;
982 ULONG num = *numbytes;
983 ULONG size = file->size;
984 ULONG block, offset;
985 UBYTE *buf = buffer, *p;
986 LONG error = 0;
988 if ((LONG)(handle->position + num) < 0)
990 return ERROR_OBJECT_TOO_LARGE;
993 Notify_fileChange(rambase, NOTIFY_Write, file);
995 block = handle->position/BLOCKSIZE;
996 offset = handle->position & (BLOCKSIZE - 1);
997 size = BLOCKSIZE - offset;
999 while (num)
1001 if (size > num)
1003 size = num;
1006 error = getblock(rambase, file, block, 1, &p);
1008 if (error)
1010 break;
1013 CopyMem(buffer, p + offset, size);
1014 buffer += size;
1015 num -= size;
1016 block++;
1017 offset = 0;
1018 size = BLOCKSIZE;
1021 *numbytes = (UBYTE *)buffer - buf;
1022 handle->position += *numbytes;
1023 DateStamp(&file->date);
1025 if (handle->position > file->size)
1027 file->size = handle->position;
1030 return error;
1034 static LONG lock(struct dnode *dir, ULONG mode)
1036 if ((mode & FMF_EXECUTE) && (dir->protect & FMF_EXECUTE))
1038 return ERROR_NOT_EXECUTABLE;
1041 if ((mode & FMF_WRITE) && (dir->protect & FMF_WRITE))
1043 return ERROR_WRITE_PROTECTED;
1046 if ((mode & FMF_READ) && (dir->protect & FMF_READ))
1048 return ERROR_READ_PROTECTED;
1051 if (mode & FMF_LOCK)
1053 if (dir->usecount)
1055 return ERROR_OBJECT_IN_USE;
1058 dir->usecount = ((ULONG)~0)/2 + 1;
1060 else
1062 if (dir->usecount < 0)
1064 return ERROR_OBJECT_IN_USE;
1068 dir->usecount++;
1069 dir->volume->volcount++;
1071 return 0;
1075 static LONG open_(struct rambase *rambase, struct filehandle **handle,
1076 CONST_STRPTR name, ULONG mode)
1078 struct dnode *dir = (*handle)->node;
1079 struct filehandle *fh;
1080 LONG error;
1082 fh = (struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1084 if (fh != NULL)
1086 error = findname(rambase, &name, &dir);
1088 if (!error)
1090 error = lock(dir, mode);
1092 if (!error)
1094 fh->node = dir;
1095 *handle = fh;
1097 if (dir->type == ST_FILE)
1099 Notify_fileChange(rambase, NOTIFY_Open,
1100 (struct fnode *)dir);
1102 else if (dir->type == ST_USERDIR)
1104 D(kprintf("Notifying OPEN at dir %s\n", dir->name));
1105 Notify_directoryChange(rambase, NOTIFY_Open, dir);
1108 return 0;
1112 FreeMem(fh, sizeof(struct filehandle));
1114 else
1116 error = ERROR_NO_FREE_STORE;
1119 return error;
1123 static LONG open_file(struct rambase *rambase, struct filehandle **handle,
1124 CONST_STRPTR name, ULONG mode, ULONG protect)
1126 struct dnode *dir = (*handle)->node;
1127 struct filehandle *fh;
1128 LONG error = 0;
1130 fh = AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1132 if (fh != NULL)
1134 error = findname(rambase, &name, &dir);
1136 if ((mode & FMF_CREATE) && error == ERROR_OBJECT_NOT_FOUND)
1138 CONST_STRPTR s = name;
1139 struct fnode *file;
1141 while (*s)
1143 if (*s++ == '/')
1145 return error;
1149 file = (struct fnode *)AllocMem(sizeof(struct fnode), MEMF_CLEAR);
1150 DateStamp(&file->date);
1152 if (file != NULL)
1154 file->name = Strdup(rambase, name);
1156 if (file->name != NULL)
1158 file->type = ST_FILE;
1159 file->protect = protect;
1160 file->volume = dir->volume;
1161 NewList((struct List *)&file->receivers);
1162 AddTail((struct List *)&dir->list, (struct Node *)file);
1163 error = lock((struct dnode *)file, mode);
1165 if (!error)
1167 fh->node = (struct dnode *)file;
1168 *handle = fh;
1170 Notify_fileChange(rambase, NOTIFY_Add, file);
1172 return 0;
1175 Strfree(rambase, file->name);
1178 FreeMem(file,sizeof(struct fnode));
1181 error = ERROR_NO_FREE_STORE;
1183 else if (!error)
1185 if (dir->type != ST_FILE)
1187 error = ERROR_OBJECT_WRONG_TYPE;
1189 else
1191 error = lock(dir, mode);
1193 if (!error)
1195 /* stegerg */
1196 if (mode & FMF_CLEAR)
1198 shrinkfile(rambase, (struct fnode *)dir, 0);
1199 dir->protect = protect;
1201 /* end stegerg */
1203 fh->node = dir;
1204 *handle = fh;
1206 return 0;
1209 } /* else if (!error) */
1211 FreeMem(fh, sizeof(struct filehandle));
1214 return error;
1218 static LONG create_dir(struct rambase *rambase, struct filehandle **handle,
1219 CONST_STRPTR name, ULONG protect)
1221 struct dnode *dir = (*handle)->node, *new;
1222 struct filehandle *fh;
1223 LONG error;
1225 if (dir->protect & FIBF_WRITE)
1227 return ERROR_WRITE_PROTECTED;
1230 error = findname(rambase, &name, &dir);
1232 if (!error)
1234 return ERROR_OBJECT_EXISTS;
1237 if (error != ERROR_OBJECT_NOT_FOUND)
1239 return error;
1242 if (strchr(name, '/') != NULL)
1244 return error;
1247 fh = AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1249 if (fh != NULL)
1251 new = (struct dnode *)AllocMem(sizeof(struct dnode), MEMF_CLEAR);
1253 if (new != NULL)
1255 new->name = Strdup(rambase, name);
1257 if (new->name != NULL)
1259 new->type = ST_USERDIR;
1260 new->protect = protect;
1261 new->volume = dir->volume;
1262 new->volume->volcount++;
1263 new->usecount = ((ULONG)~0)/2 + 2;
1264 NewList((struct List *)&new->list);
1265 NewList((struct List *)&new->receivers);
1266 AddTail((struct List *)&dir->list, (struct Node *)new);
1267 fh->node = new;
1268 *handle = fh;
1269 DateStamp(&new->date);
1271 D(bug("New (%p): Name = %s\n", new, new->name));
1272 Notify_directoryChange(rambase, NOTIFY_Add, new);
1274 return 0;
1277 FreeMem(new, sizeof(struct dnode));
1280 FreeMem(fh, sizeof(struct filehandle));
1283 return ERROR_NO_FREE_STORE;
1287 static LONG free_lock(struct rambase *rambase, struct filehandle *filehandle)
1289 struct dnode *dnode = filehandle->node;
1291 dnode->usecount = (dnode->usecount - 1) & ((ULONG)~0)/2;
1292 FreeMem(filehandle, sizeof(struct filehandle));
1293 dnode->volume->volcount--;
1295 return 0;
1299 static LONG seek(struct rambase *rambase, struct filehandle *filehandle,
1300 QUAD *posp, LONG mode)
1302 struct fnode *file = (struct fnode *)filehandle->node;
1303 QUAD pos = *posp;
1305 if (file->type != ST_FILE)
1307 return ERROR_OBJECT_WRONG_TYPE;
1310 switch (mode)
1312 case OFFSET_BEGINNING:
1313 break;
1315 case OFFSET_CURRENT:
1316 pos += filehandle->position;
1317 break;
1319 case OFFSET_END:
1320 pos += file->size;
1321 break;
1323 default:
1324 return ERROR_NOT_IMPLEMENTED;
1327 if (pos < 0)
1329 return ERROR_SEEK_ERROR;
1332 *posp = filehandle->position;
1333 filehandle->position = pos;
1335 return 0;
1339 static const ULONG sizes[]=
1342 offsetof(struct ExAllData,ed_Type),
1343 offsetof(struct ExAllData,ed_Size),
1344 offsetof(struct ExAllData,ed_Prot),
1345 offsetof(struct ExAllData,ed_Days),
1346 offsetof(struct ExAllData,ed_Comment),
1347 offsetof(struct ExAllData,ed_OwnerUID),
1348 sizeof(struct ExAllData)
1352 static LONG examine(struct fnode *file,
1353 struct ExAllData *ead,
1354 ULONG size,
1355 ULONG type,
1356 LONG *dirpos)
1358 STRPTR next, end, name;
1360 if (type > ED_OWNER)
1362 return ERROR_BAD_NUMBER;
1365 next = (STRPTR)ead + sizes[type];
1366 end = (STRPTR)ead + size;
1368 if(next>end) /* > is correct. Not >= */
1369 return ERROR_BUFFER_OVERFLOW;
1371 /* Use *dirpos to store information for ExNext()
1372 * *dirpos is copied to fib->fib_DiskKey in Examine()
1374 if (file->type == ST_USERDIR)
1376 *dirpos = (LONG)(((struct dnode*)file)->list.mlh_Head);
1378 else
1380 /* ExNext() should not be called in this case anyway */
1381 *dirpos = (LONG)file;
1384 switch(type)
1386 case ED_OWNER:
1387 ead->ed_OwnerUID = 0;
1388 ead->ed_OwnerGID = 0;
1390 /* Fall through */
1391 case ED_COMMENT:
1392 if (file->comment != NULL)
1394 ead->ed_Comment = next;
1395 name = file->comment;
1397 for (;;)
1399 if (next >= end)
1401 return ERROR_BUFFER_OVERFLOW;
1404 if (!(*next++ = *name++))
1406 break;
1410 else
1412 ead->ed_Comment = NULL;
1415 /* Fall through */
1416 case ED_DATE:
1417 ead->ed_Days = file->date.ds_Days;
1418 ead->ed_Mins = file->date.ds_Minute;
1419 ead->ed_Ticks = file->date.ds_Tick;
1421 /* Fall through */
1422 case ED_PROTECTION:
1423 ead->ed_Prot = file->protect;
1425 /* Fall through */
1426 case ED_SIZE:
1427 ead->ed_Size = file->size;
1429 /* Fall through */
1430 case ED_TYPE:
1431 ead->ed_Type = file->type;
1433 if (((struct vnode *)file)->self == (struct vnode *)file)
1435 ead->ed_Type=ST_ROOT;
1438 /* Fall through */
1439 case ED_NAME:
1440 ead->ed_Name = next;
1441 name = file->name;
1443 for (;;)
1445 if (next >= end)
1447 return ERROR_BUFFER_OVERFLOW;
1450 if (!(*next++ = *name++))
1452 break;
1456 /* Fall through */
1457 case 0:
1458 ead->ed_Next = (struct ExAllData *)(((IPTR)next + AROS_PTRALIGN - 1) & ~(AROS_PTRALIGN - 1));
1461 return 0;
1465 static LONG examine_next(struct rambase *rambase,
1466 struct filehandle *dir,
1467 struct FileInfoBlock *FIB)
1469 struct fnode *file = (struct fnode *)FIB->fib_DiskKey;
1471 ASSERT_VALID_PTR_OR_NULL(file);
1473 if (file->node.mln_Succ == NULL)
1475 return ERROR_NO_MORE_ENTRIES;
1478 FIB->fib_OwnerUID = 0;
1479 FIB->fib_OwnerGID = 0;
1481 FIB->fib_Date.ds_Days = file->date.ds_Days;
1482 FIB->fib_Date.ds_Minute = file->date.ds_Minute;
1483 FIB->fib_Date.ds_Tick = file->date.ds_Tick;
1484 FIB->fib_Protection = file->protect;
1485 FIB->fib_Size = file->size;
1486 FIB->fib_DirEntryType = file->type;
1488 strncpy(FIB->fib_FileName, file->name, MAXFILENAMELENGTH - 1);
1489 strncpy(FIB->fib_Comment, file->comment != NULL ? file->comment : "",
1490 MAXCOMMENTLENGTH - 1);
1492 FIB->fib_DiskKey = (LONG)file->node.mln_Succ;
1494 return 0;
1498 static LONG examine_all(struct filehandle *dir,
1499 struct ExAllData *ead,
1500 struct ExAllControl *eac,
1501 ULONG size,
1502 ULONG type)
1504 STRPTR end;
1505 struct ExAllData *last=NULL;
1506 struct fnode *ent;
1507 LONG error;
1508 LONG dummy; /* not anything is done with this value but passed to examine */
1509 end = (STRPTR)ead + size;
1511 eac->eac_Entries = 0;
1512 if (dir->node->type != ST_USERDIR)
1514 return ERROR_OBJECT_WRONG_TYPE;
1517 ent = (struct fnode *)eac->eac_LastKey;
1519 if (ent == NULL)
1521 ent = (struct fnode *)dir->node->list.mlh_Head;
1522 if (ent->node.mln_Succ) ent->usecount++;
1525 if (ent->node.mln_Succ == NULL)
1527 return ERROR_NO_MORE_ENTRIES;
1530 ent->usecount--;
1534 error = examine(ent, ead, end - (STRPTR)ead, type, &dummy);
1536 if (error == ERROR_BUFFER_OVERFLOW)
1538 if (last == NULL)
1540 return error;
1543 ent->usecount++;
1544 last->ed_Next = NULL;
1545 eac->eac_LastKey = (IPTR)ent;
1547 return 0;
1549 eac->eac_Entries++;
1550 last = ead;
1551 ead = ead->ed_Next;
1552 ent = (struct fnode *)ent->node.mln_Succ;
1554 } while (ent->node.mln_Succ != NULL);
1556 last->ed_Next = NULL;
1557 eac->eac_LastKey = (IPTR)ent;
1559 return ERROR_NO_MORE_ENTRIES;
1563 static LONG rename_object(struct rambase *rambase,
1564 struct filehandle *filehandle,
1565 CONST_STRPTR namea, CONST_STRPTR nameb)
1567 struct dnode *file = filehandle->node;
1568 LONG error = 0, i;
1570 struct dnode *nodea = filehandle->node, *nodeb;
1571 STRPTR dira, dirb, pos = nameb;
1573 error = findname(rambase, &pos, &nodea);
1574 if (!error)
1575 return ERROR_OBJECT_EXISTS;
1577 error = findname(rambase, &namea, &file);
1578 if (error)
1579 return error;
1581 if ((struct dnode *)file->volume == file)
1582 return ERROR_OBJECT_WRONG_TYPE;
1584 if (file->usecount != 0)
1585 return ERROR_OBJECT_IN_USE;
1587 dira = Strdup(rambase, namea);
1588 dirb = Strdup(rambase, nameb);
1590 pos = strrchr(dira, '/');
1591 if (pos)
1593 *pos = '\0';
1594 namea = ++pos;
1596 else
1597 *dira = '\0';
1599 pos = strrchr(dirb, '/');
1600 if (pos)
1602 *pos = '\0';
1603 nameb = ++pos;
1605 else
1606 *dirb = '\0';
1608 D(bug("[Ram] rename (%s,%s)=>(%s,%s)\n", dira, namea, dirb, nameb));
1610 if (*dira == '\0' && *dirb == '\0')
1612 Strfree(rambase, file->name);
1613 file->name = Strdup(rambase, nameb);
1615 else
1617 nodea = filehandle->node;
1618 error = findname(rambase, &dira, &nodea);
1619 if (error)
1620 goto cleanup;
1622 nodeb = filehandle->node;
1623 error = findname(rambase, &dirb, &nodeb);
1624 if (error)
1625 goto cleanup;
1627 if (nodeb != nodea)
1629 Remove((struct Node *)file);
1630 AddTail((struct List *)&nodeb->list, (struct Node *)file);
1633 Strfree(rambase, file->name);
1634 file->name = Strdup(rambase, nameb);
1637 DateStamp(&file->date);
1639 switch (file->type)
1641 case ST_FILE:
1642 Notify_fileChange(rambase, NOTIFY_Delete, (struct fnode *)file);
1643 Notify_fileChange(rambase, NOTIFY_Add, (struct fnode *)file);
1644 break;
1645 case ST_USERDIR:
1646 default:
1647 Notify_directoryChange(rambase, NOTIFY_Delete, file);
1648 Notify_directoryChange(rambase, NOTIFY_Add, file);
1649 break;
1652 cleanup:
1653 Strfree(rambase, dirb);
1654 Strfree(rambase, dira);
1656 return error;
1659 static LONG delete_object(struct rambase *rambase,
1660 struct filehandle *filehandle, CONST_STRPTR name)
1662 struct dnode *file = filehandle->node;
1663 LONG error;
1665 error = findname(rambase, &name, &file);
1667 if (error)
1669 return error;
1672 if ((struct dnode *)file->volume == file)
1674 return ERROR_OBJECT_WRONG_TYPE;
1677 if (file->usecount != 0)
1679 return ERROR_OBJECT_IN_USE;
1682 if (file->protect & FIBF_DELETE)
1684 return ERROR_DELETE_PROTECTED;
1687 if (file->type == ST_USERDIR && file->list.mlh_Head->mln_Succ != NULL)
1689 return ERROR_DIRECTORY_NOT_EMPTY;
1692 delete(rambase, (struct fnode *)file);
1694 return 0;
1698 static int GM_UNIQUENAME(Close)
1700 LIBBASETYPEPTR rambase,
1701 struct IOFileSys *iofs
1704 struct cnode *dev;
1705 struct vnode *vol;
1706 struct dnode *dir;
1707 struct fnode *file;
1709 struct filehandle *handle;
1711 handle = (struct filehandle *)iofs->IOFS.io_Unit;
1712 dev = (struct cnode *)handle->node;
1713 vol = dev->volume;
1715 if (dev->type != ST_LINKDIR || dev->self != dev)
1717 iofs->io_DosError = ERROR_OBJECT_WRONG_TYPE;
1719 return 0;
1722 if (vol->volcount)
1724 iofs->io_DosError = ERROR_OBJECT_IN_USE;
1726 return 0;
1729 free_lock(rambase, handle);
1730 RemDosEntry(vol->doslist);
1731 FreeDosEntry(vol->doslist);
1733 while (vol->list.mlh_Head->mln_Succ != NULL)
1735 dir = (struct dnode *)vol->list.mlh_Head;
1737 if (dir->type == ST_USERDIR)
1739 while((file = (struct fnode *)RemHead((struct List *)&dir->list)) != NULL)
1741 AddTail((struct List *)&vol->list, (struct Node *)dir);
1745 delete(rambase, (struct fnode *)dir);
1748 Strfree(rambase, vol->name);
1749 FreeMem(vol, sizeof(struct vnode));
1751 Strfree(rambase, dev->name);
1752 FreeMem(dev, sizeof(struct cnode));
1754 iofs->io_DosError = 0;
1756 return TRUE;
1760 void processFSM(struct rambase *rambase);
1763 static void deventry(struct rambase *rambase)
1765 ULONG notifyMask;
1766 ULONG fileOpMask;
1767 struct Message *msg;
1770 Init device port. AllocSignal() cannot fail because this is a
1771 freshly created task with all signal bits still free.
1774 rambase->port->mp_SigBit = AllocSignal(-1);
1775 rambase->port->mp_Flags = PA_SIGNAL;
1777 /* Check if there are pending messages that we missed */
1778 if ((msg = GetMsg(rambase->port))) PutMsg(rambase->port, msg);
1780 Notify_initialize(rambase);
1782 notifyMask = 1 << rambase->notifyPort->mp_SigBit;
1784 fileOpMask = 1 << rambase->port->mp_SigBit;
1786 while (TRUE)
1788 ULONG flags;
1790 flags = Wait(fileOpMask | notifyMask);
1792 if (flags & notifyMask)
1794 struct NotifyMessage *nMessage;
1796 D(kprintf("Got replied notify message\n"));
1798 while ((nMessage = (struct NotifyMessage *)GetMsg(rambase->notifyPort)) != NULL)
1800 nMessage->nm_NReq->nr_Flags &= ~NRF_NOT_REPLIED;
1801 FreeVec(nMessage);
1805 if (flags & fileOpMask)
1807 processFSM(rambase);
1813 void processFSM(struct rambase *rambase)
1815 struct IOFileSys *iofs;
1816 struct dnode *dir;
1818 LONG error = 0;
1820 /* Get and process the messages. */
1821 while ((iofs = (struct IOFileSys *)GetMsg(rambase->port)) != NULL)
1823 D(bug("Ram.handler initialized %u\n", iofs->IOFS.io_Command));
1825 switch (iofs->IOFS.io_Command)
1827 case FSA_OPEN:
1829 get handle on a file or directory
1830 Unit *current; current directory / new handle on return
1831 STRPTR name; file- or directoryname
1832 LONG mode; open mode
1835 error = open_(rambase,
1836 (struct filehandle **)&iofs->IOFS.io_Unit,
1837 iofs->io_Union.io_OPEN.io_Filename,
1838 iofs->io_Union.io_OPEN.io_FileMode);
1839 break;
1841 case FSA_OPEN_FILE:
1843 open a file or create a new one
1844 Unit *current; current directory / new handle on return
1845 STRPTR name; file- or directoryname
1846 LONG mode; open mode
1847 LONG protect; protection flags if a new file is created
1850 error = open_file(rambase,
1851 (struct filehandle **)&iofs->IOFS.io_Unit,
1852 iofs->io_Union.io_OPEN_FILE.io_Filename,
1853 iofs->io_Union.io_OPEN_FILE.io_FileMode,
1854 iofs->io_Union.io_OPEN_FILE.io_Protection);
1855 break;
1857 case FSA_READ:
1859 read a number of bytes from a file
1860 Unit *current; filehandle
1861 APTR buffer; data
1862 LONG numbytes; number of bytes to read /
1863 number of bytes read on return,
1864 0 if there are no more bytes in the file
1866 error = read(rambase,
1867 (struct filehandle *)iofs->IOFS.io_Unit,
1868 iofs->io_Union.io_READ.io_Buffer,
1869 &iofs->io_Union.io_READ.io_Length);
1870 break;
1872 case FSA_WRITE:
1874 write a number of bytes to a file
1875 Unit *current; filehandle
1876 APTR buffer; data
1877 LONG numbytes; number of bytes to write /
1878 number of bytes written on return
1880 error = write(rambase,
1881 (struct filehandle *)iofs->IOFS.io_Unit,
1882 iofs->io_Union.io_WRITE.io_Buffer,
1883 &iofs->io_Union.io_WRITE.io_Length);
1884 break;
1886 case FSA_SEEK:
1888 set / read position in file
1889 Unit *current; filehandle
1890 LONG posh;
1891 LONG posl; relative position /
1892 old position on return
1893 LONG mode; one of OFFSET_BEGINNING, OFFSET_CURRENT,
1894 OFFSET_END
1896 error = seek(rambase,
1897 (struct filehandle *)iofs->IOFS.io_Unit,
1898 &iofs->io_Union.io_SEEK.io_Offset,
1899 iofs->io_Union.io_SEEK.io_SeekMode);
1900 break;
1902 case FSA_CLOSE:
1904 /* Get rid of a handle
1905 Unit *current; filehandle */
1907 struct filehandle *handle =
1908 (struct filehandle *)iofs->IOFS.io_Unit;
1910 Notify_fileChange(rambase, NOTIFY_Close,
1911 (struct fnode *)handle->node);
1912 error = free_lock(rambase, handle);
1913 break;
1916 case FSA_EXAMINE:
1918 Get information about the current object
1919 Unit *current; current object
1920 struct ExAllData *ead; buffer to be filled
1921 ULONG size; size of the buffer
1922 ULONG type; type of information to get
1923 iofs->io_DirPos; leave current position so
1924 ExNext() knows where to find
1925 next object
1927 error = examine((struct fnode *)((struct filehandle *)iofs->IOFS.io_Unit)->node,
1928 iofs->io_Union.io_EXAMINE.io_ead,
1929 iofs->io_Union.io_EXAMINE.io_Size,
1930 iofs->io_Union.io_EXAMINE.io_Mode,
1931 &(iofs->io_DirPos));
1932 break;
1934 case FSA_EXAMINE_NEXT:
1936 Get information about the next object
1937 Unit *current; current object
1938 struct FileInfoBlock *fib;
1940 error = examine_next(rambase,
1941 (struct filehandle *)iofs->IOFS.io_Unit,
1942 iofs->io_Union.io_EXAMINE_NEXT.io_fib);
1943 break;
1945 case FSA_EXAMINE_ALL:
1947 Read the current directory
1948 Unit *current; current directory
1949 struct ExAllData *ead; buffer to be filled
1950 ULONG size; size of the buffer
1951 ULONG type; type of information to get
1953 error = examine_all((struct filehandle *)iofs->IOFS.io_Unit,
1954 iofs->io_Union.io_EXAMINE_ALL.io_ead,
1955 iofs->io_Union.io_EXAMINE_ALL.io_eac,
1956 iofs->io_Union.io_EXAMINE_ALL.io_Size,
1957 iofs->io_Union.io_EXAMINE_ALL.io_Mode);
1958 break;
1960 case FSA_CREATE_DIR:
1962 Build lock and open a new directory
1963 Unit *current; current directory
1964 STRPTR name; name of the dir to create
1965 LONG protect; Protection flags for the new dir
1968 // kprintf("Creating directory %s\n",
1969 // iofs->io_Union.io_CREATE_DIR.io_Filename);
1972 error = create_dir(rambase,
1973 (struct filehandle **)&iofs->IOFS.io_Unit,
1974 iofs->io_Union.io_CREATE_DIR.io_Filename,
1975 iofs->io_Union.io_CREATE_DIR.io_Protection);
1976 break;
1978 case FSA_DELETE_OBJECT:
1980 Delete file or directory
1981 Unit *current; current directory
1982 STRPTR name; filename
1984 error = delete_object(rambase,
1985 (struct filehandle *)iofs->IOFS.io_Unit,
1986 iofs->io_Union.io_DELETE_OBJECT.io_Filename);
1987 break;
1989 case FSA_SET_PROTECT:
1992 Set protection bits for a certain file or directory.
1993 Unit *current; current directory
1994 STRPTR name; filename
1995 ULONG protect; new protection bits
1998 CONST_STRPTR name = iofs->io_Union.io_SET_PROTECT.io_Filename;
2000 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
2001 error = findname(rambase, &name, &dir);
2003 if (!error)
2005 dir->protect = iofs->io_Union.io_SET_PROTECT.io_Protection;
2008 break;
2011 case FSA_SET_OWNER:
2014 Set owner and group of the file or directory
2015 Unit *current; current directory
2016 STRPTR name; filename
2017 ULONG UID;
2018 ULONG GID;
2021 CONST_STRPTR name = iofs->io_Union.io_SET_OWNER.io_Filename;
2023 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
2024 error = findname(rambase, &name, &dir);
2026 if(!error)
2030 break;
2033 case FSA_SET_DATE:
2036 Set creation date of the file
2037 Unit *current; current directory
2038 STRPTR name; filename
2039 ULONG days;
2040 ULONG mins;
2041 ULONG ticks; timestamp
2044 CONST_STRPTR name = iofs->io_Union.io_SET_DATE.io_Filename;
2046 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
2047 error = findname(rambase, &name, &dir);
2049 if(!error)
2051 dir->date = iofs->io_Union.io_SET_DATE.io_Date;
2054 break;
2057 case FSA_SET_COMMENT:
2060 Set a comment for the file or directory;
2061 Unit *current; current directory
2062 STRPTR name; filename
2063 STRPTR comment; NUL terminated C string or NULL.
2066 CONST_STRPTR name = iofs->io_Union.io_SET_COMMENT.io_Filename;
2068 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
2069 error = findname(rambase, &name, &dir);
2071 if (!error)
2073 if (iofs->io_Union.io_SET_COMMENT.io_Comment)
2075 STRPTR s = Strdup(rambase,
2076 iofs->io_Union.io_SET_COMMENT.io_Comment);
2077 if (s != NULL)
2079 Strfree(rambase, dir->comment);
2080 dir->comment = s;
2082 else
2084 error = ERROR_NO_FREE_STORE;
2087 else
2089 Strfree(rambase, dir->comment);
2090 dir->comment = NULL;
2094 break;
2097 case FSA_SET_FILE_SIZE:
2099 Set a new size for the file.
2100 Unit *file; filehandle
2101 LONG offh;
2102 LONG offl; offset to current position/
2103 new size on return
2104 LONG mode; relative to what (see Seek)
2106 error = set_file_size(rambase,
2107 (struct filehandle *)iofs->IOFS.io_Unit,
2108 &iofs->io_Union.io_SET_FILE_SIZE.io_Offset,
2109 iofs->io_Union.io_SET_FILE_SIZE.io_SeekMode);
2110 break;
2112 case FSA_IS_FILESYSTEM:
2113 iofs->io_Union.io_IS_FILESYSTEM.io_IsFilesystem = TRUE;
2114 error = 0;
2115 break;
2117 case FSA_DISK_INFO:
2119 struct InfoData *id = iofs->io_Union.io_INFO.io_Info;
2121 id->id_NumSoftErrors = 0;
2122 id->id_UnitNumber = 0;
2123 id->id_DiskState = ID_VALIDATED;
2124 id->id_NumBlocks = AvailMem(MEMF_TOTAL | MEMF_PUBLIC)/BLOCKSIZE;
2125 id->id_NumBlocksUsed = id->id_NumBlocks - AvailMem(MEMF_PUBLIC)/BLOCKSIZE;
2126 id->id_BytesPerBlock = BLOCKSIZE;
2127 id->id_DiskType = ID_DOS_DISK;
2128 id->id_VolumeNode = NULL; /* What is this? */
2129 id->id_InUse = (LONG)TRUE;
2131 error = 0;
2134 break;
2137 case FSA_ADD_NOTIFY:
2139 BOOL ok;
2140 struct NotifyRequest *nr =
2141 iofs->io_Union.io_NOTIFY.io_NotificationRequest;
2142 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
2144 D(kprintf("Adding notification for entity (nr = %s)\n",
2145 nr->nr_FullName));
2147 ok = Notify_addNotification(rambase, fh->node, nr);
2149 if (!ok)
2151 error = ERROR_NO_FREE_STORE;
2154 D(kprintf("Notification now added!\n"));
2156 break;
2158 case FSA_REMOVE_NOTIFY:
2160 struct NotifyRequest *nr =
2161 iofs->io_Union.io_NOTIFY.io_NotificationRequest;
2163 Notify_removeNotification(rambase, nr);
2165 break;
2167 case FSA_RENAME:
2168 error = rename_object(rambase,
2169 (struct filehandle *)iofs->IOFS.io_Unit,
2170 iofs->io_Union.io_RENAME.io_Filename,
2171 iofs->io_Union.io_RENAME.io_NewName);
2172 break;
2174 case FSA_IS_INTERACTIVE:
2175 iofs->io_Union.io_IS_INTERACTIVE.io_IsInteractive = 0;
2176 break;
2178 default:
2179 error = ERROR_NOT_IMPLEMENTED;
2181 D(kprintf("ram_handler, unimplemented FSA: %ld\n", iofs->IOFS.io_Command));
2182 break;
2184 FSA_FILE_MODE
2185 Change or read the mode of a single filehandle
2186 Unit *current; filehandle to change
2187 ULONG newmode; new mode/old mode on return
2188 ULONG mask; bits affected
2190 FSA_MOUNT_MODE
2191 Change or read the mode of the filesystem
2192 Unit *current; filesystem to change
2193 ULONG newmode; new mode/old mode on return
2194 ULONG mask; bits affected
2195 STRPTR passwd; password for MMF_LOCKED
2197 FSA_MAKE_HARDLINK
2198 Create a hard link on a file, directory or soft link
2199 Unit *current; current directory
2200 STRPTR name; softlink name
2201 Unit *target; target handle
2203 FSA_MAKE_SOFTLINK
2204 Create a soft link to another object
2205 Unit *current; current directory
2206 STRPTR name; softlink name
2207 STRPTR target; target name
2209 FSA_READ_LINK
2210 FSA_SERIALIZE_DISK
2211 FSA_WAIT_CHAR
2212 FSA_INFO
2213 FSA_TIMER
2214 FSA_DISK_TYPE
2215 FSA_DISK_CHANGE
2216 FSA_SAME_LOCK
2217 FSA_CHANGE_SIGNAL
2218 FSA_FORMAT
2219 FSA_EXAMINE_ALL
2220 FSA_EXAMINE_FH
2221 FSA_EXAMINE_ALL_END
2226 iofs->io_DosError = error;
2227 ReplyMsg(&iofs->IOFS.io_Message);
2230 #if 0
2231 if (rambase->iofs != NULL)
2233 iofs = rambase->iofs;
2235 if (iofs->IOFS.io_Message.mn_Node.ln_Type == NT_MESSAGE)
2237 abort_notify(rambase, iofs);
2238 iofs->io_DosError = ERROR_BREAK;
2239 rambase->iofs = NULL;
2240 ReplyMsg(&iofs->IOFS.io_Message);
2242 else
2244 rambase->iofs = NULL;
2245 Signal(1, 0);
2248 #endif
2255 /***************************************************************************
2256 ****************************************************************************/
2258 /** Notification stuff **/
2261 * Immediate notification:
2263 * ACTION_RENAME_OBJECT
2264 * ACTION_RENAME_DISK
2265 * ACTION_CREATE_DIR
2266 * ACTION_DELETE_OBJECT
2267 * ACTION_SET_DATE
2270 * Session semantics notification:
2272 * ACTION_WRITE
2273 * ACTION_FINDUPDATE
2274 * ACTION_FINDOUTPUT
2275 * ACTION_SET_FILE_SIZE
2278 * For ram-handler, the only FSA actions currently implemented/affected are
2279 * FSA_WRITE, FSA_CREATE_DIR, FSA_DELETE (and implicitly FSA_OPEN, FSA_CLOSE)
2284 BOOL Notify_initialize(struct rambase *rambase)
2286 rambase->notifyPort = CreateMsgPort();
2288 if (rambase->notifyPort == NULL)
2290 return FALSE;
2293 return TRUE;
2297 void Notify_fileChange(struct rambase *rambase, NType type, struct fnode *file)
2299 switch (type)
2301 case NOTIFY_Open:
2302 break;
2304 case NOTIFY_Write:
2305 D(bug("Setting write flag!\n"));
2306 file->flags |= FILEFLAGS_Changed;
2307 break;
2309 case NOTIFY_Close:
2310 /* Only notify in case the file was changed */
2311 if (file->flags & FILEFLAGS_Changed)
2313 D(bug("Notification on close (file was changed).\n"));
2314 file->flags &= ~FILEFLAGS_Changed;
2315 Notify_notifyTasks(rambase, &file->receivers);
2317 break;
2319 case NOTIFY_Add:
2321 STRPTR fullName;
2322 struct List *receivers;
2324 fullName = getName(rambase, (struct dnode *)file);
2326 D(kprintf("Found full name: %s\n", fullName));
2328 receivers = HashTable_find(rambase, rambase->notifications,
2329 fullName);
2331 if (receivers != NULL)
2333 D(kprintf("Found notification for created file!\n"));
2335 while (!IsListEmpty(receivers))
2337 AddHead((struct List *)&file->receivers,
2338 RemHead(receivers));
2342 HashTable_remove(rambase, rambase->notifications, fullName);
2344 D(bug("Notifying file receivers!\n"));
2345 Notify_notifyTasks(rambase, &file->receivers);
2347 FreeVec(fullName);
2349 break;
2351 case NOTIFY_Delete:
2352 /* It's the same thing as for directories... */
2353 Notify_directoryChange(rambase, NOTIFY_Delete, (struct dnode *)file);
2354 break;
2356 default:
2357 kprintf("Error\n");
2358 break;
2363 void Notify_directoryChange(struct rambase *rambase, NType type,
2364 struct dnode *dir)
2366 switch (type)
2368 case NOTIFY_Open:
2370 STRPTR fullName;
2372 fullName = getName(rambase, dir);
2374 /* TODO: HashTable_apply(ht, fullName, dir); */
2376 FreeVec(fullName);
2378 break;
2380 case NOTIFY_Add:
2382 STRPTR fullName;
2383 struct List *receivers;
2385 fullName = getName(rambase, dir);
2387 D(kprintf("Found full name: %s\n", fullName));
2389 receivers = HashTable_find(rambase, rambase->notifications,
2390 fullName);
2392 if (receivers != NULL)
2394 D(kprintf("Found notification for created directory!\n"));
2396 while (!IsListEmpty(receivers))
2398 AddHead((struct List *)&dir->receivers,
2399 RemHead(receivers));
2403 HashTable_remove(rambase, rambase->notifications, fullName);
2405 FreeVec(fullName);
2408 D(kprintf("Notifying dir receivers!\n"));
2409 Notify_notifyTasks(rambase, &dir->receivers);
2410 break;
2412 case NOTIFY_Delete:
2414 /* As we have deleted a file, we must move the requests for
2415 this file to the hash table */
2416 struct List *receivers = (struct List *)&dir->receivers;
2418 Notify_notifyTasks(rambase, &dir->receivers);
2420 /* Move the Notification request to the hash table as we're going
2421 to delete this directory */
2422 while (!IsListEmpty(receivers))
2424 struct Receiver *rr = (struct Receiver *)RemHead(receivers);
2426 HashTable_insert(rambase, rambase->notifications,
2427 rr->nr->nr_FullName, rr);
2431 break;
2433 default:
2434 kprintf("Error\n");
2435 break;
2438 // kprintf("Returning from Notify_dirChange()\n");
2442 /* TODO: Implement support for NRF_WAIT_REPLY */
2443 void Notify_notifyTasks(struct rambase *rambase, struct MinList *notifications)
2445 struct Receiver *rr;
2447 // kprintf("Inside notifytasks, not = %p\n", notifications);
2449 ForeachNode((struct List *)notifications, rr)
2451 struct NotifyRequest *nr = rr->nr;
2453 if (nr->nr_Flags & NRF_SEND_MESSAGE &&
2454 !(nr->nr_Flags & NRF_WAIT_REPLY && nr->nr_Flags & NRF_NOT_REPLIED))
2456 struct NotifyMessage *nm = AllocVec(sizeof(struct NotifyMessage),
2457 MEMF_PUBLIC | MEMF_CLEAR);
2459 if (nm == NULL)
2461 return;
2464 nm->nm_ExecMessage.mn_ReplyPort = rambase->notifyPort;
2465 nm->nm_ExecMessage.mn_Length = sizeof(struct NotifyMessage);
2466 nm->nm_NReq = nr;
2467 nr->nr_Flags |= NRF_NOT_REPLIED;
2469 PutMsg(nr->nr_stuff.nr_Msg.nr_Port, &nm->nm_ExecMessage);
2471 else if (nr->nr_Flags & NRF_SEND_SIGNAL)
2473 Signal(nr->nr_stuff.nr_Signal.nr_Task,
2474 1 << nr->nr_stuff.nr_Signal.nr_SignalNum);
2479 /* also defined in rom/dos/filesystem_support.c */
2480 STRPTR RamStripVolume(STRPTR name)
2482 STRPTR path = strchr(name, ':');
2483 if (path != NULL)
2484 path++;
2485 else
2486 path = name;
2487 return path;
2490 BOOL Notify_addNotification(struct rambase *rambase, struct dnode *dn,
2491 struct NotifyRequest *nr)
2493 struct dnode *dnTemp = dn;
2494 HashTable *ht = rambase->notifications;
2495 STRPTR name = nr->nr_FullName;
2496 CONST_STRPTR tname = RamStripVolume(name);
2498 /* First: Check if the file is opened */
2499 D(bug("Checking existence of %s\n", tname));
2501 if (findname(rambase, &tname, &dnTemp) == 0)
2503 /* This file was already opened (or at least known by the file
2504 system) */
2506 struct Receiver *rr = AllocVec(sizeof(struct Receiver), MEMF_CLEAR);
2508 if (rr == NULL)
2510 return FALSE;
2513 rr->nr = nr;
2515 if (nr->nr_Flags & NRF_NOTIFY_INITIAL)
2517 struct MinList tempList;
2519 /* Create a temporary list on the stack and add the receiver to
2520 it. Then forget about this and add the node to the receiver
2521 list (below this block). */
2522 NewList((struct List *)&tempList);
2523 AddHead((struct List *)&tempList, &rr->node);
2524 Notify_notifyTasks(rambase, &tempList);
2527 /* Add the receiver node to the file's/directory's list of receivers */
2528 AddTail((struct List *)&dnTemp->receivers, &rr->node);
2530 D(bug("Notification added to node: %s\n", name));
2532 return TRUE;
2534 else
2536 /* This file is not opened */
2538 struct Receiver *rr = AllocVec(sizeof(struct Receiver), MEMF_CLEAR);
2540 if (rr == NULL)
2542 return FALSE;
2545 rr->nr = nr;
2547 HashTable_insert(rambase, ht, name, rr);
2549 return TRUE;
2554 void Notify_removeNotification(struct rambase *rambase,
2555 struct NotifyRequest *nr)
2557 struct dnode *dn = (struct dnode *)rambase->root;
2558 struct Receiver *rr, *rrTemp;
2559 STRPTR name = nr->nr_FullName;
2560 CONST_STRPTR tname = RamStripVolume(name);
2561 struct List *receivers;
2562 BOOL fromTable = FALSE;
2564 if (findname(rambase, &tname, &dn) == 0)
2566 receivers = (struct List *)&dn->receivers;
2568 else
2570 /* This was a request for an entity that doesn't exist yet */
2571 receivers = HashTable_find(rambase, rambase->notifications, name);
2573 if (receivers == NULL)
2575 D(bug("Ram: This should not happen! -- buggy application...\n"));
2576 return;
2579 fromTable = TRUE;
2582 ForeachNodeSafe(&receivers, rr, rrTemp)
2584 if (rr->nr == nr)
2586 Remove((struct Node *)rr);
2587 FreeVec(rr);
2588 break;
2592 if (fromTable)
2594 /* If we removed a request for a file that doesn't exist yet --
2595 if this was the only notification request for that file, remove
2596 also the hash entry. */
2597 if (IsListEmpty((struct List *)receivers))
2599 HashTable_remove(rambase, rambase->notifications, name);
2604 static STRPTR getName(struct rambase *rambase, struct dnode *dn)
2606 struct dnode *dnTemp = dn;
2608 ULONG length;
2609 STRPTR fullName;
2610 CONST_STRPTR slash = "/";
2611 CONST_STRPTR nextSlash = slash;
2612 ULONG partLen;
2614 /* First, calculate the size of the complete filename */
2615 length = strlen(dn->name) + 2; /* Add trailing 0 byte and possible '/' */
2617 while (findname(rambase, &slash, &dnTemp) == 0)
2619 slash = nextSlash;
2620 length += 1 + strlen(dnTemp->name); /* Add '/' byte */
2623 /* The MEMF_CLEAR is necessary for the while loop below to work */
2624 fullName = AllocVec(length, MEMF_PUBLIC | MEMF_CLEAR);
2626 if (fullName == NULL)
2628 return NULL;
2631 dnTemp = dn;
2632 fullName += length - 1;
2634 fullName -= strlen(dn->name) + 1;
2635 strcpy(fullName, dn->name);
2637 slash = "/";
2638 nextSlash = slash;
2639 while (findname(rambase, &slash, &dnTemp) != ERROR_OBJECT_NOT_FOUND)
2641 slash = nextSlash;
2642 partLen = strlen(dnTemp->name);
2644 fullName -= partLen + 1;
2645 strcpy(fullName, dnTemp->name);
2647 if ((struct vnode *)dnTemp == dnTemp->volume)
2648 fullName[partLen] = ':'; /* Root of Ram Disk */
2649 else
2650 fullName[partLen] = '/'; /* Replace 0 with '/' */
2653 return fullName;
2656 ADD2INITLIB(GM_UNIQUENAME(Init),0)
2657 ADD2OPENDEV(GM_UNIQUENAME(Open),0)
2658 ADD2CLOSEDEV(GM_UNIQUENAME(Close),0)
2659 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge),0)