make sure the right filename is being tracked for notification
[tangerine.git] / workbench / devs / ram_handler / ram_handler.c
blob77dd513eb44d9d13df1331f31f67b1de33aa3c4c
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 SysBase
195 #undef SysBase
196 #endif
197 #ifdef DOSBase
198 #undef DOSBase
199 #endif
200 #define SysBase rambase->sysbase
201 #define DOSBase rambase->dosbase
203 static int OpenDev(LIBBASETYPEPTR rambase, struct IOFileSys *iofs);
205 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR rambase)
207 /* This function is single-threaded by exec by calling Forbid. */
209 struct MsgPort *port;
210 struct Task *task;
211 struct SignalSemaphore *semaphore;
212 APTR stack;
214 rambase->dosbase = (struct DosLibrary *)OpenLibrary("dos.library",39);
216 if (rambase->dosbase != NULL)
218 rambase->utilitybase = (struct UtilityBase *)OpenLibrary("utility.library",39);
220 if (rambase->utilitybase!=NULL)
222 port = (struct MsgPort *)AllocMem(sizeof(struct MsgPort),
223 MEMF_PUBLIC | MEMF_CLEAR);
224 if (port != NULL)
226 rambase->port = port;
227 NewList(&port->mp_MsgList);
228 port->mp_Node.ln_Type = NT_MSGPORT;
229 port->mp_SigBit = SIGB_SINGLE;
231 task = (struct Task *)AllocMem(sizeof(struct Task),
232 MEMF_PUBLIC | MEMF_CLEAR);
234 if (task != NULL)
236 port->mp_SigTask = task;
237 port->mp_Flags = PA_IGNORE;
238 NewList(&task->tc_MemEntry);
239 task->tc_Node.ln_Type = NT_TASK;
240 task->tc_Node.ln_Name = "ram.handler task";
242 stack = AllocMem(AROS_STACKSIZE, MEMF_PUBLIC);
244 if (stack != NULL)
246 struct TagItem tasktags[] =
248 {TASKTAG_ARG1, (IPTR)rambase},
249 {TAG_DONE }
252 task->tc_SPLower = stack;
253 task->tc_SPUpper = (BYTE *)stack + AROS_STACKSIZE;
254 #if AROS_STACK_GROWS_DOWNWARDS
255 task->tc_SPReg = (BYTE *)task->tc_SPUpper - SP_OFFSET;
256 #else
257 task->tc_SPReg = (BYTE *)task->tc_SPLower + SP_OFFSET;
258 #endif
260 semaphore = (struct SignalSemaphore *)AllocMem(sizeof(struct SignalSemaphore),
261 MEMF_PUBLIC | MEMF_CLEAR);
263 if (semaphore != NULL)
265 rambase->sigsem = semaphore;
266 InitSemaphore(semaphore);
268 if (rambase->seglist==NULL) /* Are we a ROM module? */
270 struct DeviceNode *dn;
271 /* Install RAM: handler into device list
273 * KLUDGE: ram.handler should create only one device node, depending on
274 * the startup packet it gets. The mountlists for RAM: should be into dos.library bootstrap
275 * routines.
278 if((dn = AllocMem(sizeof (struct DeviceNode) + 4 + 3 + 2, MEMF_CLEAR|MEMF_PUBLIC)))
280 struct IOFileSys dummyiofs;
282 if (OpenDev(rambase, &dummyiofs))
284 BSTR s = MKBADDR(((IPTR)dn + sizeof(struct DeviceNode) + 4) & ~3);
286 rambase->device.dd_Library.lib_OpenCnt++;
288 AROS_BSTR_putchar(s, 0, 'R');
289 AROS_BSTR_putchar(s, 1, 'A');
290 AROS_BSTR_putchar(s, 2, 'M');
291 AROS_BSTR_putchar(s, 3, 0);
292 AROS_BSTR_setstrlen(s, 3);
294 dn->dn_Type = DLT_DEVICE;
295 dn->dn_Ext.dn_AROS.dn_Unit = dummyiofs.IOFS.io_Unit;
296 dn->dn_Ext.dn_AROS.dn_Device = dummyiofs.IOFS.io_Device;
297 dn->dn_Handler = NULL;
298 dn->dn_Startup = NULL;
299 dn->dn_Name = s;
300 dn->dn_Ext.dn_AROS.dn_DevName = AROS_BSTR_ADDR(dn->dn_Name);
302 if (AddDosEntry((struct DosList *)dn))
303 if (NewAddTask(task, deventry, NULL, tasktags) != NULL)
304 return TRUE;
307 FreeMem(dn, sizeof (struct DeviceNode));
310 else
311 if (NewAddTask(task, deventry, NULL, tasktags) != NULL)
312 return TRUE;
314 FreeMem(semaphore, sizeof(struct SignalSemaphore));
317 FreeMem(stack, AROS_STACKSIZE);
320 FreeMem(task, sizeof(struct Task));
323 FreeMem(port, sizeof(struct MsgPort));
326 CloseLibrary((struct Library *)rambase->utilitybase);
329 CloseLibrary((struct Library *)rambase->dosbase);
332 return FALSE;
335 #ifdef UtilityBase
336 #undef UtilityBase
337 #endif
338 #define UtilityBase rambase->utilitybase
341 /***************************************************************************/
343 void nullDelete(struct rambase *rambase, void *key, struct List *list)
345 // struct Receiver *rr;
346 // struct Node *tempNode;
348 // ForeachNodeSafe(list, rr, tempNode)
349 // {
350 // Remove(&rr->node);
351 // FreeVec(rr);
352 // }
354 FreeVec(key);
356 /* The list is part of the HashNode so we shouldn't free that */
360 ULONG stringHash(struct rambase *rambase, const void *key)
362 STRPTR str = (STRPTR)key;
363 ULONG val = 1;
365 while (*str != 0)
367 val *= ToLower(*str++);
368 val <<= 2;
371 return val;
374 static int
375 my_strcasecmp(struct rambase *rambase, const void *s1, const void *s2)
377 return strcasecmp(s1, s2);
380 /****************************************************************************/
383 static STRPTR Strdup(struct rambase *rambase, STRPTR string)
385 STRPTR s2 = string,s3;
387 while(*s2++)
390 s3 = (STRPTR)AllocVec(s2 - string, MEMF_ANY);
392 if (s3 != NULL)
394 CopyMem(string, s3, s2 - string);
397 return s3;
401 static void Strfree(struct rambase *rambase, STRPTR string)
403 FreeVec(string);
407 static int GM_UNIQUENAME(Open)
409 LIBBASETYPEPTR rambase,
410 struct IOFileSys *iofs,
411 ULONG unitnum,
412 ULONG flags
415 /* Mark Message as recently used. */
416 iofs->IOFS.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
418 return OpenDev(rambase, iofs);
422 static int OpenDev(LIBBASETYPEPTR rambase, struct IOFileSys *iofs)
424 struct filehandle *fhv, *fhc;
425 struct vnode *vol;
426 struct cnode *dev;
427 struct DosList *dlv;
429 iofs->IOFS.io_Error = ERROR_NO_FREE_STORE;
431 fhv = (struct filehandle*)AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
433 if (fhv != NULL)
435 fhc = (struct filehandle*)AllocMem(sizeof(struct filehandle),
436 MEMF_CLEAR);
438 if (fhc != NULL)
440 vol = (struct vnode *)AllocMem(sizeof(struct vnode), MEMF_CLEAR);
442 if (vol != NULL)
444 dev = (struct cnode *)AllocMem(sizeof(struct cnode),
445 MEMF_CLEAR);
447 if (dev != NULL)
449 vol->name = Strdup(rambase, "Ram Disk");
451 if (vol->name != NULL)
453 dlv = MakeDosEntry("Ram Disk", DLT_VOLUME);
455 if (dlv != NULL)
457 vol->type = ST_USERDIR;
458 vol->self = vol;
459 vol->doslist = dlv;
460 vol->protect = 0UL;
461 NewList((struct List *)&vol->list);
462 NewList((struct List *)&vol->receivers);
463 fhv->node = (struct dnode *)vol;
464 dlv->dol_Ext.dol_AROS.dol_Unit = (struct Unit *)fhv;
465 dlv->dol_Ext.dol_AROS.dol_Device = &rambase->device;
466 dev->type = ST_LINKDIR;
467 dev->self = dev;
468 dev->volume=vol;
469 fhc->node = (struct dnode *)dev;
470 iofs->IOFS.io_Unit = (struct Unit *)fhc;
471 iofs->IOFS.io_Device = &rambase->device;
472 AddDosEntry(dlv);
473 rambase->root = vol;
474 iofs->IOFS.io_Error = 0;
476 rambase->notifications =
477 HashTable_new(rambase, 100, stringHash,
478 my_strcasecmp, nullDelete);
480 return TRUE;
483 Strfree(rambase, vol->name);
486 FreeMem(dev, sizeof(struct cnode));
489 FreeMem(vol, sizeof(struct vnode));
492 FreeMem(fhc, sizeof(struct filehandle));
495 FreeMem(fhv, sizeof(struct filehandle));
498 iofs->IOFS.io_Error = IOERR_OPENFAIL;
500 return FALSE;
503 static int GM_UNIQUENAME(Expunge)(LIBBASETYPEPTR rambase)
506 This function is single-threaded by exec by calling Forbid.
507 Never break the Forbid() or strange things might happen.
510 /* Kill device task and free all resources */
511 RemTask(rambase->port->mp_SigTask);
512 FreeMem(rambase->sigsem, sizeof(struct SignalSemaphore));
513 FreeMem(((struct Task *)rambase->port->mp_SigTask)->tc_SPLower,
514 AROS_STACKSIZE);
515 FreeMem(rambase->port->mp_SigTask, sizeof(struct Task));
516 FreeMem(rambase->port, sizeof(struct MsgPort));
517 CloseLibrary((struct Library *)rambase->utilitybase);
518 CloseLibrary((struct Library *)rambase->dosbase);
520 return TRUE;
524 AROS_LH1(void, beginio,
525 AROS_LHA(struct IOFileSys *, iofs, A1),
526 struct rambase *, rambase, 5, Ram)
528 AROS_LIBFUNC_INIT
530 /* WaitIO will look into this */
531 iofs->IOFS.io_Message.mn_Node.ln_Type = NT_MESSAGE;
533 /* Nothing is done quick */
534 iofs->IOFS.io_Flags &= ~IOF_QUICK;
536 /* So let the device task do it */
537 PutMsg(rambase->port, &iofs->IOFS.io_Message);
539 AROS_LIBFUNC_EXIT
543 AROS_LH1(LONG, abortio,
544 AROS_LHA(struct IOFileSys *, iofs, A1),
545 struct rambase *, rambase, 6, Ram)
547 AROS_LIBFUNC_INIT
548 return 0;
549 AROS_LIBFUNC_EXIT
553 static LONG getblock(struct rambase *rambase, struct fnode *file, LONG block,
554 int mode, UBYTE **result)
556 ULONG a, i;
557 UBYTE **p, **p2;
559 if (block < 0x10)
561 p = &file->blocks[block];
562 block= 0 ;
563 i = 0;
565 else if (block < 0x410)
567 block -= 0x10;
568 p = (UBYTE **)&file->iblocks[block/0x100];
569 block &= 0xff;
570 i = 1;
572 else if(block < 0x10410)
574 block -= 0x410;
575 p = (UBYTE **)&file->i2block;
576 i = 2;
578 else
580 block -= 0x10410;
581 p = (UBYTE **)&file->i3block;
582 i = 3;
585 switch (mode)
587 case -1:
588 p2 = (UBYTE **)*p;
590 if (!block)
592 *p = NULL;
595 p = p2;
597 while (i-- && p != NULL)
599 a = (block >> i*8) & 0xff;
600 p2 = (UBYTE **)p[a];
602 if (!(block & ((1 << i*8) - 1)))
604 p[a] = NULL;
606 if (!a)
608 FreeMem(p, PBLOCKSIZE);
612 p = p2;
615 if (p != NULL)
617 FreeMem(p, BLOCKSIZE);
620 break;
622 case 0:
623 p = (UBYTE **)*p;
625 while (i-- && p != NULL)
627 p = ((UBYTE ***)p)[(block >> i*8) & 0xff];
630 *result = (UBYTE *)p;
631 break;
633 case 1:
634 while (i--)
636 if (*p == NULL)
638 *p= AllocMem(PBLOCKSIZE, MEMF_CLEAR);
640 if (*p == NULL)
642 return ERROR_NO_FREE_STORE;
646 p = (UBYTE **)*p + ((block >> i*8) & 0xff);
649 if (*p == NULL)
651 *p = AllocMem(BLOCKSIZE, MEMF_CLEAR);
653 if (*p == NULL)
655 return ERROR_NO_FREE_STORE;
659 *result = *p;
660 break;
661 } /* switch (mode) */
663 return 0;
667 static void zerofill(UBYTE *address, ULONG size)
669 while (size--)
671 *address++ = 0;
676 static void shrinkfile(struct rambase *rambase, struct fnode *file, LONG size)
678 ULONG blocks, block;
679 UBYTE *p;
681 blocks = (size + BLOCKSIZE - 1)/BLOCKSIZE;
682 block = (file->size + BLOCKSIZE - 1)/BLOCKSIZE;
684 for(;block-- > blocks;)
686 (void)getblock(rambase, file, block, -1, &p);
689 if (size & 0xff)
691 (void)getblock(rambase, file, size, 0, &p);
693 if (p != NULL)
695 zerofill(p + (size & 0xff), -size & 0xff);
699 file->size = size;
703 static void delete(struct rambase *rambase, struct fnode *file)
705 struct hnode *link, *new, *more;
706 struct Node *node;
708 Strfree(rambase, file->name);
709 Strfree(rambase, file->comment);
710 Remove((struct Node *)file);
712 if (file->type == ST_LINKDIR)
714 /* It is a link. Remove it from the chain. */
716 link = ((struct hnode *)file)->orig;
717 ((struct hnode *)file)->orig = NULL;
718 file->type = link->type;
720 while((struct fnode *)link->link != file)
722 link = link->link;
725 link->link = file->link;
727 else if (file->link != NULL)
729 /* If there is a hard link to the object make the link the original */
731 link = file->link;
732 link->type = file->type;
733 more = new->link;
735 while (more != NULL)
737 more->orig = new;
738 more = more->link;
741 switch (file->type)
743 case ST_USERDIR:
744 while((node = RemHead((struct List *)&((struct dnode *)file)->list)) != NULL)
745 AddTail((struct List *)&((struct dnode *)file)->list, node);
746 break;
748 case ST_FILE:
749 CopyMemQuick(&file->size, &((struct fnode *)new)->size,
750 sizeof(struct fnode) - offsetof(struct fnode, size));
751 zerofill((UBYTE *)&file->size,
752 sizeof(struct fnode) - offsetof(struct fnode, size));
753 break;
755 case ST_SOFTLINK:
756 ((struct snode *)new)->contents = ((struct snode *)file)->contents;
757 ((struct snode *)file)->contents = NULL;
758 break;
760 } /* else if (file->link != NULL) */
762 switch (file->type)
764 case ST_USERDIR:
765 Notify_directoryChange(rambase, NOTIFY_Delete, (struct dnode *)file);
767 FreeMem(file, sizeof(struct dnode));
769 return;
771 case ST_FILE:
772 Notify_fileChange(rambase, NOTIFY_Delete, file);
774 shrinkfile(rambase, file, 0);
775 FreeMem(file, sizeof(struct fnode));
777 return;
779 case ST_SOFTLINK:
780 Strfree(rambase, ((struct snode *)file)->contents);
781 FreeMem(file, sizeof(struct snode));
783 return;
788 static int fstrcmp(struct rambase *rambase, char *s1, char *s2)
790 for (;;)
792 if (ToLower(*s1) != ToLower(*s2))
794 return *s1 || *s2 != '/';
797 if (!*s1)
799 return 0;
802 s1++;
803 s2++;
808 /* Find a node for a given name */
809 static LONG findname(struct rambase *rambase, STRPTR *name,
810 struct dnode **dnode)
812 struct dnode *cur = *dnode;
813 char *rest = *name;
815 for (;;)
817 if (cur->type == ST_LINKDIR)
819 cur = (struct dnode *)((struct hnode *)cur)->orig;
822 if (!*rest)
824 break;
827 if (*rest == '/')
829 if ((struct dnode *)cur->volume == cur)
831 return ERROR_OBJECT_NOT_FOUND;
834 while (cur->node.mln_Pred != NULL)
836 cur = (struct dnode *)cur->node.mln_Pred;
839 cur = (struct dnode *)((BYTE *)cur - offsetof(struct dnode, list));
841 else
843 if (cur->type == ST_SOFTLINK)
845 *dnode = cur;
846 *name = rest;
848 return ERROR_IS_SOFT_LINK;
851 if (cur->type != ST_USERDIR)
853 return ERROR_DIR_NOT_FOUND;
856 *dnode = cur;
857 cur = (struct dnode *)cur->list.mlh_Head;
859 for (;;)
861 if (cur->node.mln_Succ == NULL)
863 *name = rest;
865 return ERROR_OBJECT_NOT_FOUND;
868 if (!fstrcmp(rambase, cur->name, rest))
870 break;
873 cur = (struct dnode *)cur->node.mln_Succ;
877 while (*rest)
879 if (*rest++ == '/')
881 break;
886 *dnode = cur;
888 return 0;
892 static LONG set_file_size(struct rambase *rambase, struct filehandle *handle,
893 QUAD *offp, LONG mode)
895 struct fnode *file = (struct fnode *)handle->node;
896 QUAD size = *offp;
898 if (file->type != ST_FILE)
900 return ERROR_OBJECT_WRONG_TYPE;
903 switch(mode)
905 case OFFSET_BEGINNING:
906 break;
908 case OFFSET_CURRENT:
909 size += handle->position;
910 break;
912 case OFFSET_END:
913 size += file->size;
914 break;
916 default:
917 return ERROR_NOT_IMPLEMENTED;
920 if (size < 0)
922 return ERROR_SEEK_ERROR;
925 if (size < file->size)
927 shrinkfile(rambase, file, size);
930 file->size = *offp = size;
932 return 0;
936 static LONG read(struct rambase *rambase, struct filehandle *handle,
937 APTR buffer, LONG *numbytes)
939 struct fnode *file = (struct fnode *)handle->node;
940 ULONG num = *numbytes;
941 ULONG size = file->size;
942 ULONG block, offset;
943 UBYTE *buf = buffer, *p;
945 if (handle->position >= size)
947 num = 0;
949 else if (handle->position + num > size)
951 num = size - handle->position;
954 block = handle->position/BLOCKSIZE;
955 offset = handle->position & (BLOCKSIZE - 1);
956 size = BLOCKSIZE - offset;
958 while (num)
960 if (size > num)
962 size = num;
965 (void)getblock(rambase, file, block, 0, &p);
967 if (p != NULL)
969 CopyMem(p + offset, buffer, size);
971 else
973 zerofill(buffer, size);
976 buffer += size;
977 num -= size;
978 block++;
979 offset = 0;
980 size = BLOCKSIZE;
983 *numbytes = (UBYTE *)buffer - buf;
984 handle->position += *numbytes;
986 return 0;
990 static LONG write(struct rambase *rambase, struct filehandle *handle,
991 UBYTE *buffer, LONG *numbytes)
993 struct fnode *file = (struct fnode *)handle->node;
994 ULONG num = *numbytes;
995 ULONG size = file->size;
996 ULONG block, offset;
997 UBYTE *buf = buffer, *p;
998 LONG error = 0;
1000 if ((LONG)(handle->position + num) < 0)
1002 return ERROR_OBJECT_TOO_LARGE;
1005 Notify_fileChange(rambase, NOTIFY_Write, file);
1007 block = handle->position/BLOCKSIZE;
1008 offset = handle->position & (BLOCKSIZE - 1);
1009 size = BLOCKSIZE - offset;
1011 while (num)
1013 if (size > num)
1015 size = num;
1018 error = getblock(rambase, file, block, 1, &p);
1020 if (error)
1022 break;
1025 CopyMem(buffer, p + offset, size);
1026 buffer += size;
1027 num -= size;
1028 block++;
1029 offset = 0;
1030 size = BLOCKSIZE;
1033 *numbytes = (UBYTE *)buffer - buf;
1034 handle->position += *numbytes;
1036 if (handle->position > file->size)
1038 file->size = handle->position;
1041 return error;
1045 static LONG lock(struct dnode *dir, ULONG mode)
1047 if ((mode & FMF_EXECUTE) && (dir->protect & FMF_EXECUTE))
1049 return ERROR_NOT_EXECUTABLE;
1052 if ((mode & FMF_WRITE) && (dir->protect & FMF_WRITE))
1054 return ERROR_WRITE_PROTECTED;
1057 if ((mode & FMF_READ) && (dir->protect & FMF_READ))
1059 return ERROR_READ_PROTECTED;
1062 if (mode & FMF_LOCK)
1064 if (dir->usecount)
1066 return ERROR_OBJECT_IN_USE;
1069 dir->usecount = ~0ul/2 + 1;
1071 else
1073 if (dir->usecount < 0)
1075 return ERROR_OBJECT_IN_USE;
1079 dir->usecount++;
1080 dir->volume->volcount++;
1082 return 0;
1086 static LONG open_(struct rambase *rambase, struct filehandle **handle,
1087 STRPTR name, ULONG mode)
1089 struct dnode *dir = (*handle)->node;
1090 struct filehandle *fh;
1091 LONG error;
1093 fh = (struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1095 if (fh != NULL)
1097 error = findname(rambase, &name, &dir);
1099 if (!error)
1101 error = lock(dir, mode);
1103 if (!error)
1105 fh->node = dir;
1106 *handle = fh;
1108 if (dir->type == ST_FILE)
1110 Notify_fileChange(rambase, NOTIFY_Open,
1111 (struct fnode *)dir);
1113 else if (dir->type == ST_USERDIR)
1115 D(kprintf("Notifying OPEN at dir %s\n", dir->name));
1116 Notify_directoryChange(rambase, NOTIFY_Open, dir);
1119 return 0;
1123 FreeMem(fh, sizeof(struct filehandle));
1125 else
1127 error = ERROR_NO_FREE_STORE;
1130 return error;
1134 static LONG open_file(struct rambase *rambase, struct filehandle **handle,
1135 STRPTR name, ULONG mode, ULONG protect)
1137 struct dnode *dir = (*handle)->node;
1138 struct filehandle *fh;
1139 LONG error = 0;
1141 fh = AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1143 if (fh != NULL)
1145 error = findname(rambase, &name, &dir);
1147 if ((mode & FMF_CREATE) && error == ERROR_OBJECT_NOT_FOUND)
1149 char *s = name;
1150 struct fnode *file;
1152 while (*s)
1154 if (*s++ == '/')
1156 return error;
1160 file = (struct fnode *)AllocMem(sizeof(struct fnode), MEMF_CLEAR);
1162 if (file != NULL)
1164 file->name = Strdup(rambase, name);
1166 if (file->name != NULL)
1168 file->type = ST_FILE;
1169 file->protect = protect;
1170 file->volume = dir->volume;
1171 NewList((struct List *)&file->receivers);
1172 AddTail((struct List *)&dir->list, (struct Node *)file);
1173 error = lock((struct dnode *)file, mode);
1175 if (!error)
1177 fh->node = (struct dnode *)file;
1178 *handle = fh;
1180 Notify_fileChange(rambase, NOTIFY_Add, file);
1182 return 0;
1185 Strfree(rambase, file->name);
1188 FreeMem(file,sizeof(struct fnode));
1191 error = ERROR_NO_FREE_STORE;
1193 else if (!error)
1195 if (dir->type != ST_FILE)
1197 error = ERROR_OBJECT_WRONG_TYPE;
1199 else
1201 error = lock(dir, mode);
1203 if (!error)
1205 /* stegerg */
1206 if (mode & FMF_CLEAR)
1208 shrinkfile(rambase, (struct fnode *)dir, 0);
1209 dir->protect = protect;
1211 /* end stegerg */
1213 fh->node = dir;
1214 *handle = fh;
1216 return 0;
1219 } /* else if (!error) */
1221 FreeMem(fh, sizeof(struct filehandle));
1224 return error;
1228 static LONG create_dir(struct rambase *rambase, struct filehandle **handle,
1229 STRPTR name, ULONG protect)
1231 struct dnode *dir = (*handle)->node, *new;
1232 struct filehandle *fh;
1233 LONG error;
1235 if (dir->protect & FIBF_WRITE)
1237 return ERROR_WRITE_PROTECTED;
1240 error = findname(rambase, &name, &dir);
1242 if (!error)
1244 return ERROR_OBJECT_EXISTS;
1247 if (error != ERROR_OBJECT_NOT_FOUND)
1249 return error;
1252 if (strchr(name, '/') != NULL)
1254 return error;
1257 fh = AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1259 if (fh != NULL)
1261 new = (struct dnode *)AllocMem(sizeof(struct dnode), MEMF_CLEAR);
1263 if (new != NULL)
1265 new->name = Strdup(rambase, name);
1267 if (new->name != NULL)
1269 new->type = ST_USERDIR;
1270 new->protect = protect;
1271 new->volume = dir->volume;
1272 new->volume->volcount++;
1273 new->usecount = ~0ul/2 + 2;
1274 NewList((struct List *)&new->list);
1275 NewList((struct List *)&new->receivers);
1276 AddTail((struct List *)&dir->list, (struct Node *)new);
1277 fh->node = new;
1278 *handle = fh;
1280 // kprintf("New (%p): Name = %s\n", new, new->name);
1281 Notify_directoryChange(rambase, NOTIFY_Add, new);
1283 return 0;
1286 FreeMem(new, sizeof(struct dnode));
1289 FreeMem(fh, sizeof(struct filehandle));
1292 return ERROR_NO_FREE_STORE;
1296 static LONG free_lock(struct rambase *rambase, struct filehandle *filehandle)
1298 struct dnode *dnode = filehandle->node;
1300 dnode->usecount = (dnode->usecount - 1) & ~0ul/2;
1301 FreeMem(filehandle, sizeof(struct filehandle));
1302 dnode->volume->volcount--;
1304 return 0;
1308 static LONG seek(struct rambase *rambase, struct filehandle *filehandle,
1309 QUAD *posp, LONG mode)
1311 struct fnode *file = (struct fnode *)filehandle->node;
1312 QUAD pos = *posp;
1314 if (file->type != ST_FILE)
1316 return ERROR_OBJECT_WRONG_TYPE;
1319 switch (mode)
1321 case OFFSET_BEGINNING:
1322 break;
1324 case OFFSET_CURRENT:
1325 pos += filehandle->position;
1326 break;
1328 case OFFSET_END:
1329 pos += file->size;
1330 break;
1332 default:
1333 return ERROR_NOT_IMPLEMENTED;
1336 if (pos < 0)
1338 return ERROR_SEEK_ERROR;
1341 *posp = filehandle->position;
1342 filehandle->position = pos;
1344 return 0;
1348 static const ULONG sizes[]=
1351 offsetof(struct ExAllData,ed_Type),
1352 offsetof(struct ExAllData,ed_Size),
1353 offsetof(struct ExAllData,ed_Prot),
1354 offsetof(struct ExAllData,ed_Days),
1355 offsetof(struct ExAllData,ed_Comment),
1356 offsetof(struct ExAllData,ed_OwnerUID),
1357 sizeof(struct ExAllData)
1361 static LONG examine(struct fnode *file,
1362 struct ExAllData *ead,
1363 ULONG size,
1364 ULONG type,
1365 LONG *dirpos)
1367 STRPTR next, end, name;
1369 if (type > ED_OWNER)
1371 return ERROR_BAD_NUMBER;
1374 next = (STRPTR)ead + sizes[type];
1375 end = (STRPTR)ead + size;
1377 if(next>end) /* > is correct. Not >= */
1378 return ERROR_BUFFER_OVERFLOW;
1380 /* Use *dirpos to store information for ExNext()
1381 * *dirpos is copied to fib->fib_DiskKey in Examine()
1383 if (file->type == ST_USERDIR)
1385 *dirpos = (LONG)(((struct dnode*)file)->list.mlh_Head);
1387 else
1389 /* ExNext() should not be called in this case anyway */
1390 *dirpos = (LONG)file;
1393 switch(type)
1395 case ED_OWNER:
1396 ead->ed_OwnerUID = 0;
1397 ead->ed_OwnerGID = 0;
1399 /* Fall through */
1400 case ED_COMMENT:
1401 if (file->comment != NULL)
1403 ead->ed_Comment = next;
1404 name = file->comment;
1406 for (;;)
1408 if (next >= end)
1410 return ERROR_BUFFER_OVERFLOW;
1413 if (!(*next++ = *name++))
1415 break;
1419 else
1421 ead->ed_Comment = NULL;
1424 /* Fall through */
1425 case ED_DATE:
1426 ead->ed_Days = 0;
1427 ead->ed_Mins = 0;
1428 ead->ed_Ticks = 0;
1430 /* Fall through */
1431 case ED_PROTECTION:
1432 ead->ed_Prot = file->protect;
1434 /* Fall through */
1435 case ED_SIZE:
1436 ead->ed_Size = file->size;
1438 /* Fall through */
1439 case ED_TYPE:
1440 ead->ed_Type = file->type;
1442 if (((struct vnode *)file)->self == (struct vnode *)file)
1444 ead->ed_Type=ST_ROOT;
1447 /* Fall through */
1448 case ED_NAME:
1449 ead->ed_Name = next;
1450 name = file->name;
1452 for (;;)
1454 if (next >= end)
1456 return ERROR_BUFFER_OVERFLOW;
1459 if (!(*next++ = *name++))
1461 break;
1465 /* Fall through */
1466 case 0:
1467 ead->ed_Next = (struct ExAllData *)(((IPTR)next + AROS_PTRALIGN - 1) & ~(AROS_PTRALIGN - 1));
1470 return 0;
1474 static LONG examine_next(struct rambase *rambase,
1475 struct filehandle *dir,
1476 struct FileInfoBlock *FIB)
1478 struct fnode *file = (struct fnode *)FIB->fib_DiskKey;
1480 ASSERT_VALID_PTR_OR_NULL(file);
1482 if (file->node.mln_Succ == NULL)
1484 return ERROR_NO_MORE_ENTRIES;
1487 FIB->fib_OwnerUID = 0;
1488 FIB->fib_OwnerGID = 0;
1490 FIB->fib_Date.ds_Days = 0;
1491 FIB->fib_Date.ds_Minute = 0;
1492 FIB->fib_Date.ds_Tick = 0;
1493 FIB->fib_Protection = file->protect;
1494 FIB->fib_Size = file->size;
1495 FIB->fib_DirEntryType = file->type;
1497 strncpy(FIB->fib_FileName, file->name, MAXFILENAMELENGTH - 1);
1498 strncpy(FIB->fib_Comment, file->comment != NULL ? file->comment : "",
1499 MAXCOMMENTLENGTH - 1);
1501 FIB->fib_DiskKey = (LONG)file->node.mln_Succ;
1503 return 0;
1507 static LONG examine_all(struct filehandle *dir,
1508 struct ExAllData *ead,
1509 struct ExAllControl *eac,
1510 ULONG size,
1511 ULONG type)
1513 STRPTR end;
1514 struct ExAllData *last=NULL;
1515 struct fnode *ent;
1516 LONG error;
1517 LONG dummy; /* not anything is done with this value but passed to examine */
1518 end = (STRPTR)ead + size;
1520 eac->eac_Entries = 0;
1521 if (dir->node->type != ST_USERDIR)
1523 return ERROR_OBJECT_WRONG_TYPE;
1526 ent = (struct fnode *)eac->eac_LastKey;
1528 if (ent == NULL)
1530 ent = (struct fnode *)dir->node->list.mlh_Head;
1531 if (ent->node.mln_Succ) ent->usecount++;
1534 if (ent->node.mln_Succ == NULL)
1536 return ERROR_NO_MORE_ENTRIES;
1539 ent->usecount--;
1543 error = examine(ent, ead, end - (STRPTR)ead, type, &dummy);
1545 if (error == ERROR_BUFFER_OVERFLOW)
1547 if (last == NULL)
1549 return error;
1552 ent->usecount++;
1553 last->ed_Next = NULL;
1554 eac->eac_LastKey = (IPTR)ent;
1556 return 0;
1558 eac->eac_Entries++;
1559 last = ead;
1560 ead = ead->ed_Next;
1561 ent = (struct fnode *)ent->node.mln_Succ;
1563 } while (ent->node.mln_Succ != NULL);
1565 last->ed_Next = NULL;
1566 eac->eac_LastKey = (IPTR)ent;
1568 return ERROR_NO_MORE_ENTRIES;
1572 static LONG delete_object(struct rambase *rambase,
1573 struct filehandle *filehandle, STRPTR name)
1575 struct dnode *file = filehandle->node;
1576 LONG error;
1578 error = findname(rambase, &name, &file);
1580 if (error)
1582 return error;
1585 if ((struct dnode *)file->volume == file)
1587 return ERROR_OBJECT_WRONG_TYPE;
1590 if (file->usecount != 0)
1592 return ERROR_OBJECT_IN_USE;
1595 if (file->protect & FIBF_DELETE)
1597 return ERROR_DELETE_PROTECTED;
1600 if (file->type == ST_USERDIR && file->list.mlh_Head->mln_Succ != NULL)
1602 return ERROR_DIRECTORY_NOT_EMPTY;
1605 delete(rambase, (struct fnode *)file);
1607 return 0;
1611 static int GM_UNIQUENAME(Close)
1613 LIBBASETYPEPTR rambase,
1614 struct IOFileSys *iofs
1617 struct cnode *dev;
1618 struct vnode *vol;
1619 struct dnode *dir;
1620 struct fnode *file;
1622 struct filehandle *handle;
1624 handle = (struct filehandle *)iofs->IOFS.io_Unit;
1625 dev = (struct cnode *)handle->node;
1626 vol = dev->volume;
1628 if (dev->type != ST_LINKDIR || dev->self != dev)
1630 iofs->io_DosError = ERROR_OBJECT_WRONG_TYPE;
1632 return 0;
1635 if (vol->volcount)
1637 iofs->io_DosError = ERROR_OBJECT_IN_USE;
1639 return 0;
1642 free_lock(rambase, handle);
1643 RemDosEntry(vol->doslist);
1644 FreeDosEntry(vol->doslist);
1646 while (vol->list.mlh_Head->mln_Succ != NULL)
1648 dir = (struct dnode *)vol->list.mlh_Head;
1650 if (dir->type == ST_USERDIR)
1652 while((file = (struct fnode *)RemHead((struct List *)&dir->list)) != NULL)
1654 AddTail((struct List *)&vol->list, (struct Node *)dir);
1658 delete(rambase, (struct fnode *)dir);
1661 Strfree(rambase, vol->name);
1662 FreeMem(vol, sizeof(struct vnode));
1664 Strfree(rambase, dev->name);
1665 FreeMem(dev, sizeof(struct cnode));
1667 iofs->io_DosError = 0;
1669 return TRUE;
1673 void processFSM(struct rambase *rambase);
1676 void deventry(struct rambase *rambase)
1678 ULONG notifyMask;
1679 ULONG fileOpMask;
1680 struct Message *msg;
1683 Init device port. AllocSignal() cannot fail because this is a
1684 freshly created task with all signal bits still free.
1687 rambase->port->mp_SigBit = AllocSignal(-1);
1688 rambase->port->mp_Flags = PA_SIGNAL;
1690 /* Check if there are pending messages that we missed */
1691 if ((msg = GetMsg(rambase->port))) PutMsg(rambase->port, msg);
1693 Notify_initialize(rambase);
1695 notifyMask = 1 << rambase->notifyPort->mp_SigBit;
1697 fileOpMask = 1 << rambase->port->mp_SigBit;
1699 while (TRUE)
1701 ULONG flags;
1703 flags = Wait(fileOpMask | notifyMask);
1705 if (flags & notifyMask)
1707 struct NotifyMessage *nMessage;
1709 D(kprintf("Got replied notify message\n"));
1711 while ((nMessage = (struct NotifyMessage *)GetMsg(rambase->notifyPort)) != NULL)
1713 nMessage->nm_NReq->nr_Flags &= ~NRF_NOT_REPLIED;
1714 FreeVec(nMessage);
1718 if (flags & fileOpMask)
1720 processFSM(rambase);
1726 void processFSM(struct rambase *rambase)
1728 struct IOFileSys *iofs;
1729 struct dnode *dir;
1731 LONG error = 0;
1734 /* Get and process the messages. */
1735 while ((iofs = (struct IOFileSys *)GetMsg(rambase->port)) != NULL)
1737 // kprintf("Ram.handler initialized %u\n", iofs->IOFS.io_Command);
1739 switch (iofs->IOFS.io_Command)
1741 case FSA_OPEN:
1743 get handle on a file or directory
1744 Unit *current; current directory / new handle on return
1745 STRPTR name; file- or directoryname
1746 LONG mode; open mode
1749 error = open_(rambase,
1750 (struct filehandle **)&iofs->IOFS.io_Unit,
1751 iofs->io_Union.io_OPEN.io_Filename,
1752 iofs->io_Union.io_OPEN.io_FileMode);
1753 break;
1755 case FSA_OPEN_FILE:
1757 open a file or create a new one
1758 Unit *current; current directory / new handle on return
1759 STRPTR name; file- or directoryname
1760 LONG mode; open mode
1761 LONG protect; protection flags if a new file is created
1764 error = open_file(rambase,
1765 (struct filehandle **)&iofs->IOFS.io_Unit,
1766 iofs->io_Union.io_OPEN_FILE.io_Filename,
1767 iofs->io_Union.io_OPEN_FILE.io_FileMode,
1768 iofs->io_Union.io_OPEN_FILE.io_Protection);
1769 break;
1771 case FSA_READ:
1773 read a number of bytes from a file
1774 Unit *current; filehandle
1775 APTR buffer; data
1776 LONG numbytes; number of bytes to read /
1777 number of bytes read on return,
1778 0 if there are no more bytes in the file
1780 error = read(rambase,
1781 (struct filehandle *)iofs->IOFS.io_Unit,
1782 iofs->io_Union.io_READ.io_Buffer,
1783 &iofs->io_Union.io_READ.io_Length);
1784 break;
1786 case FSA_WRITE:
1788 write a number of bytes to a file
1789 Unit *current; filehandle
1790 APTR buffer; data
1791 LONG numbytes; number of bytes to write /
1792 number of bytes written on return
1794 error = write(rambase,
1795 (struct filehandle *)iofs->IOFS.io_Unit,
1796 iofs->io_Union.io_WRITE.io_Buffer,
1797 &iofs->io_Union.io_WRITE.io_Length);
1798 break;
1800 case FSA_SEEK:
1802 set / read position in file
1803 Unit *current; filehandle
1804 LONG posh;
1805 LONG posl; relative position /
1806 old position on return
1807 LONG mode; one of OFFSET_BEGINNING, OFFSET_CURRENT,
1808 OFFSET_END
1810 error = seek(rambase,
1811 (struct filehandle *)iofs->IOFS.io_Unit,
1812 &iofs->io_Union.io_SEEK.io_Offset,
1813 iofs->io_Union.io_SEEK.io_SeekMode);
1814 break;
1816 case FSA_CLOSE:
1818 /* Get rid of a handle
1819 Unit *current; filehandle */
1821 struct filehandle *handle =
1822 (struct filehandle *)iofs->IOFS.io_Unit;
1824 Notify_fileChange(rambase, NOTIFY_Close,
1825 (struct fnode *)handle->node);
1826 error = free_lock(rambase, handle);
1827 break;
1830 case FSA_EXAMINE:
1832 Get information about the current object
1833 Unit *current; current object
1834 struct ExAllData *ead; buffer to be filled
1835 ULONG size; size of the buffer
1836 ULONG type; type of information to get
1837 iofs->io_DirPos; leave current position so
1838 ExNext() knows where to find
1839 next object
1841 error = examine((struct fnode *)((struct filehandle *)iofs->IOFS.io_Unit)->node,
1842 iofs->io_Union.io_EXAMINE.io_ead,
1843 iofs->io_Union.io_EXAMINE.io_Size,
1844 iofs->io_Union.io_EXAMINE.io_Mode,
1845 &(iofs->io_DirPos));
1846 break;
1848 case FSA_EXAMINE_NEXT:
1850 Get information about the next object
1851 Unit *current; current object
1852 struct FileInfoBlock *fib;
1854 error = examine_next(rambase,
1855 (struct filehandle *)iofs->IOFS.io_Unit,
1856 iofs->io_Union.io_EXAMINE_NEXT.io_fib);
1857 break;
1859 case FSA_EXAMINE_ALL:
1861 Read the current directory
1862 Unit *current; current directory
1863 struct ExAllData *ead; buffer to be filled
1864 ULONG size; size of the buffer
1865 ULONG type; type of information to get
1867 error = examine_all((struct filehandle *)iofs->IOFS.io_Unit,
1868 iofs->io_Union.io_EXAMINE_ALL.io_ead,
1869 iofs->io_Union.io_EXAMINE_ALL.io_eac,
1870 iofs->io_Union.io_EXAMINE_ALL.io_Size,
1871 iofs->io_Union.io_EXAMINE_ALL.io_Mode);
1872 break;
1874 case FSA_CREATE_DIR:
1876 Build lock and open a new directory
1877 Unit *current; current directory
1878 STRPTR name; name of the dir to create
1879 LONG protect; Protection flags for the new dir
1882 // kprintf("Creating directory %s\n",
1883 // iofs->io_Union.io_CREATE_DIR.io_Filename);
1886 error = create_dir(rambase,
1887 (struct filehandle **)&iofs->IOFS.io_Unit,
1888 iofs->io_Union.io_CREATE_DIR.io_Filename,
1889 iofs->io_Union.io_CREATE_DIR.io_Protection);
1890 break;
1892 case FSA_DELETE_OBJECT:
1894 Delete file or directory
1895 Unit *current; current directory
1896 STRPTR name; filename
1898 error = delete_object(rambase,
1899 (struct filehandle *)iofs->IOFS.io_Unit,
1900 iofs->io_Union.io_DELETE_OBJECT.io_Filename);
1901 break;
1903 case FSA_SET_PROTECT:
1906 Set protection bits for a certain file or directory.
1907 Unit *current; current directory
1908 STRPTR name; filename
1909 ULONG protect; new protection bits
1912 STRPTR realName = iofs->io_Union.io_SET_PROTECT.io_Filename;
1914 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
1915 error = findname(rambase, &realName, &dir);
1917 if (!error)
1919 dir->protect = iofs->io_Union.io_SET_PROTECT.io_Protection;
1922 break;
1925 case FSA_SET_OWNER:
1928 Set owner and group of the file or directory
1929 Unit *current; current directory
1930 STRPTR name; filename
1931 ULONG UID;
1932 ULONG GID;
1935 STRPTR realName = iofs->io_Union.io_SET_OWNER.io_Filename;
1937 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
1938 error = findname(rambase, &realName, &dir);
1940 if(!error)
1944 break;
1947 case FSA_SET_DATE:
1950 Set creation date of the file
1951 Unit *current; current directory
1952 STRPTR name; filename
1953 ULONG days;
1954 ULONG mins;
1955 ULONG ticks; timestamp
1958 STRPTR realName = iofs->io_Union.io_SET_DATE.io_Filename;
1960 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
1961 error = findname(rambase, &realName, &dir);
1963 if(!error)
1967 break;
1970 case FSA_SET_COMMENT:
1973 Set a comment for the file or directory;
1974 Unit *current; current directory
1975 STRPTR name; filename
1976 STRPTR comment; NUL terminated C string or NULL.
1979 STRPTR realName = iofs->io_Union.io_SET_COMMENT.io_Filename;
1981 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
1982 error = findname(rambase, &realName, &dir);
1984 if (!error)
1986 if (iofs->io_Union.io_SET_COMMENT.io_Comment)
1988 STRPTR s = Strdup(rambase,
1989 iofs->io_Union.io_SET_COMMENT.io_Comment);
1990 if (s != NULL)
1992 Strfree(rambase, dir->comment);
1993 dir->comment = s;
1995 else
1997 error = ERROR_NO_FREE_STORE;
2000 else
2002 Strfree(rambase, dir->comment);
2003 dir->comment = NULL;
2007 break;
2010 case FSA_SET_FILE_SIZE:
2012 Set a new size for the file.
2013 Unit *file; filehandle
2014 LONG offh;
2015 LONG offl; offset to current position/
2016 new size on return
2017 LONG mode; relative to what (see Seek)
2019 error = set_file_size(rambase,
2020 (struct filehandle *)iofs->IOFS.io_Unit,
2021 &iofs->io_Union.io_SET_FILE_SIZE.io_Offset,
2022 iofs->io_Union.io_SET_FILE_SIZE.io_SeekMode);
2023 break;
2025 case FSA_IS_FILESYSTEM:
2026 iofs->io_Union.io_IS_FILESYSTEM.io_IsFilesystem = TRUE;
2027 error = 0;
2028 break;
2030 case FSA_DISK_INFO:
2032 struct InfoData *id = iofs->io_Union.io_INFO.io_Info;
2034 id->id_NumSoftErrors = 0;
2035 id->id_UnitNumber = 0;
2036 id->id_DiskState = ID_VALIDATED;
2037 id->id_NumBlocks = AvailMem(MEMF_TOTAL | MEMF_PUBLIC)/BLOCKSIZE;
2038 id->id_NumBlocksUsed = id->id_NumBlocks - AvailMem(MEMF_PUBLIC)/BLOCKSIZE;
2039 id->id_BytesPerBlock = BLOCKSIZE;
2040 id->id_DiskType = ID_DOS_DISK;
2041 id->id_VolumeNode = NULL; /* What is this? */
2042 id->id_InUse = (LONG)TRUE;
2044 error = 0;
2047 break;
2050 case FSA_ADD_NOTIFY:
2052 BOOL ok;
2053 struct NotifyRequest *nr =
2054 iofs->io_Union.io_NOTIFY.io_NotificationRequest;
2055 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
2057 D(kprintf("Adding notification for entity (nr = %s)\n",
2058 nr->nr_FullName));
2060 ok = Notify_addNotification(rambase, fh->node, nr);
2062 if (!ok)
2064 error = ERROR_NO_FREE_STORE;
2067 D(kprintf("Notification now added!\n"));
2069 break;
2071 case FSA_REMOVE_NOTIFY:
2073 struct NotifyRequest *nr =
2074 iofs->io_Union.io_NOTIFY.io_NotificationRequest;
2076 Notify_removeNotification(rambase, nr);
2078 break;
2080 default:
2081 error = ERROR_NOT_IMPLEMENTED;
2083 D(kprintf("ram_handler, unimplemented FSA: %ld\n", iofs->IOFS.io_Command));
2084 break;
2086 FSA_FILE_MODE
2087 Change or read the mode of a single filehandle
2088 Unit *current; filehandle to change
2089 ULONG newmode; new mode/old mode on return
2090 ULONG mask; bits affected
2092 FSA_MOUNT_MODE
2093 Change or read the mode of the filesystem
2094 Unit *current; filesystem to change
2095 ULONG newmode; new mode/old mode on return
2096 ULONG mask; bits affected
2097 STRPTR passwd; password for MMF_LOCKED
2099 FSA_MAKE_HARDLINK
2100 Create a hard link on a file, directory or soft link
2101 Unit *current; current directory
2102 STRPTR name; softlink name
2103 Unit *target; target handle
2105 FSA_MAKE_SOFTLINK
2106 Create a soft link to another object
2107 Unit *current; current directory
2108 STRPTR name; softlink name
2109 STRPTR target; target name
2111 FSA_RENAME
2112 FSA_READ_LINK
2113 FSA_SERIALIZE_DISK
2114 FSA_WAIT_CHAR
2115 FSA_INFO
2116 FSA_TIMER
2117 FSA_DISK_TYPE
2118 FSA_DISK_CHANGE
2119 FSA_SAME_LOCK
2120 FSA_CHANGE_SIGNAL
2121 FSA_FORMAT
2122 FSA_EXAMINE_ALL
2123 FSA_EXAMINE_FH
2124 FSA_EXAMINE_ALL_END
2129 iofs->io_DosError = error;
2130 ReplyMsg(&iofs->IOFS.io_Message);
2133 #if 0
2134 if (rambase->iofs != NULL)
2136 iofs = rambase->iofs;
2138 if (iofs->IOFS.io_Message.mn_Node.ln_Type == NT_MESSAGE)
2140 abort_notify(rambase, iofs);
2141 iofs->io_DosError = ERROR_BREAK;
2142 rambase->iofs = NULL;
2143 ReplyMsg(&iofs->IOFS.io_Message);
2145 else
2147 rambase->iofs = NULL;
2148 Signal(1, 0);
2151 #endif
2158 /***************************************************************************
2159 ****************************************************************************/
2161 /** Notification stuff **/
2164 * Immediate notification:
2166 * ACTION_RENAME_OBJECT
2167 * ACTION_RENAME_DISK
2168 * ACTION_CREATE_DIR
2169 * ACTION_DELETE_OBJECT
2170 * ACTION_SET_DATE
2173 * Session semantics notification:
2175 * ACTION_WRITE
2176 * ACTION_FINDUPDATE
2177 * ACTION_FINDOUTPUT
2178 * ACTION_SET_FILE_SIZE
2181 * For ram-handler, the only FSA actions currently implemented/affected are
2182 * FSA_WRITE, FSA_CREATE_DIR, FSA_DELETE (and implicitly FSA_OPEN, FSA_CLOSE)
2187 BOOL Notify_initialize(struct rambase *rambase)
2189 rambase->notifyPort = CreateMsgPort();
2191 if (rambase->notifyPort == NULL)
2193 return FALSE;
2196 return TRUE;
2200 void Notify_fileChange(struct rambase *rambase, NType type, struct fnode *file)
2202 switch (type)
2204 case NOTIFY_Open:
2205 break;
2207 case NOTIFY_Write:
2208 // kprintf("Setting write flag!\n");
2209 file->flags |= FILEFLAGS_Changed;
2210 break;
2212 case NOTIFY_Close:
2213 /* Only notify in case the file was changed */
2214 if (file->flags & FILEFLAGS_Changed)
2216 // kprintf("Notification on close (file was changed).\n");
2217 file->flags &= ~FILEFLAGS_Changed;
2218 Notify_notifyTasks(rambase, &file->receivers);
2220 break;
2222 case NOTIFY_Add:
2224 STRPTR fullName;
2225 struct List *receivers;
2227 fullName = getName(rambase, (struct dnode *)file, "");
2229 D(kprintf("Found full name: %s\n", fullName));
2231 receivers = HashTable_find(rambase, rambase->notifications,
2232 fullName);
2234 if (receivers != NULL)
2236 D(kprintf("Found notification for created file!\n"));
2238 while (!IsListEmpty(receivers))
2240 AddHead((struct List *)&file->receivers,
2241 RemHead(receivers));
2245 HashTable_remove(rambase, rambase->notifications, fullName);
2247 FreeVec(fullName);
2249 break;
2251 case NOTIFY_Delete:
2252 /* It's the same thing as for directories... */
2253 Notify_directoryChange(rambase, NOTIFY_Delete, (struct dnode *)file);
2254 break;
2256 default:
2257 kprintf("Error\n");
2258 break;
2263 void Notify_directoryChange(struct rambase *rambase, NType type,
2264 struct dnode *dir)
2266 switch (type)
2268 case NOTIFY_Open:
2270 STRPTR fullName;
2272 fullName = getName(rambase, dir, "");
2274 /* TODO: HashTable_apply(ht, fullName, dir); */
2276 FreeVec(fullName);
2278 break;
2280 case NOTIFY_Add:
2282 STRPTR fullName;
2283 struct List *receivers;
2285 fullName = getName(rambase, dir, "");
2287 D(kprintf("Found full name: %s\n", fullName));
2289 receivers = HashTable_find(rambase, rambase->notifications,
2290 fullName);
2292 if (receivers != NULL)
2294 D(kprintf("Found notification for created directory!\n"));
2296 while (!IsListEmpty(receivers))
2298 AddHead((struct List *)&dir->receivers,
2299 RemHead(receivers));
2303 HashTable_remove(rambase, rambase->notifications, fullName);
2305 FreeVec(fullName);
2308 D(kprintf("Notifying receivers!\n"));
2309 Notify_notifyTasks(rambase, &dir->receivers);
2310 break;
2312 case NOTIFY_Delete:
2314 /* As we have deleted a file, we must move the requests for
2315 this file to the hash table */
2316 struct List *receivers = (struct List *)&dir->receivers;
2318 Notify_notifyTasks(rambase, &dir->receivers);
2320 /* Move the Notification request to the hash table as we're going
2321 to delete this directory */
2322 while (!IsListEmpty(receivers))
2324 struct Receiver *rr = (struct Receiver *)RemHead(receivers);
2326 HashTable_insert(rambase, rambase->notifications,
2327 rr->nr->nr_FullName, rr);
2331 break;
2333 default:
2334 kprintf("Error\n");
2335 break;
2338 // kprintf("Returning from Notify_dirChange()\n");
2342 /* TODO: Implement support for NRF_WAIT_REPLY */
2343 void Notify_notifyTasks(struct rambase *rambase, struct MinList *notifications)
2345 struct Receiver *rr;
2347 // kprintf("Inside notifytasks, not = %p\n", notifications);
2349 ForeachNode((struct List *)notifications, rr)
2351 struct NotifyRequest *nr = rr->nr;
2353 if (nr->nr_Flags & NRF_SEND_MESSAGE &&
2354 !(nr->nr_Flags & NRF_WAIT_REPLY && nr->nr_Flags & NRF_NOT_REPLIED))
2356 struct NotifyMessage *nm = AllocVec(sizeof(struct NotifyMessage),
2357 MEMF_PUBLIC | MEMF_CLEAR);
2359 if (nm == NULL)
2361 return;
2364 nm->nm_ExecMessage.mn_ReplyPort = rambase->notifyPort;
2365 nm->nm_ExecMessage.mn_Length = sizeof(struct NotifyMessage);
2366 nm->nm_NReq = nr;
2367 nr->nr_Flags |= NRF_NOT_REPLIED;
2369 PutMsg(nr->nr_stuff.nr_Msg.nr_Port, &nm->nm_ExecMessage);
2371 else if (nr->nr_Flags & NRF_SEND_SIGNAL)
2373 Signal(nr->nr_stuff.nr_Signal.nr_Task,
2374 1 << nr->nr_stuff.nr_Signal.nr_SignalNum);
2380 BOOL Notify_addNotification(struct rambase *rambase, struct dnode *dn,
2381 struct NotifyRequest *nr)
2383 struct dnode *dnTemp = dn;
2384 HashTable *ht = rambase->notifications;
2385 STRPTR name = nr->nr_FullName, colon;
2387 colon = strchr(name, ':');
2388 if (colon != NULL)
2389 name = colon + 1;
2391 /* First: Check if the file is opened */
2393 D(kprintf("Checking existence of %s\n", name));
2395 if (findname(rambase, &name, &dnTemp) == 0)
2397 /* This file was already opened (or at least known by the file
2398 system) */
2400 struct Receiver *rr = AllocVec(sizeof(struct Receiver), MEMF_CLEAR);
2402 if (rr == NULL)
2404 return FALSE;
2407 rr->nr = nr;
2409 if (nr->nr_Flags & NRF_NOTIFY_INITIAL)
2411 struct MinList tempList;
2413 /* Create a temporary list on the stack and add the receiver to
2414 it. Then forget about this and add the node to the receiver
2415 list (below this block). */
2416 NewList((struct List *)&tempList);
2417 AddHead((struct List *)&tempList, &rr->node);
2418 Notify_notifyTasks(rambase, &tempList);
2421 /* Add the receiver node to the file's/directory's list of receivers */
2422 AddTail((struct List *)&dnTemp->receivers, &rr->node);
2424 return TRUE;
2426 else
2428 /* This file is not opened */
2430 struct Receiver *rr = AllocVec(sizeof(struct Receiver), MEMF_CLEAR);
2432 if (rr == NULL)
2434 return FALSE;
2437 rr->nr = nr;
2439 HashTable_insert(rambase, ht, name, rr);
2441 return TRUE;
2446 void Notify_removeNotification(struct rambase *rambase,
2447 struct NotifyRequest *nr)
2449 struct dnode *dn = (struct dnode *)rambase->root;
2450 struct Receiver *rr, *rrTemp;
2451 /* STRPTR name = strchr(nr->nr_FullName, '/') + 1; */
2452 STRPTR name = nr->nr_FullName;
2453 struct List *receivers;
2454 BOOL fromTable = FALSE;
2455 STRPTR colon;
2457 colon = strchr(name, ':');
2459 /* Take care of absolute names in nr_Name */
2460 if (colon != NULL)
2462 name = colon + 1;
2465 if (findname(rambase, &name, &dn) == 0)
2467 receivers = (struct List *)&dn->receivers;
2469 else
2471 /* This was a request for an entity that doesn't exist yet */
2472 receivers = HashTable_find(rambase, rambase->notifications, name);
2474 if (receivers == NULL)
2476 kprintf("Ram: This should not happen! -- buggy application...\n");
2477 return;
2480 fromTable = TRUE;
2484 ForeachNodeSafe(&receivers, rr, rrTemp)
2486 if (rr->nr == nr)
2488 Remove((struct Node *)rr);
2489 FreeVec(rr);
2490 break;
2494 if (fromTable)
2496 /* If we removed a request for a file that doesn't exist yet --
2497 if this was the only notification request for that file, remove
2498 also the hash entry. */
2499 if (IsListEmpty((struct List *)receivers))
2501 HashTable_remove(rambase, rambase->notifications, name);
2507 STRPTR getAbsoluteName(struct rambase *rambase, STRPTR name)
2509 int length = strlen(name) + 1 + 1;
2510 STRPTR fullName = AllocVec(length, MEMF_CLEAR | MEMF_PUBLIC);
2512 if (fullName == NULL)
2514 return NULL;
2517 strcpy(fullName, name);
2518 *strchr(fullName, ':') = '/';
2520 if (fullName[strlen(fullName) - 1] != '/')
2522 strcat(fullName, "/");
2525 return fullName;
2529 STRPTR getName(struct rambase *rambase, struct dnode *dn, STRPTR name)
2531 struct dnode *dnTemp = dn;
2533 ULONG length;
2534 STRPTR fullName;
2535 STRPTR fullNameTemp;
2536 STRPTR slash = "/";
2537 STRPTR nextSlash = slash;
2539 /* First, calculate the size of the complete filename */
2541 if (strchr(name, ':') != NULL)
2543 return getAbsoluteName(rambase, name);
2547 length = strlen(name) + 1 + 1 + 1; /* Add trailing 0 byte and possible '/' */
2548 length += strlen(dn->name) + 1;
2550 while (findname(rambase, &slash, &dnTemp) == 0)
2552 slash = nextSlash;
2553 length += 1 + strlen(dnTemp->name); /* Add '/' byte */
2556 /* The MEMF_CLEAR is necessary for the while loop below to work */
2557 fullName = AllocVec(length, MEMF_PUBLIC | MEMF_CLEAR);
2559 if (fullName == NULL)
2561 return NULL;
2564 fullNameTemp = fullName;
2566 dnTemp = dn;
2567 fullName += length - 1 - 1;
2570 int temp = strlen(name);
2572 if (temp > 0 && name[temp - 1] != '/')
2574 *fullName = '/';
2578 fullName -= strlen(name);
2579 strncpy(fullName, name, strlen(name));
2581 fullName -= strlen(dn->name) + 1;
2582 strcpy(fullName, dn->name);
2583 fullName[strlen(dn->name)] = '/';
2586 ULONG partLen;
2587 STRPTR slash = "/";
2588 STRPTR nextSlash = slash;
2590 while (findname(rambase, &slash, &dnTemp) != ERROR_OBJECT_NOT_FOUND)
2592 slash = nextSlash;
2593 partLen = strlen(dnTemp->name);
2595 fullName -= partLen + 1;
2596 strcpy(fullName, dnTemp->name);
2597 fullName[partLen] = '/'; /* Replace 0 with '/' */
2601 if (fullName != fullNameTemp)
2603 length = 0;
2604 while((fullNameTemp[length] = fullName[length])) length++;
2607 return fullNameTemp;
2611 HashNode *find(struct rambase *rambase, HashTable *ht,
2612 void *key, struct List *list);
2615 HashTable *HashTable_new(struct rambase *rambase, ULONG size,
2616 ULONG (*hash)(struct rambase *rambase,
2617 const void *key),
2618 int (*compare)(struct rambase *rambase,
2619 const void *key1,
2620 const void *key2),
2621 void (*delete)(struct rambase *rambase,
2622 void *key,
2623 struct List *list))
2625 ULONG i; /* Loop variable */
2626 HashTable *ht = AllocVec(sizeof(HashTable), MEMF_ANY);
2628 if (ht == NULL)
2630 return NULL;
2633 ht->size = size;
2634 ht->nElems = 0;
2635 ht->array = AllocVec(sizeof(struct List)*size, MEMF_ANY);
2637 if (ht->array == NULL)
2639 FreeVec(ht);
2641 return NULL;
2644 ht->hash = hash;
2645 ht->compare = compare;
2646 ht->delete = delete;
2648 for (i = 0; i < size; i++)
2650 NewList(&ht->array[i]);
2653 return ht;
2657 /* TODO: Fix the double list thing, remove the (void *) hack */
2658 void HashTable_delete(struct rambase *rambase, HashTable *ht)
2660 ULONG i;
2662 for (i = 0; i < ht->size; i++)
2664 while (!IsListEmpty(&ht->array[i]))
2666 HashNode *hn = (HashNode *)RemHead(&ht->array[i]);
2668 ht->delete(rambase, hn->key, (void *)&hn->requests);
2669 FreeVec(hn);
2673 FreeVec(ht);
2677 void HashTable_insert(struct rambase *rambase, HashTable *ht, void *key,
2678 struct Receiver *rr)
2680 ULONG pos;
2681 HashNode *hn;
2683 pos = ht->hash(rambase, key) % ht->size;
2685 hn = find(rambase, ht, key, &ht->array[pos]);
2687 if (hn == NULL)
2689 /* There was no previous request for this entity */
2690 hn = AllocVec(sizeof(HashNode), MEMF_ANY);
2692 if (hn == NULL)
2694 return;
2697 hn->key = Strdup(rambase, key);
2699 if (hn->key == NULL)
2701 FreeVec(hn);
2702 return;
2705 NewList(&hn->requests);
2706 AddHead(&ht->array[pos], &hn->node);
2709 AddHead(&hn->requests, &rr->node);
2711 ht->nElems++;
2715 void HashTable_remove(struct rambase *rambase, HashTable *ht, void *key)
2717 HashNode *hn;
2718 ULONG pos;
2719 struct Node *tempNode;
2720 struct List *list;
2722 pos = ht->hash(rambase, key) % ht->size;
2723 list = &ht->array[pos];
2725 ForeachNodeSafe(list, hn, tempNode)
2727 if (ht->compare(rambase, key, hn->key) == 0)
2729 Remove(&hn->node);
2730 ht->delete(rambase, hn->key, (void *)&hn->requests);
2731 FreeVec(hn);
2732 break;
2738 HashNode *find(
2739 struct rambase *rambase, HashTable *ht,
2740 void *key, struct List *list)
2742 HashNode *hn; /* Loop variable */
2744 ForeachNode(list, hn)
2746 if (ht->compare(rambase, key, hn->key) == 0)
2748 return hn;
2752 return NULL;
2756 struct List *HashTable_find(struct rambase *rambase, HashTable *ht, void *key)
2758 HashNode *hn;
2759 ULONG pos;
2761 pos = ht->hash(rambase, key) % ht->size;
2762 hn = find(rambase, ht, key, &ht->array[pos]);
2764 if (hn != NULL)
2766 return &hn->requests;
2768 else
2770 return NULL;
2773 return NULL; /* Make the compiler happy */
2777 inline ULONG HashTable_size(HashTable *ht)
2779 return ht->nElems;
2782 ADD2INITLIB(GM_UNIQUENAME(Init),0)
2783 ADD2OPENDEV(GM_UNIQUENAME(Open),0)
2784 ADD2CLOSEDEV(GM_UNIQUENAME(Close),0)
2785 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge),0)