added reentrant time functions
[tangerine.git] / workbench / devs / ram_handler / ram_handler.c
blob54ed8035b74ae4fbf9e7e8e82e0de517b8ac50d4
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 RAM: handler.
6 */
8 #define INKERNEL 1
11 #define DEBUG 0
12 #include <aros/debug.h>
14 #include <exec/errors.h>
15 #include <exec/types.h>
16 #include <exec/resident.h>
17 #include <exec/memory.h>
18 #include <exec/semaphores.h>
19 #include <utility/tagitem.h>
20 #include <proto/exec.h>
21 #include <proto/utility.h>
22 #include <proto/alib.h>
23 #include <proto/dos.h>
24 #include <dos/dos.h>
25 #include <dos/dosextens.h>
26 #include <dos/dosasl.h>
27 #include <dos/exall.h>
28 #include <dos/filesystem.h>
29 #include <aros/libcall.h>
30 #include <aros/symbolsets.h>
32 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
33 #include "ram_handler_gcc.h"
34 #endif
35 #include <stddef.h>
36 #include <string.h>
37 #include <ctype.h>
39 #include "HashTable.h"
41 extern void deventry();
43 #include LC_LIBDEFS_FILE
45 #define NRF_NOT_REPLIED NRF_MAGIC
48 /* Device node */
49 struct cnode
51 struct MinNode node;
52 LONG type; /* ST_LINKDIR */
53 char *name; /* Link's name */
54 struct cnode *self; /* Pointer to top of structure */
55 struct hnode *link; /* NULL */
56 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
57 ULONG protect; /* 0 */
58 char *comment; /* NULL */
59 struct vnode *volume; /* Pointer to volume */
60 struct DosList *doslist; /* Pointer to doslist entry */
63 /* Volume node */
64 struct vnode
66 struct MinNode node;
67 LONG type; /* ST_USERDIR */
68 char *name; /* Directory name */
69 struct vnode *self; /* Points to top of structure */
70 struct hnode *link; /* This one is linked to me */
71 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
72 ULONG protect; /* 0 */
73 char *comment; /* NULL */
74 struct MinList receivers;
75 struct MinList list; /* Contents of directory */
76 ULONG volcount; /* number of handles on this volume */
77 struct DosList *doslist; /* Pointer to doslist entry */
80 /* Directory node */
81 struct dnode
83 struct MinNode node;
84 LONG type; /* ST_USERDIR */
85 char *name; /* Directory name */
86 struct vnode *volume; /* Volume's root directory */
87 struct hnode *link; /* This one is linked to me */
88 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
89 ULONG protect; /* protection bits */
90 char *comment; /* Some comment */
91 struct MinList receivers;
92 struct MinList list; /* Contents of directory */
95 /* File node */
96 struct fnode
98 struct MinNode node;
99 LONG type; /* ST_FILE */
100 char *name; /* Filename */
101 struct vnode *volume; /* Volume's root directory */
102 struct hnode *link; /* This one is linked to me */
103 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
104 ULONG protect; /* protection bits */
105 char *comment; /* Some file comment */
106 struct MinList receivers;
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 char *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 char *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 char *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 char *comment; /* Some file comment */
140 struct hnode *orig; /* original object */
143 /*****************************************************************************/
145 #define FILEFLAGS_Changed 1
147 STRPTR getName(struct rambase *rambase, struct dnode *dn, STRPTR name);
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 typedef struct _HashNode
175 struct Node node;
176 void *key;
177 struct List requests;
178 } HashNode;
181 /****************************************************************************/
184 #define BLOCKSIZE 256
185 #define PBLOCKSIZE (256*sizeof(UBYTE *))
187 struct filehandle
189 struct dnode *node;
190 IPTR position;
193 /* Use This from now on */
194 #ifdef DOSBase
195 #undef DOSBase
196 #endif
197 #define DOSBase rambase->dosbase
199 static int OpenDev(LIBBASETYPEPTR rambase, struct IOFileSys *iofs);
201 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR rambase)
203 /* This function is single-threaded by exec by calling Forbid. */
205 struct MsgPort *port;
206 struct Task *task;
207 struct SignalSemaphore *semaphore;
208 APTR stack;
210 rambase->dosbase = (struct DosLibrary *)OpenLibrary("dos.library",39);
212 if (rambase->dosbase != NULL)
214 rambase->utilitybase = (struct UtilityBase *)OpenLibrary("utility.library",39);
216 if (rambase->utilitybase!=NULL)
218 port = (struct MsgPort *)AllocMem(sizeof(struct MsgPort),
219 MEMF_PUBLIC | MEMF_CLEAR);
220 if (port != NULL)
222 rambase->port = port;
223 NewList(&port->mp_MsgList);
224 port->mp_Node.ln_Type = NT_MSGPORT;
225 port->mp_SigBit = SIGB_SINGLE;
227 task = (struct Task *)AllocMem(sizeof(struct Task),
228 MEMF_PUBLIC | MEMF_CLEAR);
230 if (task != NULL)
232 port->mp_SigTask = task;
233 port->mp_Flags = PA_IGNORE;
234 NewList(&task->tc_MemEntry);
235 task->tc_Node.ln_Type = NT_TASK;
236 task->tc_Node.ln_Name = "ram.handler task";
238 stack = AllocMem(AROS_STACKSIZE, MEMF_PUBLIC);
240 if (stack != NULL)
242 struct TagItem tasktags[] =
244 {TASKTAG_ARG1, (IPTR)rambase},
245 {TAG_DONE }
248 task->tc_SPLower = stack;
249 task->tc_SPUpper = (BYTE *)stack + AROS_STACKSIZE;
250 #if AROS_STACK_GROWS_DOWNWARDS
251 task->tc_SPReg = (BYTE *)task->tc_SPUpper - SP_OFFSET;
252 #else
253 task->tc_SPReg = (BYTE *)task->tc_SPLower + SP_OFFSET;
254 #endif
256 semaphore = (struct SignalSemaphore *)AllocMem(sizeof(struct SignalSemaphore),
257 MEMF_PUBLIC | MEMF_CLEAR);
259 if (semaphore != NULL)
261 rambase->sigsem = semaphore;
262 InitSemaphore(semaphore);
264 if (rambase->seglist==NULL) /* Are we a ROM module? */
266 struct DeviceNode *dn;
267 /* Install RAM: handler into device list
269 * KLUDGE: ram.handler should create only one device node, depending on
270 * the startup packet it gets. The mountlists for RAM: should be into dos.library bootstrap
271 * routines.
274 if((dn = AllocMem(sizeof (struct DeviceNode) + 4 + 3 + 2, MEMF_CLEAR|MEMF_PUBLIC)))
276 struct IOFileSys dummyiofs;
278 if (OpenDev(rambase, &dummyiofs))
280 BSTR s = MKBADDR(((IPTR)dn + sizeof(struct DeviceNode) + 4) & ~3);
282 rambase->device.dd_Library.lib_OpenCnt++;
284 AROS_BSTR_putchar(s, 0, 'R');
285 AROS_BSTR_putchar(s, 1, 'A');
286 AROS_BSTR_putchar(s, 2, 'M');
287 AROS_BSTR_putchar(s, 3, 0);
288 AROS_BSTR_setstrlen(s, 3);
290 dn->dn_Type = DLT_DEVICE;
291 dn->dn_Ext.dn_AROS.dn_Unit = dummyiofs.IOFS.io_Unit;
292 dn->dn_Ext.dn_AROS.dn_Device = dummyiofs.IOFS.io_Device;
293 dn->dn_Handler = NULL;
294 dn->dn_Startup = NULL;
295 dn->dn_Name = s;
296 dn->dn_Ext.dn_AROS.dn_DevName = AROS_BSTR_ADDR(dn->dn_Name);
298 if (AddDosEntry((struct DosList *)dn))
299 if (NewAddTask(task, deventry, NULL, tasktags) != NULL)
300 return TRUE;
303 FreeMem(dn, sizeof (struct DeviceNode));
306 else
307 if (NewAddTask(task, deventry, NULL, tasktags) != NULL)
308 return TRUE;
310 FreeMem(semaphore, sizeof(struct SignalSemaphore));
313 FreeMem(stack, AROS_STACKSIZE);
316 FreeMem(task, sizeof(struct Task));
319 FreeMem(port, sizeof(struct MsgPort));
322 CloseLibrary((struct Library *)rambase->utilitybase);
325 CloseLibrary((struct Library *)rambase->dosbase);
328 return FALSE;
331 #ifdef UtilityBase
332 #undef UtilityBase
333 #endif
334 #define UtilityBase rambase->utilitybase
337 /***************************************************************************/
339 void nullDelete(struct rambase *rambase, void *key, struct List *list)
341 // struct Receiver *rr;
342 // struct Node *tempNode;
344 // ForeachNodeSafe(list, rr, tempNode)
345 // {
346 // Remove(&rr->node);
347 // FreeVec(rr);
348 // }
350 FreeVec(key);
352 /* The list is part of the HashNode so we shouldn't free that */
356 ULONG stringHash(struct rambase *rambase, const void *key)
358 STRPTR str = (STRPTR)key;
359 ULONG val = 1;
361 while (*str != 0)
363 val *= ToLower(*str++);
364 val <<= 2;
367 return val;
370 static int
371 my_strcasecmp(struct rambase *rambase, const void *s1, const void *s2)
373 return strcasecmp(s1, s2);
376 /****************************************************************************/
379 static STRPTR Strdup(struct rambase *rambase, STRPTR string)
381 STRPTR s2 = string,s3;
383 while(*s2++)
386 s3 = (STRPTR)AllocVec(s2 - string, MEMF_ANY);
388 if (s3 != NULL)
390 CopyMem(string, s3, s2 - string);
393 return s3;
397 static void Strfree(struct rambase *rambase, STRPTR string)
399 FreeVec(string);
403 static int GM_UNIQUENAME(Open)
405 LIBBASETYPEPTR rambase,
406 struct IOFileSys *iofs,
407 ULONG unitnum,
408 ULONG flags
411 /* Mark Message as recently used. */
412 iofs->IOFS.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
414 return OpenDev(rambase, iofs);
418 static int OpenDev(LIBBASETYPEPTR rambase, struct IOFileSys *iofs)
420 struct filehandle *fhv, *fhc;
421 struct vnode *vol;
422 struct cnode *dev;
423 struct DosList *dlv;
425 iofs->IOFS.io_Error = ERROR_NO_FREE_STORE;
427 fhv = (struct filehandle*)AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
429 if (fhv != NULL)
431 fhc = (struct filehandle*)AllocMem(sizeof(struct filehandle),
432 MEMF_CLEAR);
434 if (fhc != NULL)
436 vol = (struct vnode *)AllocMem(sizeof(struct vnode), MEMF_CLEAR);
438 if (vol != NULL)
440 dev = (struct cnode *)AllocMem(sizeof(struct cnode),
441 MEMF_CLEAR);
443 if (dev != NULL)
445 vol->name = Strdup(rambase, "Ram Disk");
447 if (vol->name != NULL)
449 dlv = MakeDosEntry("Ram Disk", DLT_VOLUME);
451 if (dlv != NULL)
453 vol->type = ST_USERDIR;
454 vol->self = vol;
455 vol->doslist = dlv;
456 vol->protect = 0UL;
457 NewList((struct List *)&vol->list);
458 NewList((struct List *)&vol->receivers);
459 fhv->node = (struct dnode *)vol;
460 dlv->dol_Ext.dol_AROS.dol_Unit = (struct Unit *)fhv;
461 dlv->dol_Ext.dol_AROS.dol_Device = &rambase->device;
462 dev->type = ST_LINKDIR;
463 dev->self = dev;
464 dev->volume=vol;
465 fhc->node = (struct dnode *)dev;
466 iofs->IOFS.io_Unit = (struct Unit *)fhc;
467 iofs->IOFS.io_Device = &rambase->device;
468 AddDosEntry(dlv);
469 rambase->root = vol;
470 iofs->IOFS.io_Error = 0;
472 rambase->notifications =
473 HashTable_new(rambase, 100, stringHash,
474 my_strcasecmp, nullDelete);
476 return TRUE;
479 Strfree(rambase, vol->name);
482 FreeMem(dev, sizeof(struct cnode));
485 FreeMem(vol, sizeof(struct vnode));
488 FreeMem(fhc, sizeof(struct filehandle));
491 FreeMem(fhv, sizeof(struct filehandle));
494 iofs->IOFS.io_Error = IOERR_OPENFAIL;
496 return FALSE;
499 static int GM_UNIQUENAME(Expunge)(LIBBASETYPEPTR rambase)
502 This function is single-threaded by exec by calling Forbid.
503 Never break the Forbid() or strange things might happen.
506 /* Kill device task and free all resources */
507 RemTask(rambase->port->mp_SigTask);
508 FreeMem(rambase->sigsem, sizeof(struct SignalSemaphore));
509 FreeMem(((struct Task *)rambase->port->mp_SigTask)->tc_SPLower,
510 AROS_STACKSIZE);
511 FreeMem(rambase->port->mp_SigTask, sizeof(struct Task));
512 FreeMem(rambase->port, sizeof(struct MsgPort));
513 CloseLibrary((struct Library *)rambase->utilitybase);
514 CloseLibrary((struct Library *)rambase->dosbase);
516 return TRUE;
520 AROS_LH1(void, beginio,
521 AROS_LHA(struct IOFileSys *, iofs, A1),
522 struct rambase *, rambase, 5, Ram)
524 AROS_LIBFUNC_INIT
526 /* WaitIO will look into this */
527 iofs->IOFS.io_Message.mn_Node.ln_Type = NT_MESSAGE;
529 /* Nothing is done quick */
530 iofs->IOFS.io_Flags &= ~IOF_QUICK;
532 /* So let the device task do it */
533 PutMsg(rambase->port, &iofs->IOFS.io_Message);
535 AROS_LIBFUNC_EXIT
539 AROS_LH1(LONG, abortio,
540 AROS_LHA(struct IOFileSys *, iofs, A1),
541 struct rambase *, rambase, 6, Ram)
543 AROS_LIBFUNC_INIT
544 return 0;
545 AROS_LIBFUNC_EXIT
549 static LONG getblock(struct rambase *rambase, struct fnode *file, LONG block,
550 int mode, UBYTE **result)
552 ULONG a, i;
553 UBYTE **p, **p2;
555 if (block < 0x10)
557 p = &file->blocks[block];
558 block= 0 ;
559 i = 0;
561 else if (block < 0x410)
563 block -= 0x10;
564 p = (UBYTE **)&file->iblocks[block/0x100];
565 block &= 0xff;
566 i = 1;
568 else if(block < 0x10410)
570 block -= 0x410;
571 p = (UBYTE **)&file->i2block;
572 i = 2;
574 else
576 block -= 0x10410;
577 p = (UBYTE **)&file->i3block;
578 i = 3;
581 switch (mode)
583 case -1:
584 p2 = (UBYTE **)*p;
586 if (!block)
588 *p = NULL;
591 p = p2;
593 while (i-- && p != NULL)
595 a = (block >> i*8) & 0xff;
596 p2 = (UBYTE **)p[a];
598 if (!(block & ((1 << i*8) - 1)))
600 p[a] = NULL;
602 if (!a)
604 FreeMem(p, PBLOCKSIZE);
608 p = p2;
611 if (p != NULL)
613 FreeMem(p, BLOCKSIZE);
616 break;
618 case 0:
619 p = (UBYTE **)*p;
621 while (i-- && p != NULL)
623 p = ((UBYTE ***)p)[(block >> i*8) & 0xff];
626 *result = (UBYTE *)p;
627 break;
629 case 1:
630 while (i--)
632 if (*p == NULL)
634 *p= AllocMem(PBLOCKSIZE, MEMF_CLEAR);
636 if (*p == NULL)
638 return ERROR_NO_FREE_STORE;
642 p = (UBYTE **)*p + ((block >> i*8) & 0xff);
645 if (*p == NULL)
647 *p = AllocMem(BLOCKSIZE, MEMF_CLEAR);
649 if (*p == NULL)
651 return ERROR_NO_FREE_STORE;
655 *result = *p;
656 break;
657 } /* switch (mode) */
659 return 0;
663 static void zerofill(UBYTE *address, ULONG size)
665 while (size--)
667 *address++ = 0;
672 static void shrinkfile(struct rambase *rambase, struct fnode *file, LONG size)
674 ULONG blocks, block;
675 UBYTE *p;
677 blocks = (size + BLOCKSIZE - 1)/BLOCKSIZE;
678 block = (file->size + BLOCKSIZE - 1)/BLOCKSIZE;
680 for(;block-- > blocks;)
682 (void)getblock(rambase, file, block, -1, &p);
685 if (size & 0xff)
687 (void)getblock(rambase, file, size, 0, &p);
689 if (p != NULL)
691 zerofill(p + (size & 0xff), -size & 0xff);
695 file->size = size;
699 static void delete(struct rambase *rambase, struct fnode *file)
701 struct hnode *link, *new, *more;
702 struct Node *node;
704 Strfree(rambase, file->name);
705 Strfree(rambase, file->comment);
706 Remove((struct Node *)file);
708 if (file->type == ST_LINKDIR)
710 /* It is a link. Remove it from the chain. */
712 link = ((struct hnode *)file)->orig;
713 ((struct hnode *)file)->orig = NULL;
714 file->type = link->type;
716 while((struct fnode *)link->link != file)
718 link = link->link;
721 link->link = file->link;
723 else if (file->link != NULL)
725 /* If there is a hard link to the object make the link the original */
727 link = file->link;
728 link->type = file->type;
729 more = new->link;
731 while (more != NULL)
733 more->orig = new;
734 more = more->link;
737 switch (file->type)
739 case ST_USERDIR:
740 while((node = RemHead((struct List *)&((struct dnode *)file)->list)) != NULL)
741 AddTail((struct List *)&((struct dnode *)file)->list, node);
742 break;
744 case ST_FILE:
745 CopyMemQuick(&file->size, &((struct fnode *)new)->size,
746 sizeof(struct fnode) - offsetof(struct fnode, size));
747 zerofill((UBYTE *)&file->size,
748 sizeof(struct fnode) - offsetof(struct fnode, size));
749 break;
751 case ST_SOFTLINK:
752 ((struct snode *)new)->contents = ((struct snode *)file)->contents;
753 ((struct snode *)file)->contents = NULL;
754 break;
756 } /* else if (file->link != NULL) */
758 switch (file->type)
760 case ST_USERDIR:
761 Notify_directoryChange(rambase, NOTIFY_Delete, (struct dnode *)file);
763 FreeMem(file, sizeof(struct dnode));
765 return;
767 case ST_FILE:
768 Notify_fileChange(rambase, NOTIFY_Delete, file);
770 shrinkfile(rambase, file, 0);
771 FreeMem(file, sizeof(struct fnode));
773 return;
775 case ST_SOFTLINK:
776 Strfree(rambase, ((struct snode *)file)->contents);
777 FreeMem(file, sizeof(struct snode));
779 return;
784 static int fstrcmp(struct rambase *rambase, char *s1, char *s2)
786 for (;;)
788 if (ToLower(*s1) != ToLower(*s2))
790 return *s1 || *s2 != '/';
793 if (!*s1)
795 return 0;
798 s1++;
799 s2++;
804 /* Find a node for a given name */
805 static LONG findname(struct rambase *rambase, STRPTR *name,
806 struct dnode **dnode)
808 struct dnode *cur = *dnode;
809 char *rest = *name;
811 for (;;)
813 if (cur->type == ST_LINKDIR)
815 cur = (struct dnode *)((struct hnode *)cur)->orig;
818 if (!*rest)
820 break;
823 if (*rest == '/')
825 if ((struct dnode *)cur->volume == cur)
827 return ERROR_OBJECT_NOT_FOUND;
830 while (cur->node.mln_Pred != NULL)
832 cur = (struct dnode *)cur->node.mln_Pred;
835 cur = (struct dnode *)((BYTE *)cur - offsetof(struct dnode, list));
837 else
839 if (cur->type == ST_SOFTLINK)
841 *dnode = cur;
842 *name = rest;
844 return ERROR_IS_SOFT_LINK;
847 if (cur->type != ST_USERDIR)
849 return ERROR_DIR_NOT_FOUND;
852 *dnode = cur;
853 cur = (struct dnode *)cur->list.mlh_Head;
855 for (;;)
857 if (cur->node.mln_Succ == NULL)
859 *name = rest;
861 return ERROR_OBJECT_NOT_FOUND;
864 if (!fstrcmp(rambase, cur->name, rest))
866 break;
869 cur = (struct dnode *)cur->node.mln_Succ;
873 while (*rest)
875 if (*rest++ == '/')
877 break;
882 *dnode = cur;
884 return 0;
888 static LONG set_file_size(struct rambase *rambase, struct filehandle *handle,
889 QUAD *offp, LONG mode)
891 struct fnode *file = (struct fnode *)handle->node;
892 QUAD size = *offp;
894 if (file->type != ST_FILE)
896 return ERROR_OBJECT_WRONG_TYPE;
899 switch(mode)
901 case OFFSET_BEGINNING:
902 break;
904 case OFFSET_CURRENT:
905 size += handle->position;
906 break;
908 case OFFSET_END:
909 size += file->size;
910 break;
912 default:
913 return ERROR_NOT_IMPLEMENTED;
916 if (size < 0)
918 return ERROR_SEEK_ERROR;
921 if (size < file->size)
923 shrinkfile(rambase, file, size);
926 file->size = *offp = size;
928 return 0;
932 static LONG read(struct rambase *rambase, struct filehandle *handle,
933 APTR buffer, LONG *numbytes)
935 struct fnode *file = (struct fnode *)handle->node;
936 ULONG num = *numbytes;
937 ULONG size = file->size;
938 ULONG block, offset;
939 UBYTE *buf = buffer, *p;
941 if (handle->position >= size)
943 num = 0;
945 else if (handle->position + num > size)
947 num = size - handle->position;
950 block = handle->position/BLOCKSIZE;
951 offset = handle->position & (BLOCKSIZE - 1);
952 size = BLOCKSIZE - offset;
954 while (num)
956 if (size > num)
958 size = num;
961 (void)getblock(rambase, file, block, 0, &p);
963 if (p != NULL)
965 CopyMem(p + offset, buffer, size);
967 else
969 zerofill(buffer, size);
972 buffer += size;
973 num -= size;
974 block++;
975 offset = 0;
976 size = BLOCKSIZE;
979 *numbytes = (UBYTE *)buffer - buf;
980 handle->position += *numbytes;
982 return 0;
986 static LONG write(struct rambase *rambase, struct filehandle *handle,
987 UBYTE *buffer, LONG *numbytes)
989 struct fnode *file = (struct fnode *)handle->node;
990 ULONG num = *numbytes;
991 ULONG size = file->size;
992 ULONG block, offset;
993 UBYTE *buf = buffer, *p;
994 LONG error = 0;
996 if ((LONG)(handle->position + num) < 0)
998 return ERROR_OBJECT_TOO_LARGE;
1001 Notify_fileChange(rambase, NOTIFY_Write, file);
1003 block = handle->position/BLOCKSIZE;
1004 offset = handle->position & (BLOCKSIZE - 1);
1005 size = BLOCKSIZE - offset;
1007 while (num)
1009 if (size > num)
1011 size = num;
1014 error = getblock(rambase, file, block, 1, &p);
1016 if (error)
1018 break;
1021 CopyMem(buffer, p + offset, size);
1022 buffer += size;
1023 num -= size;
1024 block++;
1025 offset = 0;
1026 size = BLOCKSIZE;
1029 *numbytes = (UBYTE *)buffer - buf;
1030 handle->position += *numbytes;
1032 if (handle->position > file->size)
1034 file->size = handle->position;
1037 return error;
1041 static LONG lock(struct dnode *dir, ULONG mode)
1043 if ((mode & FMF_EXECUTE) && (dir->protect & FMF_EXECUTE))
1045 return ERROR_NOT_EXECUTABLE;
1048 if ((mode & FMF_WRITE) && (dir->protect & FMF_WRITE))
1050 return ERROR_WRITE_PROTECTED;
1053 if ((mode & FMF_READ) && (dir->protect & FMF_READ))
1055 return ERROR_READ_PROTECTED;
1058 if (mode & FMF_LOCK)
1060 if (dir->usecount)
1062 return ERROR_OBJECT_IN_USE;
1065 dir->usecount = ~0ul/2 + 1;
1067 else
1069 if (dir->usecount < 0)
1071 return ERROR_OBJECT_IN_USE;
1075 dir->usecount++;
1076 dir->volume->volcount++;
1078 return 0;
1082 static LONG open_(struct rambase *rambase, struct filehandle **handle,
1083 STRPTR name, ULONG mode)
1085 struct dnode *dir = (*handle)->node;
1086 struct filehandle *fh;
1087 LONG error;
1089 fh = (struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1091 if (fh != NULL)
1093 error = findname(rambase, &name, &dir);
1095 if (!error)
1097 error = lock(dir, mode);
1099 if (!error)
1101 fh->node = dir;
1102 *handle = fh;
1104 if (dir->type == ST_FILE)
1106 Notify_fileChange(rambase, NOTIFY_Open,
1107 (struct fnode *)dir);
1109 else if (dir->type == ST_USERDIR)
1111 D(kprintf("Notifying OPEN at dir %s\n", dir->name));
1112 Notify_directoryChange(rambase, NOTIFY_Open, dir);
1115 return 0;
1119 FreeMem(fh, sizeof(struct filehandle));
1121 else
1123 error = ERROR_NO_FREE_STORE;
1126 return error;
1130 static LONG open_file(struct rambase *rambase, struct filehandle **handle,
1131 STRPTR name, ULONG mode, ULONG protect)
1133 struct dnode *dir = (*handle)->node;
1134 struct filehandle *fh;
1135 LONG error = 0;
1137 fh = AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1139 if (fh != NULL)
1141 error = findname(rambase, &name, &dir);
1143 if ((mode & FMF_CREATE) && error == ERROR_OBJECT_NOT_FOUND)
1145 char *s = name;
1146 struct fnode *file;
1148 while (*s)
1150 if (*s++ == '/')
1152 return error;
1156 file = (struct fnode *)AllocMem(sizeof(struct fnode), MEMF_CLEAR);
1158 if (file != NULL)
1160 file->name = Strdup(rambase, name);
1162 if (file->name != NULL)
1164 file->type = ST_FILE;
1165 file->protect = protect;
1166 file->volume = dir->volume;
1167 NewList((struct List *)&file->receivers);
1168 AddTail((struct List *)&dir->list, (struct Node *)file);
1169 error = lock((struct dnode *)file, mode);
1171 if (!error)
1173 fh->node = (struct dnode *)file;
1174 *handle = fh;
1176 Notify_fileChange(rambase, NOTIFY_Add, file);
1178 return 0;
1181 Strfree(rambase, file->name);
1184 FreeMem(file,sizeof(struct fnode));
1187 error = ERROR_NO_FREE_STORE;
1189 else if (!error)
1191 if (dir->type != ST_FILE)
1193 error = ERROR_OBJECT_WRONG_TYPE;
1195 else
1197 error = lock(dir, mode);
1199 if (!error)
1201 /* stegerg */
1202 if (mode & FMF_CLEAR)
1204 shrinkfile(rambase, (struct fnode *)dir, 0);
1205 dir->protect = protect;
1207 /* end stegerg */
1209 fh->node = dir;
1210 *handle = fh;
1212 return 0;
1215 } /* else if (!error) */
1217 FreeMem(fh, sizeof(struct filehandle));
1220 return error;
1224 static LONG create_dir(struct rambase *rambase, struct filehandle **handle,
1225 STRPTR name, ULONG protect)
1227 struct dnode *dir = (*handle)->node, *new;
1228 struct filehandle *fh;
1229 LONG error;
1231 if (dir->protect & FIBF_WRITE)
1233 return ERROR_WRITE_PROTECTED;
1236 error = findname(rambase, &name, &dir);
1238 if (!error)
1240 return ERROR_OBJECT_EXISTS;
1243 if (error != ERROR_OBJECT_NOT_FOUND)
1245 return error;
1248 if (strchr(name, '/') != NULL)
1250 return error;
1253 fh = AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1255 if (fh != NULL)
1257 new = (struct dnode *)AllocMem(sizeof(struct dnode), MEMF_CLEAR);
1259 if (new != NULL)
1261 new->name = Strdup(rambase, name);
1263 if (new->name != NULL)
1265 new->type = ST_USERDIR;
1266 new->protect = protect;
1267 new->volume = dir->volume;
1268 new->volume->volcount++;
1269 new->usecount = ~0ul/2 + 2;
1270 NewList((struct List *)&new->list);
1271 NewList((struct List *)&new->receivers);
1272 AddTail((struct List *)&dir->list, (struct Node *)new);
1273 fh->node = new;
1274 *handle = fh;
1276 // kprintf("New (%p): Name = %s\n", new, new->name);
1277 Notify_directoryChange(rambase, NOTIFY_Add, new);
1279 return 0;
1282 FreeMem(new, sizeof(struct dnode));
1285 FreeMem(fh, sizeof(struct filehandle));
1288 return ERROR_NO_FREE_STORE;
1292 static LONG free_lock(struct rambase *rambase, struct filehandle *filehandle)
1294 struct dnode *dnode = filehandle->node;
1296 dnode->usecount = (dnode->usecount - 1) & ~0ul/2;
1297 FreeMem(filehandle, sizeof(struct filehandle));
1298 dnode->volume->volcount--;
1300 return 0;
1304 static LONG seek(struct rambase *rambase, struct filehandle *filehandle,
1305 QUAD *posp, LONG mode)
1307 struct fnode *file = (struct fnode *)filehandle->node;
1308 QUAD pos = *posp;
1310 if (file->type != ST_FILE)
1312 return ERROR_OBJECT_WRONG_TYPE;
1315 switch (mode)
1317 case OFFSET_BEGINNING:
1318 break;
1320 case OFFSET_CURRENT:
1321 pos += filehandle->position;
1322 break;
1324 case OFFSET_END:
1325 pos += file->size;
1326 break;
1328 default:
1329 return ERROR_NOT_IMPLEMENTED;
1332 if (pos < 0)
1334 return ERROR_SEEK_ERROR;
1337 *posp = filehandle->position;
1338 filehandle->position = pos;
1340 return 0;
1344 static const ULONG sizes[]=
1347 offsetof(struct ExAllData,ed_Type),
1348 offsetof(struct ExAllData,ed_Size),
1349 offsetof(struct ExAllData,ed_Prot),
1350 offsetof(struct ExAllData,ed_Days),
1351 offsetof(struct ExAllData,ed_Comment),
1352 offsetof(struct ExAllData,ed_OwnerUID),
1353 sizeof(struct ExAllData)
1357 static LONG examine(struct fnode *file,
1358 struct ExAllData *ead,
1359 ULONG size,
1360 ULONG type,
1361 LONG *dirpos)
1363 STRPTR next, end, name;
1365 if (type > ED_OWNER)
1367 return ERROR_BAD_NUMBER;
1370 next = (STRPTR)ead + sizes[type];
1371 end = (STRPTR)ead + size;
1373 if(next>end) /* > is correct. Not >= */
1374 return ERROR_BUFFER_OVERFLOW;
1376 /* Use *dirpos to store information for ExNext()
1377 * *dirpos is copied to fib->fib_DiskKey in Examine()
1379 if (file->type == ST_USERDIR)
1381 *dirpos = (LONG)(((struct dnode*)file)->list.mlh_Head);
1383 else
1385 /* ExNext() should not be called in this case anyway */
1386 *dirpos = (LONG)file;
1389 switch(type)
1391 case ED_OWNER:
1392 ead->ed_OwnerUID = 0;
1393 ead->ed_OwnerGID = 0;
1395 /* Fall through */
1396 case ED_COMMENT:
1397 if (file->comment != NULL)
1399 ead->ed_Comment = next;
1400 name = file->comment;
1402 for (;;)
1404 if (next >= end)
1406 return ERROR_BUFFER_OVERFLOW;
1409 if (!(*next++ = *name++))
1411 break;
1415 else
1417 ead->ed_Comment = NULL;
1420 /* Fall through */
1421 case ED_DATE:
1422 ead->ed_Days = 0;
1423 ead->ed_Mins = 0;
1424 ead->ed_Ticks = 0;
1426 /* Fall through */
1427 case ED_PROTECTION:
1428 ead->ed_Prot = file->protect;
1430 /* Fall through */
1431 case ED_SIZE:
1432 ead->ed_Size = file->size;
1434 /* Fall through */
1435 case ED_TYPE:
1436 ead->ed_Type = file->type;
1438 if (((struct vnode *)file)->self == (struct vnode *)file)
1440 ead->ed_Type=ST_ROOT;
1443 /* Fall through */
1444 case ED_NAME:
1445 ead->ed_Name = next;
1446 name = file->name;
1448 for (;;)
1450 if (next >= end)
1452 return ERROR_BUFFER_OVERFLOW;
1455 if (!(*next++ = *name++))
1457 break;
1461 /* Fall through */
1462 case 0:
1463 ead->ed_Next = (struct ExAllData *)(((IPTR)next + AROS_PTRALIGN - 1) & ~(AROS_PTRALIGN - 1));
1466 return 0;
1470 static LONG examine_next(struct rambase *rambase,
1471 struct filehandle *dir,
1472 struct FileInfoBlock *FIB)
1474 struct fnode *file = (struct fnode *)FIB->fib_DiskKey;
1476 ASSERT_VALID_PTR_OR_NULL(file);
1478 if (file->node.mln_Succ == NULL)
1480 return ERROR_NO_MORE_ENTRIES;
1483 FIB->fib_OwnerUID = 0;
1484 FIB->fib_OwnerGID = 0;
1486 FIB->fib_Date.ds_Days = 0;
1487 FIB->fib_Date.ds_Minute = 0;
1488 FIB->fib_Date.ds_Tick = 0;
1489 FIB->fib_Protection = file->protect;
1490 FIB->fib_Size = file->size;
1491 FIB->fib_DirEntryType = file->type;
1493 strncpy(FIB->fib_FileName, file->name, MAXFILENAMELENGTH - 1);
1494 strncpy(FIB->fib_Comment, file->comment != NULL ? file->comment : "",
1495 MAXCOMMENTLENGTH - 1);
1497 FIB->fib_DiskKey = (LONG)file->node.mln_Succ;
1499 return 0;
1503 static LONG examine_all(struct filehandle *dir,
1504 struct ExAllData *ead,
1505 struct ExAllControl *eac,
1506 ULONG size,
1507 ULONG type)
1509 STRPTR end;
1510 struct ExAllData *last=NULL;
1511 struct fnode *ent;
1512 LONG error;
1513 LONG dummy; /* not anything is done with this value but passed to examine */
1514 end = (STRPTR)ead + size;
1516 eac->eac_Entries = 0;
1517 if (dir->node->type != ST_USERDIR)
1519 return ERROR_OBJECT_WRONG_TYPE;
1522 ent = (struct fnode *)eac->eac_LastKey;
1524 if (ent == NULL)
1526 ent = (struct fnode *)dir->node->list.mlh_Head;
1527 if (ent->node.mln_Succ) ent->usecount++;
1530 if (ent->node.mln_Succ == NULL)
1532 return ERROR_NO_MORE_ENTRIES;
1535 ent->usecount--;
1539 error = examine(ent, ead, end - (STRPTR)ead, type, &dummy);
1541 if (error == ERROR_BUFFER_OVERFLOW)
1543 if (last == NULL)
1545 return error;
1548 ent->usecount++;
1549 last->ed_Next = NULL;
1550 eac->eac_LastKey = (IPTR)ent;
1552 return 0;
1554 eac->eac_Entries++;
1555 last = ead;
1556 ead = ead->ed_Next;
1557 ent = (struct fnode *)ent->node.mln_Succ;
1559 } while (ent->node.mln_Succ != NULL);
1561 last->ed_Next = NULL;
1562 eac->eac_LastKey = (IPTR)ent;
1564 return ERROR_NO_MORE_ENTRIES;
1568 static LONG delete_object(struct rambase *rambase,
1569 struct filehandle *filehandle, STRPTR name)
1571 struct dnode *file = filehandle->node;
1572 LONG error;
1574 error = findname(rambase, &name, &file);
1576 if (error)
1578 return error;
1581 if ((struct dnode *)file->volume == file)
1583 return ERROR_OBJECT_WRONG_TYPE;
1586 if (file->usecount != 0)
1588 return ERROR_OBJECT_IN_USE;
1591 if (file->protect & FIBF_DELETE)
1593 return ERROR_DELETE_PROTECTED;
1596 if (file->type == ST_USERDIR && file->list.mlh_Head->mln_Succ != NULL)
1598 return ERROR_DIRECTORY_NOT_EMPTY;
1601 delete(rambase, (struct fnode *)file);
1603 return 0;
1607 static int GM_UNIQUENAME(Close)
1609 LIBBASETYPEPTR rambase,
1610 struct IOFileSys *iofs
1613 struct cnode *dev;
1614 struct vnode *vol;
1615 struct dnode *dir;
1616 struct fnode *file;
1618 struct filehandle *handle;
1620 handle = (struct filehandle *)iofs->IOFS.io_Unit;
1621 dev = (struct cnode *)handle->node;
1622 vol = dev->volume;
1624 if (dev->type != ST_LINKDIR || dev->self != dev)
1626 iofs->io_DosError = ERROR_OBJECT_WRONG_TYPE;
1628 return 0;
1631 if (vol->volcount)
1633 iofs->io_DosError = ERROR_OBJECT_IN_USE;
1635 return 0;
1638 free_lock(rambase, handle);
1639 RemDosEntry(vol->doslist);
1640 FreeDosEntry(vol->doslist);
1642 while (vol->list.mlh_Head->mln_Succ != NULL)
1644 dir = (struct dnode *)vol->list.mlh_Head;
1646 if (dir->type == ST_USERDIR)
1648 while((file = (struct fnode *)RemHead((struct List *)&dir->list)) != NULL)
1650 AddTail((struct List *)&vol->list, (struct Node *)dir);
1654 delete(rambase, (struct fnode *)dir);
1657 Strfree(rambase, vol->name);
1658 FreeMem(vol, sizeof(struct vnode));
1660 Strfree(rambase, dev->name);
1661 FreeMem(dev, sizeof(struct cnode));
1663 iofs->io_DosError = 0;
1665 return TRUE;
1669 void processFSM(struct rambase *rambase);
1672 void deventry(struct rambase *rambase)
1674 ULONG notifyMask;
1675 ULONG fileOpMask;
1676 struct Message *msg;
1679 Init device port. AllocSignal() cannot fail because this is a
1680 freshly created task with all signal bits still free.
1683 rambase->port->mp_SigBit = AllocSignal(-1);
1684 rambase->port->mp_Flags = PA_SIGNAL;
1686 /* Check if there are pending messages that we missed */
1687 if ((msg = GetMsg(rambase->port))) PutMsg(rambase->port, msg);
1689 Notify_initialize(rambase);
1691 notifyMask = 1 << rambase->notifyPort->mp_SigBit;
1693 fileOpMask = 1 << rambase->port->mp_SigBit;
1695 while (TRUE)
1697 ULONG flags;
1699 flags = Wait(fileOpMask | notifyMask);
1701 if (flags & notifyMask)
1703 struct NotifyMessage *nMessage;
1705 D(kprintf("Got replied notify message\n"));
1707 while ((nMessage = (struct NotifyMessage *)GetMsg(rambase->notifyPort)) != NULL)
1709 nMessage->nm_NReq->nr_Flags &= ~NRF_NOT_REPLIED;
1710 FreeVec(nMessage);
1714 if (flags & fileOpMask)
1716 processFSM(rambase);
1722 void processFSM(struct rambase *rambase)
1724 struct IOFileSys *iofs;
1725 struct dnode *dir;
1727 LONG error = 0;
1730 /* Get and process the messages. */
1731 while ((iofs = (struct IOFileSys *)GetMsg(rambase->port)) != NULL)
1733 // kprintf("Ram.handler initialized %u\n", iofs->IOFS.io_Command);
1735 switch (iofs->IOFS.io_Command)
1737 case FSA_OPEN:
1739 get handle on a file or directory
1740 Unit *current; current directory / new handle on return
1741 STRPTR name; file- or directoryname
1742 LONG mode; open mode
1745 error = open_(rambase,
1746 (struct filehandle **)&iofs->IOFS.io_Unit,
1747 iofs->io_Union.io_OPEN.io_Filename,
1748 iofs->io_Union.io_OPEN.io_FileMode);
1749 break;
1751 case FSA_OPEN_FILE:
1753 open a file or create a new one
1754 Unit *current; current directory / new handle on return
1755 STRPTR name; file- or directoryname
1756 LONG mode; open mode
1757 LONG protect; protection flags if a new file is created
1760 error = open_file(rambase,
1761 (struct filehandle **)&iofs->IOFS.io_Unit,
1762 iofs->io_Union.io_OPEN_FILE.io_Filename,
1763 iofs->io_Union.io_OPEN_FILE.io_FileMode,
1764 iofs->io_Union.io_OPEN_FILE.io_Protection);
1765 break;
1767 case FSA_READ:
1769 read a number of bytes from a file
1770 Unit *current; filehandle
1771 APTR buffer; data
1772 LONG numbytes; number of bytes to read /
1773 number of bytes read on return,
1774 0 if there are no more bytes in the file
1776 error = read(rambase,
1777 (struct filehandle *)iofs->IOFS.io_Unit,
1778 iofs->io_Union.io_READ.io_Buffer,
1779 &iofs->io_Union.io_READ.io_Length);
1780 break;
1782 case FSA_WRITE:
1784 write a number of bytes to a file
1785 Unit *current; filehandle
1786 APTR buffer; data
1787 LONG numbytes; number of bytes to write /
1788 number of bytes written on return
1790 error = write(rambase,
1791 (struct filehandle *)iofs->IOFS.io_Unit,
1792 iofs->io_Union.io_WRITE.io_Buffer,
1793 &iofs->io_Union.io_WRITE.io_Length);
1794 break;
1796 case FSA_SEEK:
1798 set / read position in file
1799 Unit *current; filehandle
1800 LONG posh;
1801 LONG posl; relative position /
1802 old position on return
1803 LONG mode; one of OFFSET_BEGINNING, OFFSET_CURRENT,
1804 OFFSET_END
1806 error = seek(rambase,
1807 (struct filehandle *)iofs->IOFS.io_Unit,
1808 &iofs->io_Union.io_SEEK.io_Offset,
1809 iofs->io_Union.io_SEEK.io_SeekMode);
1810 break;
1812 case FSA_CLOSE:
1814 /* Get rid of a handle
1815 Unit *current; filehandle */
1817 struct filehandle *handle =
1818 (struct filehandle *)iofs->IOFS.io_Unit;
1820 Notify_fileChange(rambase, NOTIFY_Close,
1821 (struct fnode *)handle->node);
1822 error = free_lock(rambase, handle);
1823 break;
1826 case FSA_EXAMINE:
1828 Get information about the current object
1829 Unit *current; current object
1830 struct ExAllData *ead; buffer to be filled
1831 ULONG size; size of the buffer
1832 ULONG type; type of information to get
1833 iofs->io_DirPos; leave current position so
1834 ExNext() knows where to find
1835 next object
1837 error = examine((struct fnode *)((struct filehandle *)iofs->IOFS.io_Unit)->node,
1838 iofs->io_Union.io_EXAMINE.io_ead,
1839 iofs->io_Union.io_EXAMINE.io_Size,
1840 iofs->io_Union.io_EXAMINE.io_Mode,
1841 &(iofs->io_DirPos));
1842 break;
1844 case FSA_EXAMINE_NEXT:
1846 Get information about the next object
1847 Unit *current; current object
1848 struct FileInfoBlock *fib;
1850 error = examine_next(rambase,
1851 (struct filehandle *)iofs->IOFS.io_Unit,
1852 iofs->io_Union.io_EXAMINE_NEXT.io_fib);
1853 break;
1855 case FSA_EXAMINE_ALL:
1857 Read the current directory
1858 Unit *current; current directory
1859 struct ExAllData *ead; buffer to be filled
1860 ULONG size; size of the buffer
1861 ULONG type; type of information to get
1863 error = examine_all((struct filehandle *)iofs->IOFS.io_Unit,
1864 iofs->io_Union.io_EXAMINE_ALL.io_ead,
1865 iofs->io_Union.io_EXAMINE_ALL.io_eac,
1866 iofs->io_Union.io_EXAMINE_ALL.io_Size,
1867 iofs->io_Union.io_EXAMINE_ALL.io_Mode);
1868 break;
1870 case FSA_CREATE_DIR:
1872 Build lock and open a new directory
1873 Unit *current; current directory
1874 STRPTR name; name of the dir to create
1875 LONG protect; Protection flags for the new dir
1878 // kprintf("Creating directory %s\n",
1879 // iofs->io_Union.io_CREATE_DIR.io_Filename);
1882 error = create_dir(rambase,
1883 (struct filehandle **)&iofs->IOFS.io_Unit,
1884 iofs->io_Union.io_CREATE_DIR.io_Filename,
1885 iofs->io_Union.io_CREATE_DIR.io_Protection);
1886 break;
1888 case FSA_DELETE_OBJECT:
1890 Delete file or directory
1891 Unit *current; current directory
1892 STRPTR name; filename
1894 error = delete_object(rambase,
1895 (struct filehandle *)iofs->IOFS.io_Unit,
1896 iofs->io_Union.io_DELETE_OBJECT.io_Filename);
1897 break;
1899 case FSA_SET_PROTECT:
1902 Set protection bits for a certain file or directory.
1903 Unit *current; current directory
1904 STRPTR name; filename
1905 ULONG protect; new protection bits
1908 STRPTR realName = iofs->io_Union.io_SET_PROTECT.io_Filename;
1910 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
1911 error = findname(rambase, &realName, &dir);
1913 if (!error)
1915 dir->protect = iofs->io_Union.io_SET_PROTECT.io_Protection;
1918 break;
1921 case FSA_SET_OWNER:
1924 Set owner and group of the file or directory
1925 Unit *current; current directory
1926 STRPTR name; filename
1927 ULONG UID;
1928 ULONG GID;
1931 STRPTR realName = iofs->io_Union.io_SET_OWNER.io_Filename;
1933 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
1934 error = findname(rambase, &realName, &dir);
1936 if(!error)
1940 break;
1943 case FSA_SET_DATE:
1946 Set creation date of the file
1947 Unit *current; current directory
1948 STRPTR name; filename
1949 ULONG days;
1950 ULONG mins;
1951 ULONG ticks; timestamp
1954 STRPTR realName = iofs->io_Union.io_SET_DATE.io_Filename;
1956 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
1957 error = findname(rambase, &realName, &dir);
1959 if(!error)
1963 break;
1966 case FSA_SET_COMMENT:
1969 Set a comment for the file or directory;
1970 Unit *current; current directory
1971 STRPTR name; filename
1972 STRPTR comment; NUL terminated C string or NULL.
1975 STRPTR realName = iofs->io_Union.io_SET_COMMENT.io_Filename;
1977 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
1978 error = findname(rambase, &realName, &dir);
1980 if (!error)
1982 if (iofs->io_Union.io_SET_COMMENT.io_Comment)
1984 STRPTR s = Strdup(rambase,
1985 iofs->io_Union.io_SET_COMMENT.io_Comment);
1986 if (s != NULL)
1988 Strfree(rambase, dir->comment);
1989 dir->comment = s;
1991 else
1993 error = ERROR_NO_FREE_STORE;
1996 else
1998 Strfree(rambase, dir->comment);
1999 dir->comment = NULL;
2003 break;
2006 case FSA_SET_FILE_SIZE:
2008 Set a new size for the file.
2009 Unit *file; filehandle
2010 LONG offh;
2011 LONG offl; offset to current position/
2012 new size on return
2013 LONG mode; relative to what (see Seek)
2015 error = set_file_size(rambase,
2016 (struct filehandle *)iofs->IOFS.io_Unit,
2017 &iofs->io_Union.io_SET_FILE_SIZE.io_Offset,
2018 iofs->io_Union.io_SET_FILE_SIZE.io_SeekMode);
2019 break;
2021 case FSA_IS_FILESYSTEM:
2022 iofs->io_Union.io_IS_FILESYSTEM.io_IsFilesystem = TRUE;
2023 error = 0;
2024 break;
2026 case FSA_DISK_INFO:
2028 struct InfoData *id = iofs->io_Union.io_INFO.io_Info;
2030 id->id_NumSoftErrors = 0;
2031 id->id_UnitNumber = 0;
2032 id->id_DiskState = ID_VALIDATED;
2033 id->id_NumBlocks = AvailMem(MEMF_TOTAL | MEMF_PUBLIC)/BLOCKSIZE;
2034 id->id_NumBlocksUsed = id->id_NumBlocks - AvailMem(MEMF_PUBLIC)/BLOCKSIZE;
2035 id->id_BytesPerBlock = BLOCKSIZE;
2036 id->id_DiskType = ID_DOS_DISK;
2037 id->id_VolumeNode = NULL; /* What is this? */
2038 id->id_InUse = (LONG)TRUE;
2040 error = 0;
2043 break;
2046 case FSA_ADD_NOTIFY:
2048 BOOL ok;
2049 struct NotifyRequest *nr =
2050 iofs->io_Union.io_NOTIFY.io_NotificationRequest;
2051 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
2053 D(kprintf("Adding notification for entity (nr = %s)\n",
2054 nr->nr_FullName));
2056 ok = Notify_addNotification(rambase, fh->node, nr);
2058 if (!ok)
2060 error = ERROR_NO_FREE_STORE;
2063 D(kprintf("Notification now added!\n"));
2065 break;
2067 case FSA_REMOVE_NOTIFY:
2069 struct NotifyRequest *nr =
2070 iofs->io_Union.io_NOTIFY.io_NotificationRequest;
2072 Notify_removeNotification(rambase, nr);
2074 break;
2076 default:
2077 error = ERROR_NOT_IMPLEMENTED;
2079 D(kprintf("ram_handler, unimplemented FSA: %ld\n", iofs->IOFS.io_Command));
2080 break;
2082 FSA_FILE_MODE
2083 Change or read the mode of a single filehandle
2084 Unit *current; filehandle to change
2085 ULONG newmode; new mode/old mode on return
2086 ULONG mask; bits affected
2088 FSA_MOUNT_MODE
2089 Change or read the mode of the filesystem
2090 Unit *current; filesystem to change
2091 ULONG newmode; new mode/old mode on return
2092 ULONG mask; bits affected
2093 STRPTR passwd; password for MMF_LOCKED
2095 FSA_MAKE_HARDLINK
2096 Create a hard link on a file, directory or soft link
2097 Unit *current; current directory
2098 STRPTR name; softlink name
2099 Unit *target; target handle
2101 FSA_MAKE_SOFTLINK
2102 Create a soft link to another object
2103 Unit *current; current directory
2104 STRPTR name; softlink name
2105 STRPTR target; target name
2107 FSA_RENAME
2108 FSA_READ_LINK
2109 FSA_SERIALIZE_DISK
2110 FSA_WAIT_CHAR
2111 FSA_INFO
2112 FSA_TIMER
2113 FSA_DISK_TYPE
2114 FSA_DISK_CHANGE
2115 FSA_SAME_LOCK
2116 FSA_CHANGE_SIGNAL
2117 FSA_FORMAT
2118 FSA_EXAMINE_ALL
2119 FSA_EXAMINE_FH
2120 FSA_EXAMINE_ALL_END
2125 iofs->io_DosError = error;
2126 ReplyMsg(&iofs->IOFS.io_Message);
2129 #if 0
2130 if (rambase->iofs != NULL)
2132 iofs = rambase->iofs;
2134 if (iofs->IOFS.io_Message.mn_Node.ln_Type == NT_MESSAGE)
2136 abort_notify(rambase, iofs);
2137 iofs->io_DosError = ERROR_BREAK;
2138 rambase->iofs = NULL;
2139 ReplyMsg(&iofs->IOFS.io_Message);
2141 else
2143 rambase->iofs = NULL;
2144 Signal(1, 0);
2147 #endif
2154 /***************************************************************************
2155 ****************************************************************************/
2157 /** Notification stuff **/
2160 * Immediate notification:
2162 * ACTION_RENAME_OBJECT
2163 * ACTION_RENAME_DISK
2164 * ACTION_CREATE_DIR
2165 * ACTION_DELETE_OBJECT
2166 * ACTION_SET_DATE
2169 * Session semantics notification:
2171 * ACTION_WRITE
2172 * ACTION_FINDUPDATE
2173 * ACTION_FINDOUTPUT
2174 * ACTION_SET_FILE_SIZE
2177 * For ram-handler, the only FSA actions currently implemented/affected are
2178 * FSA_WRITE, FSA_CREATE_DIR, FSA_DELETE (and implicitly FSA_OPEN, FSA_CLOSE)
2183 BOOL Notify_initialize(struct rambase *rambase)
2185 rambase->notifyPort = CreateMsgPort();
2187 if (rambase->notifyPort == NULL)
2189 return FALSE;
2192 return TRUE;
2196 void Notify_fileChange(struct rambase *rambase, NType type, struct fnode *file)
2198 switch (type)
2200 case NOTIFY_Open:
2201 break;
2203 case NOTIFY_Write:
2204 // kprintf("Setting write flag!\n");
2205 file->flags |= FILEFLAGS_Changed;
2206 break;
2208 case NOTIFY_Close:
2209 /* Only notify in case the file was changed */
2210 if (file->flags & FILEFLAGS_Changed)
2212 // kprintf("Notification on close (file was changed).\n");
2213 file->flags &= ~FILEFLAGS_Changed;
2214 Notify_notifyTasks(rambase, &file->receivers);
2216 break;
2218 case NOTIFY_Add:
2220 STRPTR fullName;
2221 struct List *receivers;
2223 fullName = getName(rambase, (struct dnode *)file, "");
2225 D(kprintf("Found full name: %s\n", fullName));
2227 receivers = HashTable_find(rambase, rambase->notifications,
2228 fullName);
2230 if (receivers != NULL)
2232 D(kprintf("Found notification for created file!\n"));
2234 while (!IsListEmpty(receivers))
2236 AddHead((struct List *)&file->receivers,
2237 RemHead(receivers));
2241 HashTable_remove(rambase, rambase->notifications, fullName);
2243 FreeVec(fullName);
2245 break;
2247 case NOTIFY_Delete:
2248 /* It's the same thing as for directories... */
2249 Notify_directoryChange(rambase, NOTIFY_Delete, (struct dnode *)file);
2250 break;
2252 default:
2253 kprintf("Error\n");
2254 break;
2259 void Notify_directoryChange(struct rambase *rambase, NType type,
2260 struct dnode *dir)
2262 switch (type)
2264 case NOTIFY_Open:
2266 STRPTR fullName;
2268 fullName = getName(rambase, dir, "");
2270 /* TODO: HashTable_apply(ht, fullName, dir); */
2272 FreeVec(fullName);
2274 break;
2276 case NOTIFY_Add:
2278 STRPTR fullName;
2279 struct List *receivers;
2281 fullName = getName(rambase, dir, "");
2283 D(kprintf("Found full name: %s\n", fullName));
2285 receivers = HashTable_find(rambase, rambase->notifications,
2286 fullName);
2288 if (receivers != NULL)
2290 D(kprintf("Found notification for created directory!\n"));
2292 while (!IsListEmpty(receivers))
2294 AddHead((struct List *)&dir->receivers,
2295 RemHead(receivers));
2299 HashTable_remove(rambase, rambase->notifications, fullName);
2301 FreeVec(fullName);
2304 D(kprintf("Notifying receivers!\n"));
2305 Notify_notifyTasks(rambase, &dir->receivers);
2306 break;
2308 case NOTIFY_Delete:
2310 /* As we have deleted a file, we must move the requests for
2311 this file to the hash table */
2312 struct List *receivers = (struct List *)&dir->receivers;
2314 Notify_notifyTasks(rambase, &dir->receivers);
2316 /* Move the Notification request to the hash table as we're going
2317 to delete this directory */
2318 while (!IsListEmpty(receivers))
2320 struct Receiver *rr = (struct Receiver *)RemHead(receivers);
2322 HashTable_insert(rambase, rambase->notifications,
2323 rr->nr->nr_FullName, rr);
2327 break;
2329 default:
2330 kprintf("Error\n");
2331 break;
2334 // kprintf("Returning from Notify_dirChange()\n");
2338 /* TODO: Implement support for NRF_WAIT_REPLY */
2339 void Notify_notifyTasks(struct rambase *rambase, struct MinList *notifications)
2341 struct Receiver *rr;
2343 // kprintf("Inside notifytasks, not = %p\n", notifications);
2345 ForeachNode((struct List *)notifications, rr)
2347 struct NotifyRequest *nr = rr->nr;
2349 if (nr->nr_Flags & NRF_SEND_MESSAGE &&
2350 !(nr->nr_Flags & NRF_WAIT_REPLY && nr->nr_Flags & NRF_NOT_REPLIED))
2352 struct NotifyMessage *nm = AllocVec(sizeof(struct NotifyMessage),
2353 MEMF_PUBLIC | MEMF_CLEAR);
2355 if (nm == NULL)
2357 return;
2360 nm->nm_ExecMessage.mn_ReplyPort = rambase->notifyPort;
2361 nm->nm_ExecMessage.mn_Length = sizeof(struct NotifyMessage);
2362 nm->nm_NReq = nr;
2363 nr->nr_Flags |= NRF_NOT_REPLIED;
2365 PutMsg(nr->nr_stuff.nr_Msg.nr_Port, &nm->nm_ExecMessage);
2367 else if (nr->nr_Flags & NRF_SEND_SIGNAL)
2369 Signal(nr->nr_stuff.nr_Signal.nr_Task,
2370 1 << nr->nr_stuff.nr_Signal.nr_SignalNum);
2376 BOOL Notify_addNotification(struct rambase *rambase, struct dnode *dn,
2377 struct NotifyRequest *nr)
2379 struct dnode *dnTemp = dn;
2380 HashTable *ht = rambase->notifications;
2381 STRPTR name = nr->nr_FullName, colon;
2383 colon = strchr(name, ':');
2384 if (colon != NULL)
2385 name = colon + 1;
2387 /* First: Check if the file is opened */
2389 D(kprintf("Checking existence of %s\n", name));
2391 if (findname(rambase, &name, &dnTemp) == 0)
2393 /* This file was already opened (or at least known by the file
2394 system) */
2396 struct Receiver *rr = AllocVec(sizeof(struct Receiver), MEMF_CLEAR);
2398 if (rr == NULL)
2400 return FALSE;
2403 rr->nr = nr;
2405 if (nr->nr_Flags & NRF_NOTIFY_INITIAL)
2407 struct MinList tempList;
2409 /* Create a temporary list on the stack and add the receiver to
2410 it. Then forget about this and add the node to the receiver
2411 list (below this block). */
2412 NewList((struct List *)&tempList);
2413 AddHead((struct List *)&tempList, &rr->node);
2414 Notify_notifyTasks(rambase, &tempList);
2417 /* Add the receiver node to the file's/directory's list of receivers */
2418 AddTail((struct List *)&dnTemp->receivers, &rr->node);
2420 return TRUE;
2422 else
2424 /* This file is not opened */
2426 struct Receiver *rr = AllocVec(sizeof(struct Receiver), MEMF_CLEAR);
2428 if (rr == NULL)
2430 return FALSE;
2433 rr->nr = nr;
2435 HashTable_insert(rambase, ht, name, rr);
2437 return TRUE;
2442 void Notify_removeNotification(struct rambase *rambase,
2443 struct NotifyRequest *nr)
2445 struct dnode *dn = (struct dnode *)rambase->root;
2446 struct Receiver *rr, *rrTemp;
2447 /* STRPTR name = strchr(nr->nr_FullName, '/') + 1; */
2448 STRPTR name = nr->nr_FullName;
2449 struct List *receivers;
2450 BOOL fromTable = FALSE;
2451 STRPTR colon;
2453 colon = strchr(name, ':');
2455 /* Take care of absolute names in nr_Name */
2456 if (colon != NULL)
2458 name = colon + 1;
2461 if (findname(rambase, &name, &dn) == 0)
2463 receivers = (struct List *)&dn->receivers;
2465 else
2467 /* This was a request for an entity that doesn't exist yet */
2468 receivers = HashTable_find(rambase, rambase->notifications, name);
2470 if (receivers == NULL)
2472 kprintf("Ram: This should not happen! -- buggy application...\n");
2473 return;
2476 fromTable = TRUE;
2480 ForeachNodeSafe(&receivers, rr, rrTemp)
2482 if (rr->nr == nr)
2484 Remove((struct Node *)rr);
2485 FreeVec(rr);
2486 break;
2490 if (fromTable)
2492 /* If we removed a request for a file that doesn't exist yet --
2493 if this was the only notification request for that file, remove
2494 also the hash entry. */
2495 if (IsListEmpty((struct List *)receivers))
2497 HashTable_remove(rambase, rambase->notifications, name);
2503 STRPTR getAbsoluteName(struct rambase *rambase, STRPTR name)
2505 int length = strlen(name) + 1 + 1;
2506 STRPTR fullName = AllocVec(length, MEMF_CLEAR | MEMF_PUBLIC);
2508 if (fullName == NULL)
2510 return NULL;
2513 strcpy(fullName, name);
2514 *strchr(fullName, ':') = '/';
2516 if (fullName[strlen(fullName) - 1] != '/')
2518 strcat(fullName, "/");
2521 return fullName;
2525 STRPTR getName(struct rambase *rambase, struct dnode *dn, STRPTR name)
2527 struct dnode *dnTemp = dn;
2529 ULONG length;
2530 STRPTR fullName;
2531 STRPTR fullNameTemp;
2532 STRPTR slash = "/";
2533 STRPTR nextSlash = slash;
2535 /* First, calculate the size of the complete filename */
2537 if (strchr(name, ':') != NULL)
2539 return getAbsoluteName(rambase, name);
2543 length = strlen(name) + 1 + 1 + 1; /* Add trailing 0 byte and possible '/' */
2544 length += strlen(dn->name) + 1;
2546 while (findname(rambase, &slash, &dnTemp) == 0)
2548 slash = nextSlash;
2549 length += 1 + strlen(dnTemp->name); /* Add '/' byte */
2552 /* The MEMF_CLEAR is necessary for the while loop below to work */
2553 fullName = AllocVec(length, MEMF_PUBLIC | MEMF_CLEAR);
2555 if (fullName == NULL)
2557 return NULL;
2560 fullNameTemp = fullName;
2562 dnTemp = dn;
2563 fullName += length - 1 - 1;
2566 int temp = strlen(name);
2568 if (temp > 0 && name[temp - 1] != '/')
2570 *fullName = '/';
2574 fullName -= strlen(name);
2575 strncpy(fullName, name, strlen(name));
2577 fullName -= strlen(dn->name) + 1;
2578 strcpy(fullName, dn->name);
2579 fullName[strlen(dn->name)] = '/';
2582 ULONG partLen;
2583 STRPTR slash = "/";
2584 STRPTR nextSlash = slash;
2586 while (findname(rambase, &slash, &dnTemp) != ERROR_OBJECT_NOT_FOUND)
2588 slash = nextSlash;
2589 partLen = strlen(dnTemp->name);
2591 fullName -= partLen + 1;
2592 strcpy(fullName, dnTemp->name);
2593 fullName[partLen] = '/'; /* Replace 0 with '/' */
2597 if (fullName != fullNameTemp)
2599 length = 0;
2600 while((fullNameTemp[length] = fullName[length])) length++;
2603 return fullNameTemp;
2607 HashNode *find(struct rambase *rambase, HashTable *ht,
2608 void *key, struct List *list);
2611 HashTable *HashTable_new(struct rambase *rambase, ULONG size,
2612 ULONG (*hash)(struct rambase *rambase,
2613 const void *key),
2614 int (*compare)(struct rambase *rambase,
2615 const void *key1,
2616 const void *key2),
2617 void (*delete)(struct rambase *rambase,
2618 void *key,
2619 struct List *list))
2621 ULONG i; /* Loop variable */
2622 HashTable *ht = AllocVec(sizeof(HashTable), MEMF_ANY);
2624 if (ht == NULL)
2626 return NULL;
2629 ht->size = size;
2630 ht->nElems = 0;
2631 ht->array = AllocVec(sizeof(struct List)*size, MEMF_ANY);
2633 if (ht->array == NULL)
2635 FreeVec(ht);
2637 return NULL;
2640 ht->hash = hash;
2641 ht->compare = compare;
2642 ht->delete = delete;
2644 for (i = 0; i < size; i++)
2646 NewList(&ht->array[i]);
2649 return ht;
2653 /* TODO: Fix the double list thing, remove the (void *) hack */
2654 void HashTable_delete(struct rambase *rambase, HashTable *ht)
2656 ULONG i;
2658 for (i = 0; i < ht->size; i++)
2660 while (!IsListEmpty(&ht->array[i]))
2662 HashNode *hn = (HashNode *)RemHead(&ht->array[i]);
2664 ht->delete(rambase, hn->key, (void *)&hn->requests);
2665 FreeVec(hn);
2669 FreeVec(ht);
2673 void HashTable_insert(struct rambase *rambase, HashTable *ht, void *key,
2674 struct Receiver *rr)
2676 ULONG pos;
2677 HashNode *hn;
2679 pos = ht->hash(rambase, key) % ht->size;
2681 hn = find(rambase, ht, key, &ht->array[pos]);
2683 if (hn == NULL)
2685 /* There was no previous request for this entity */
2686 hn = AllocVec(sizeof(HashNode), MEMF_ANY);
2688 if (hn == NULL)
2690 return;
2693 hn->key = Strdup(rambase, key);
2695 if (hn->key == NULL)
2697 FreeVec(hn);
2698 return;
2701 NewList(&hn->requests);
2702 AddHead(&ht->array[pos], &hn->node);
2705 AddHead(&hn->requests, &rr->node);
2707 ht->nElems++;
2711 void HashTable_remove(struct rambase *rambase, HashTable *ht, void *key)
2713 HashNode *hn;
2714 ULONG pos;
2715 struct Node *tempNode;
2716 struct List *list;
2718 pos = ht->hash(rambase, key) % ht->size;
2719 list = &ht->array[pos];
2721 ForeachNodeSafe(list, hn, tempNode)
2723 if (ht->compare(rambase, key, hn->key) == 0)
2725 Remove(&hn->node);
2726 ht->delete(rambase, hn->key, (void *)&hn->requests);
2727 FreeVec(hn);
2728 break;
2734 HashNode *find(
2735 struct rambase *rambase, HashTable *ht,
2736 void *key, struct List *list)
2738 HashNode *hn; /* Loop variable */
2740 ForeachNode(list, hn)
2742 if (ht->compare(rambase, key, hn->key) == 0)
2744 return hn;
2748 return NULL;
2752 struct List *HashTable_find(struct rambase *rambase, HashTable *ht, void *key)
2754 HashNode *hn;
2755 ULONG pos;
2757 pos = ht->hash(rambase, key) % ht->size;
2758 hn = find(rambase, ht, key, &ht->array[pos]);
2760 if (hn != NULL)
2762 return &hn->requests;
2764 else
2766 return NULL;
2769 return NULL; /* Make the compiler happy */
2773 inline ULONG HashTable_size(HashTable *ht)
2775 return ht->nElems;
2778 ADD2INITLIB(GM_UNIQUENAME(Init),0)
2779 ADD2OPENDEV(GM_UNIQUENAME(Open),0)
2780 ADD2CLOSEDEV(GM_UNIQUENAME(Close),0)
2781 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge),0)