add a missing section header table index conversion
[tangerine.git] / workbench / devs / ram_handler / ram_handler.c
blob3e75e6de1edb37de5cabb0c2938f0f3ff82e804a
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 RAM: handler.
6 */
8 #define DEBUG 0
9 #include <aros/debug.h>
11 #include <exec/errors.h>
12 #include <exec/types.h>
13 #include <exec/resident.h>
14 #include <exec/memory.h>
15 #include <exec/semaphores.h>
16 #include <utility/tagitem.h>
17 #include <utility/utility.h>
18 #include <proto/exec.h>
19 #include <proto/utility.h>
20 #include <proto/alib.h>
21 #include <proto/dos.h>
22 #include <dos/dos.h>
23 #include <dos/dosextens.h>
24 #include <dos/dosasl.h>
25 #include <dos/exall.h>
26 #include <dos/filesystem.h>
27 #include <aros/libcall.h>
28 #include <aros/symbolsets.h>
30 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
31 #include "ram_handler_gcc.h"
32 #endif
33 #include <stddef.h>
34 #include <string.h>
36 #include "HashTable.h"
38 static void deventry();
40 #include LC_LIBDEFS_FILE
42 #define NRF_NOT_REPLIED NRF_MAGIC
45 /* Device node */
46 struct cnode
48 struct MinNode node;
49 LONG type; /* ST_LINKDIR */
50 STRPTR name; /* Link's name */
51 struct cnode *self; /* Pointer to top of structure */
52 struct hnode *link; /* NULL */
53 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
54 ULONG protect; /* 0 */
55 STRPTR comment; /* NULL */
56 struct vnode *volume; /* Pointer to volume */
57 struct DosList *doslist; /* Pointer to doslist entry */
60 /* Volume node */
61 struct vnode
63 struct MinNode node;
64 LONG type; /* ST_USERDIR */
65 STRPTR name; /* Directory name */
66 struct vnode *self; /* Points to top of structure */
67 struct hnode *link; /* This one is linked to me */
68 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
69 ULONG protect; /* 0 */
70 STRPTR comment; /* NULL */
71 struct MinList receivers;
72 struct DateStamp date;
73 struct MinList list; /* Contents of directory */
74 ULONG volcount; /* number of handles on this volume */
75 struct DosList *doslist; /* Pointer to doslist entry */
78 /* Directory node */
79 struct dnode
81 struct MinNode node;
82 LONG type; /* ST_USERDIR */
83 STRPTR name; /* Directory name */
84 struct vnode *volume; /* Volume's root directory */
85 struct hnode *link; /* This one is linked to me */
86 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
87 ULONG protect; /* protection bits */
88 STRPTR comment; /* Some comment */
89 struct MinList receivers;
90 struct DateStamp date;
91 struct MinList list; /* Contents of directory */
94 /* File node */
95 struct fnode
97 struct MinNode node;
98 LONG type; /* ST_FILE */
99 STRPTR name; /* Filename */
100 struct vnode *volume; /* Volume's root directory */
101 struct hnode *link; /* This one is linked to me */
102 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
103 ULONG protect; /* protection bits */
104 STRPTR comment; /* Some file comment */
105 struct MinList receivers;
106 struct DateStamp date;
107 ULONG flags;
108 LONG size; /* Filesize */
109 UBYTE *blocks[16]; /* Upto 0x1000 bytes */
110 UBYTE **iblocks[4]; /* Upto 0x41000 bytes */
111 UBYTE ***i2block; /* Upto 0x1041000 bytes */
112 UBYTE ****i3block; /* Upto 0x101041000 bytes */
115 /* Softlink node */
116 struct snode
118 struct MinNode node;
119 LONG type; /* ST_SOFTLINK */
120 STRPTR name; /* Link's name */
121 struct vnode *volume; /* Volume's root directory */
122 struct hnode *link; /* This one is hardlinked to me */
123 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
124 ULONG protect; /* protection bits */
125 STRPTR comment; /* Some file comment */
126 char *contents; /* Contents of soft link */
129 /* Hardlink node */
130 struct hnode
132 struct MinNode node;
133 LONG type; /* ST_LINKDIR */
134 STRPTR name; /* Link's name */
135 struct vnode *volume; /* Volume's root directory */
136 struct hnode *link; /* This one is hardlinked to me */
137 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
138 ULONG protect; /* protection bits */
139 STRPTR comment; /* Some file comment */
140 struct hnode *orig; /* original object */
143 /*****************************************************************************/
145 #define FILEFLAGS_Changed 1
147 static STRPTR getName(struct rambase *rambase, struct dnode *dn);
149 typedef enum
151 NOTIFY_Add,
152 NOTIFY_Delete,
153 NOTIFY_Write,
154 NOTIFY_Close,
155 NOTIFY_Open,
156 } NType;
158 void Notify_notifyTasks(struct rambase *rambase,
159 struct MinList *notifications);
161 BOOL Notify_initialize(struct rambase *rambase);
162 void Notify_fileChange(struct rambase *rambase, NType type,
163 struct fnode *file);
164 void Notify_directoryChange(struct rambase *rambase, NType type,
165 struct dnode *dir);
168 BOOL Notify_addNotification(struct rambase *rambase, struct dnode *dn,
169 struct NotifyRequest *nr);
170 void Notify_removeNotification(struct rambase *rambase,
171 struct NotifyRequest *nr);
173 /****************************************************************************/
176 #define BLOCKSIZE 256
177 #define PBLOCKSIZE (256*sizeof(UBYTE *))
179 struct filehandle
181 struct dnode *node;
182 IPTR position;
185 /* Use This from now on */
186 #ifdef DOSBase
187 #undef DOSBase
188 #endif
189 #define DOSBase rambase->dosbase
191 static int OpenDev(LIBBASETYPEPTR rambase, struct IOFileSys *iofs);
193 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR rambase)
195 /* This function is single-threaded by exec by calling Forbid. */
197 struct MsgPort *port;
198 struct Task *task;
199 struct SignalSemaphore *semaphore;
200 APTR stack;
202 rambase->dosbase = (struct DosLibrary *)OpenLibrary(DOSNAME, 39);
204 if (rambase->dosbase != NULL)
206 rambase->utilitybase = (struct UtilityBase *)OpenLibrary(UTILITYNAME, 39);
208 if (rambase->utilitybase != NULL)
210 port = (struct MsgPort *)AllocMem(sizeof(struct MsgPort),
211 MEMF_PUBLIC | MEMF_CLEAR);
212 if (port != NULL)
214 rambase->port = port;
215 NewList(&port->mp_MsgList);
216 port->mp_Node.ln_Type = NT_MSGPORT;
217 port->mp_SigBit = SIGB_SINGLE;
219 task = (struct Task *)AllocMem(sizeof(struct Task),
220 MEMF_PUBLIC | MEMF_CLEAR);
222 if (task != NULL)
224 port->mp_SigTask = task;
225 port->mp_Flags = PA_IGNORE;
226 NewList(&task->tc_MemEntry);
227 task->tc_Node.ln_Type = NT_TASK;
228 task->tc_Node.ln_Name = "ram.handler task";
230 stack = AllocMem(AROS_STACKSIZE, MEMF_PUBLIC);
232 if (stack != NULL)
234 struct TagItem tasktags[] =
236 {TASKTAG_ARG1, (IPTR)rambase},
237 {TAG_DONE }
240 task->tc_SPLower = stack;
241 task->tc_SPUpper = (BYTE *)stack + AROS_STACKSIZE;
242 #if AROS_STACK_GROWS_DOWNWARDS
243 task->tc_SPReg = (BYTE *)task->tc_SPUpper - SP_OFFSET;
244 #else
245 task->tc_SPReg = (BYTE *)task->tc_SPLower + SP_OFFSET;
246 #endif
248 semaphore = (struct SignalSemaphore *)AllocMem(sizeof(struct SignalSemaphore),
249 MEMF_PUBLIC | MEMF_CLEAR);
251 if (semaphore != NULL)
253 rambase->sigsem = semaphore;
254 InitSemaphore(semaphore);
256 if (rambase->seglist==NULL) /* Are we a ROM module? */
258 struct DeviceNode *dn;
259 /* Install RAM: handler into device list
261 * KLUDGE: ram.handler should create only one device node, depending on
262 * the startup packet it gets. The mountlists for RAM: should be into dos.library bootstrap
263 * routines.
266 if((dn = AllocMem(sizeof (struct DeviceNode) + 4 + 3 + 2, MEMF_CLEAR|MEMF_PUBLIC)))
268 struct IOFileSys dummyiofs;
270 if (OpenDev(rambase, &dummyiofs))
272 BSTR s = MKBADDR(((IPTR)dn + sizeof(struct DeviceNode) + 4) & ~3);
274 rambase->device.dd_Library.lib_OpenCnt++;
276 AROS_BSTR_putchar(s, 0, 'R');
277 AROS_BSTR_putchar(s, 1, 'A');
278 AROS_BSTR_putchar(s, 2, 'M');
279 AROS_BSTR_putchar(s, 3, 0);
280 AROS_BSTR_setstrlen(s, 3);
282 dn->dn_Type = DLT_DEVICE;
283 dn->dn_Ext.dn_AROS.dn_Unit = dummyiofs.IOFS.io_Unit;
284 dn->dn_Ext.dn_AROS.dn_Device = dummyiofs.IOFS.io_Device;
285 dn->dn_Handler = NULL;
286 dn->dn_Startup = NULL;
287 dn->dn_Name = s;
288 dn->dn_Ext.dn_AROS.dn_DevName = AROS_BSTR_ADDR(dn->dn_Name);
290 if (AddDosEntry((struct DosList *)dn))
291 if (NewAddTask(task, deventry, NULL, tasktags) != NULL)
292 return TRUE;
295 FreeMem(dn, sizeof (struct DeviceNode));
298 else
299 if (NewAddTask(task, deventry, NULL, tasktags) != NULL)
300 return TRUE;
302 FreeMem(semaphore, sizeof(struct SignalSemaphore));
305 FreeMem(stack, AROS_STACKSIZE);
308 FreeMem(task, sizeof(struct Task));
311 FreeMem(port, sizeof(struct MsgPort));
314 CloseLibrary((struct Library *)rambase->utilitybase);
317 CloseLibrary((struct Library *)rambase->dosbase);
320 return FALSE;
323 #ifdef UtilityBase
324 #undef UtilityBase
325 #endif
326 #define UtilityBase rambase->utilitybase
329 /***************************************************************************/
331 void nullDelete(struct rambase *rambase, void *key, struct List *list)
333 // struct Receiver *rr;
334 // struct Node *tempNode;
336 // ForeachNodeSafe(list, rr, tempNode)
337 // {
338 // Remove(&rr->node);
339 // FreeVec(rr);
340 // }
342 FreeVec(key);
344 /* The list is part of the HashNode so we shouldn't free that */
348 ULONG stringHash(struct rambase *rambase, const void *key)
350 STRPTR str = (STRPTR)key;
351 ULONG val = 1;
353 while (*str != 0)
355 val *= ToLower(*str++);
356 val <<= 2;
359 return val;
362 static int
363 my_strcasecmp(struct rambase *rambase, const void *s1, const void *s2)
365 return strcasecmp(s1, s2);
368 /****************************************************************************/
371 STRPTR Strdup(struct rambase *rambase, CONST_STRPTR string)
373 CONST_STRPTR s2 = string;
374 STRPTR s3;
376 while(*s2++)
379 s3 = (STRPTR)AllocVec(s2 - string, MEMF_ANY);
381 if (s3 != NULL)
383 CopyMem(string, s3, s2 - string);
386 return s3;
390 void Strfree(struct rambase *rambase, STRPTR string)
392 FreeVec(string);
396 static int GM_UNIQUENAME(Open)
398 LIBBASETYPEPTR rambase,
399 struct IOFileSys *iofs,
400 ULONG unitnum,
401 ULONG flags
404 /* Mark Message as recently used. */
405 iofs->IOFS.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
407 return OpenDev(rambase, iofs);
411 static int OpenDev(LIBBASETYPEPTR rambase, struct IOFileSys *iofs)
413 struct filehandle *fhv, *fhc;
414 struct vnode *vol;
415 struct cnode *dev;
416 struct DosList *dlv;
418 iofs->IOFS.io_Error = ERROR_NO_FREE_STORE;
420 fhv = (struct filehandle*)AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
422 if (fhv != NULL)
424 fhc = (struct filehandle*)AllocMem(sizeof(struct filehandle),
425 MEMF_CLEAR);
427 if (fhc != NULL)
429 vol = (struct vnode *)AllocMem(sizeof(struct vnode), MEMF_CLEAR);
431 if (vol != NULL)
433 dev = (struct cnode *)AllocMem(sizeof(struct cnode),
434 MEMF_CLEAR);
436 if (dev != NULL)
438 vol->name = Strdup(rambase, "Ram Disk");
440 if (vol->name != NULL)
442 dlv = MakeDosEntry("Ram Disk", DLT_VOLUME);
444 if (dlv != NULL)
446 vol->type = ST_USERDIR;
447 vol->self = vol;
448 vol->doslist = dlv;
449 vol->protect = 0UL;
450 NewList((struct List *)&vol->list);
451 NewList((struct List *)&vol->receivers);
452 fhv->node = (struct dnode *)vol;
453 dlv->dol_Ext.dol_AROS.dol_Unit = (struct Unit *)fhv;
454 dlv->dol_Ext.dol_AROS.dol_Device = &rambase->device;
455 dev->type = ST_LINKDIR;
456 dev->self = dev;
457 dev->volume=vol;
458 fhc->node = (struct dnode *)dev;
459 iofs->IOFS.io_Unit = (struct Unit *)fhc;
460 iofs->IOFS.io_Device = &rambase->device;
461 AddDosEntry(dlv);
462 rambase->root = vol;
463 iofs->IOFS.io_Error = 0;
465 rambase->notifications =
466 HashTable_new(rambase, 100, stringHash,
467 my_strcasecmp, nullDelete);
469 return TRUE;
472 Strfree(rambase, vol->name);
475 FreeMem(dev, sizeof(struct cnode));
478 FreeMem(vol, sizeof(struct vnode));
481 FreeMem(fhc, sizeof(struct filehandle));
484 FreeMem(fhv, sizeof(struct filehandle));
487 iofs->IOFS.io_Error = IOERR_OPENFAIL;
489 return FALSE;
492 static int GM_UNIQUENAME(Expunge)(LIBBASETYPEPTR rambase)
495 This function is single-threaded by exec by calling Forbid.
496 Never break the Forbid() or strange things might happen.
499 /* Kill device task and free all resources */
500 RemTask(rambase->port->mp_SigTask);
501 FreeMem(rambase->sigsem, sizeof(struct SignalSemaphore));
502 FreeMem(((struct Task *)rambase->port->mp_SigTask)->tc_SPLower,
503 AROS_STACKSIZE);
504 FreeMem(rambase->port->mp_SigTask, sizeof(struct Task));
505 FreeMem(rambase->port, sizeof(struct MsgPort));
506 CloseLibrary((struct Library *)rambase->utilitybase);
507 CloseLibrary((struct Library *)rambase->dosbase);
509 return TRUE;
513 AROS_LH1(void, beginio,
514 AROS_LHA(struct IOFileSys *, iofs, A1),
515 struct rambase *, rambase, 5, Ram)
517 AROS_LIBFUNC_INIT
519 /* WaitIO will look into this */
520 iofs->IOFS.io_Message.mn_Node.ln_Type = NT_MESSAGE;
522 /* Nothing is done quick */
523 iofs->IOFS.io_Flags &= ~IOF_QUICK;
525 /* So let the device task do it */
526 PutMsg(rambase->port, &iofs->IOFS.io_Message);
528 AROS_LIBFUNC_EXIT
532 AROS_LH1(LONG, abortio,
533 AROS_LHA(struct IOFileSys *, iofs, A1),
534 struct rambase *, rambase, 6, Ram)
536 AROS_LIBFUNC_INIT
537 return 0;
538 AROS_LIBFUNC_EXIT
542 static LONG getblock(struct rambase *rambase, struct fnode *file, LONG block,
543 int mode, UBYTE **result)
545 ULONG a, i;
546 UBYTE **p, **p2;
548 if (block < 0x10)
550 p = &file->blocks[block];
551 block= 0 ;
552 i = 0;
554 else if (block < 0x410)
556 block -= 0x10;
557 p = (UBYTE **)&file->iblocks[block/0x100];
558 block &= 0xff;
559 i = 1;
561 else if(block < 0x10410)
563 block -= 0x410;
564 p = (UBYTE **)&file->i2block;
565 i = 2;
567 else
569 block -= 0x10410;
570 p = (UBYTE **)&file->i3block;
571 i = 3;
574 switch (mode)
576 case -1:
577 p2 = (UBYTE **)*p;
579 if (!block)
581 *p = NULL;
584 p = p2;
586 while (i-- && p != NULL)
588 a = (block >> i*8) & 0xff;
589 p2 = (UBYTE **)p[a];
591 if (!(block & ((1 << i*8) - 1)))
593 p[a] = NULL;
595 if (!a)
597 FreeMem(p, PBLOCKSIZE);
601 p = p2;
604 if (p != NULL)
606 FreeMem(p, BLOCKSIZE);
609 break;
611 case 0:
612 p = (UBYTE **)*p;
614 while (i-- && p != NULL)
616 p = ((UBYTE ***)p)[(block >> i*8) & 0xff];
619 *result = (UBYTE *)p;
620 break;
622 case 1:
623 while (i--)
625 if (*p == NULL)
627 *p= AllocMem(PBLOCKSIZE, MEMF_CLEAR);
629 if (*p == NULL)
631 return ERROR_NO_FREE_STORE;
635 p = (UBYTE **)*p + ((block >> i*8) & 0xff);
638 if (*p == NULL)
640 *p = AllocMem(BLOCKSIZE, MEMF_CLEAR);
642 if (*p == NULL)
644 return ERROR_NO_FREE_STORE;
648 *result = *p;
649 break;
650 } /* switch (mode) */
652 return 0;
656 static void zerofill(UBYTE *address, ULONG size)
658 while (size--)
660 *address++ = 0;
665 static void shrinkfile(struct rambase *rambase, struct fnode *file, LONG size)
667 ULONG blocks, block;
668 UBYTE *p;
670 blocks = (size + BLOCKSIZE - 1)/BLOCKSIZE;
671 block = (file->size + BLOCKSIZE - 1)/BLOCKSIZE;
673 for(;block-- > blocks;)
675 (void)getblock(rambase, file, block, -1, &p);
678 if (size & 0xff)
680 (void)getblock(rambase, file, size, 0, &p);
682 if (p != NULL)
684 zerofill(p + (size & 0xff), -size & 0xff);
688 file->size = size;
692 static void delete(struct rambase *rambase, struct fnode *file)
694 struct hnode *link, *new, *more;
695 struct Node *node;
697 Strfree(rambase, file->name);
698 Strfree(rambase, file->comment);
699 Remove((struct Node *)file);
701 if (file->type == ST_LINKDIR)
703 /* It is a link. Remove it from the chain. */
705 link = ((struct hnode *)file)->orig;
706 ((struct hnode *)file)->orig = NULL;
707 file->type = link->type;
709 while((struct fnode *)link->link != file)
711 link = link->link;
714 link->link = file->link;
716 else if (file->link != NULL)
718 /* If there is a hard link to the object make the link the original */
720 link = file->link;
721 link->type = file->type;
722 more = new->link;
724 while (more != NULL)
726 more->orig = new;
727 more = more->link;
730 switch (file->type)
732 case ST_USERDIR:
733 while((node = RemHead((struct List *)&((struct dnode *)file)->list)) != NULL)
734 AddTail((struct List *)&((struct dnode *)file)->list, node);
735 break;
737 case ST_FILE:
738 CopyMemQuick(&file->size, &((struct fnode *)new)->size,
739 sizeof(struct fnode) - offsetof(struct fnode, size));
740 zerofill((UBYTE *)&file->size,
741 sizeof(struct fnode) - offsetof(struct fnode, size));
742 break;
744 case ST_SOFTLINK:
745 ((struct snode *)new)->contents = ((struct snode *)file)->contents;
746 ((struct snode *)file)->contents = NULL;
747 break;
749 } /* else if (file->link != NULL) */
751 switch (file->type)
753 case ST_USERDIR:
754 Notify_directoryChange(rambase, NOTIFY_Delete, (struct dnode *)file);
756 FreeMem(file, sizeof(struct dnode));
758 return;
760 case ST_FILE:
761 Notify_fileChange(rambase, NOTIFY_Delete, file);
763 shrinkfile(rambase, file, 0);
764 FreeMem(file, sizeof(struct fnode));
766 return;
768 case ST_SOFTLINK:
769 Strfree(rambase, ((struct snode *)file)->contents);
770 FreeMem(file, sizeof(struct snode));
772 return;
777 static int fstrcmp(struct rambase *rambase, CONST_STRPTR s1, CONST_STRPTR s2)
779 for (;;)
781 if (ToLower(*s1) != ToLower(*s2))
783 return *s1 || *s2 != '/';
786 if (!*s1)
788 return 0;
791 s1++;
792 s2++;
797 /* Find a node for a given name */
798 static LONG findname(struct rambase *rambase, CONST_STRPTR *name,
799 struct dnode **dnode)
801 struct dnode *cur = *dnode;
802 CONST_STRPTR rest = *name;
804 for (;;)
806 if (cur->type == ST_LINKDIR)
808 cur = (struct dnode *)((struct hnode *)cur)->orig;
811 if (!*rest)
813 break;
816 if (*rest == '/')
818 if ((struct dnode *)cur->volume == cur)
820 return ERROR_OBJECT_NOT_FOUND;
823 while (cur->node.mln_Pred != NULL)
825 cur = (struct dnode *)cur->node.mln_Pred;
828 cur = (struct dnode *)((BYTE *)cur - offsetof(struct dnode, list));
830 else
832 if (cur->type == ST_SOFTLINK)
834 *dnode = cur;
835 *name = rest;
837 return ERROR_IS_SOFT_LINK;
840 if (cur->type != ST_USERDIR)
842 return ERROR_DIR_NOT_FOUND;
845 *dnode = cur;
846 cur = (struct dnode *)cur->list.mlh_Head;
848 for (;;)
850 if (cur->node.mln_Succ == NULL)
852 *name = rest;
854 return ERROR_OBJECT_NOT_FOUND;
857 if (!fstrcmp(rambase, cur->name, rest))
859 break;
862 cur = (struct dnode *)cur->node.mln_Succ;
866 while (*rest)
868 if (*rest++ == '/')
870 break;
875 *dnode = cur;
877 return 0;
881 static LONG set_file_size(struct rambase *rambase, struct filehandle *handle,
882 QUAD *offp, LONG mode)
884 struct fnode *file = (struct fnode *)handle->node;
885 QUAD size = *offp;
887 if (file->type != ST_FILE)
889 return ERROR_OBJECT_WRONG_TYPE;
892 switch(mode)
894 case OFFSET_BEGINNING:
895 break;
897 case OFFSET_CURRENT:
898 size += handle->position;
899 break;
901 case OFFSET_END:
902 size += file->size;
903 break;
905 default:
906 return ERROR_NOT_IMPLEMENTED;
909 if (size < 0)
911 return ERROR_SEEK_ERROR;
914 if (size < file->size)
916 shrinkfile(rambase, file, size);
919 file->size = *offp = size;
921 return 0;
925 static LONG read(struct rambase *rambase, struct filehandle *handle,
926 APTR buffer, LONG *numbytes)
928 struct fnode *file = (struct fnode *)handle->node;
929 ULONG num = *numbytes;
930 ULONG size = file->size;
931 ULONG block, offset;
932 UBYTE *buf = buffer, *p;
934 if (handle->position >= size)
936 num = 0;
938 else if (handle->position + num > size)
940 num = size - handle->position;
943 block = handle->position/BLOCKSIZE;
944 offset = handle->position & (BLOCKSIZE - 1);
945 size = BLOCKSIZE - offset;
947 while (num)
949 if (size > num)
951 size = num;
954 (void)getblock(rambase, file, block, 0, &p);
956 if (p != NULL)
958 CopyMem(p + offset, buffer, size);
960 else
962 zerofill(buffer, size);
965 buffer += size;
966 num -= size;
967 block++;
968 offset = 0;
969 size = BLOCKSIZE;
972 *numbytes = (UBYTE *)buffer - buf;
973 handle->position += *numbytes;
975 return 0;
979 static LONG write(struct rambase *rambase, struct filehandle *handle,
980 UBYTE *buffer, LONG *numbytes)
982 struct fnode *file = (struct fnode *)handle->node;
983 ULONG num = *numbytes;
984 ULONG size = file->size;
985 ULONG block, offset;
986 UBYTE *buf = buffer, *p;
987 LONG error = 0;
989 if ((LONG)(handle->position + num) < 0)
991 return ERROR_OBJECT_TOO_LARGE;
994 Notify_fileChange(rambase, NOTIFY_Write, file);
996 block = handle->position/BLOCKSIZE;
997 offset = handle->position & (BLOCKSIZE - 1);
998 size = BLOCKSIZE - offset;
1000 while (num)
1002 if (size > num)
1004 size = num;
1007 error = getblock(rambase, file, block, 1, &p);
1009 if (error)
1011 break;
1014 CopyMem(buffer, p + offset, size);
1015 buffer += size;
1016 num -= size;
1017 block++;
1018 offset = 0;
1019 size = BLOCKSIZE;
1022 *numbytes = (UBYTE *)buffer - buf;
1023 handle->position += *numbytes;
1024 DateStamp(&file->date);
1026 if (handle->position > file->size)
1028 file->size = handle->position;
1031 return error;
1035 static LONG lock(struct dnode *dir, ULONG mode)
1037 if ((mode & FMF_EXECUTE) && (dir->protect & FMF_EXECUTE))
1039 return ERROR_NOT_EXECUTABLE;
1042 if ((mode & FMF_WRITE) && (dir->protect & FMF_WRITE))
1044 return ERROR_WRITE_PROTECTED;
1047 if ((mode & FMF_READ) && (dir->protect & FMF_READ))
1049 return ERROR_READ_PROTECTED;
1052 if (mode & FMF_LOCK)
1054 if (dir->usecount)
1056 return ERROR_OBJECT_IN_USE;
1059 dir->usecount = ((ULONG)~0)/2 + 1;
1061 else
1063 if (dir->usecount < 0)
1065 return ERROR_OBJECT_IN_USE;
1069 dir->usecount++;
1070 dir->volume->volcount++;
1072 return 0;
1076 static LONG open_(struct rambase *rambase, struct filehandle **handle,
1077 CONST_STRPTR name, ULONG mode)
1079 struct dnode *dir = (*handle)->node;
1080 struct filehandle *fh;
1081 LONG error;
1083 fh = (struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1085 if (fh != NULL)
1087 error = findname(rambase, &name, &dir);
1089 if (!error)
1091 error = lock(dir, mode);
1093 if (!error)
1095 fh->node = dir;
1096 *handle = fh;
1098 if (dir->type == ST_FILE)
1100 Notify_fileChange(rambase, NOTIFY_Open,
1101 (struct fnode *)dir);
1103 else if (dir->type == ST_USERDIR)
1105 D(kprintf("Notifying OPEN at dir %s\n", dir->name));
1106 Notify_directoryChange(rambase, NOTIFY_Open, dir);
1109 return 0;
1113 FreeMem(fh, sizeof(struct filehandle));
1115 else
1117 error = ERROR_NO_FREE_STORE;
1120 return error;
1124 static LONG open_file(struct rambase *rambase, struct filehandle **handle,
1125 CONST_STRPTR name, ULONG mode, ULONG protect)
1127 struct dnode *dir = (*handle)->node;
1128 struct filehandle *fh;
1129 LONG error = 0;
1131 fh = AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1133 if (fh != NULL)
1135 error = findname(rambase, &name, &dir);
1137 if ((mode & FMF_CREATE) && error == ERROR_OBJECT_NOT_FOUND)
1139 CONST_STRPTR s = name;
1140 struct fnode *file;
1142 while (*s)
1144 if (*s++ == '/')
1146 return error;
1150 file = (struct fnode *)AllocMem(sizeof(struct fnode), MEMF_CLEAR);
1151 DateStamp(&file->date);
1153 if (file != NULL)
1155 file->name = Strdup(rambase, name);
1157 if (file->name != NULL)
1159 file->type = ST_FILE;
1160 file->protect = protect;
1161 file->volume = dir->volume;
1162 NewList((struct List *)&file->receivers);
1163 AddTail((struct List *)&dir->list, (struct Node *)file);
1164 error = lock((struct dnode *)file, mode);
1166 if (!error)
1168 fh->node = (struct dnode *)file;
1169 *handle = fh;
1171 Notify_fileChange(rambase, NOTIFY_Add, file);
1173 return 0;
1176 Strfree(rambase, file->name);
1179 FreeMem(file,sizeof(struct fnode));
1182 error = ERROR_NO_FREE_STORE;
1184 else if (!error)
1186 if (dir->type != ST_FILE)
1188 error = ERROR_OBJECT_WRONG_TYPE;
1190 else
1192 error = lock(dir, mode);
1194 if (!error)
1196 /* stegerg */
1197 if (mode & FMF_CLEAR)
1199 shrinkfile(rambase, (struct fnode *)dir, 0);
1200 dir->protect = protect;
1202 /* end stegerg */
1204 fh->node = dir;
1205 *handle = fh;
1207 return 0;
1210 } /* else if (!error) */
1212 FreeMem(fh, sizeof(struct filehandle));
1215 return error;
1219 static LONG create_dir(struct rambase *rambase, struct filehandle **handle,
1220 CONST_STRPTR name, ULONG protect)
1222 struct dnode *dir = (*handle)->node, *new;
1223 struct filehandle *fh;
1224 LONG error;
1226 if (dir->protect & FIBF_WRITE)
1228 return ERROR_WRITE_PROTECTED;
1231 error = findname(rambase, &name, &dir);
1233 if (!error)
1235 return ERROR_OBJECT_EXISTS;
1238 if (error != ERROR_OBJECT_NOT_FOUND)
1240 return error;
1243 if (strchr(name, '/') != NULL)
1245 return error;
1248 fh = AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1250 if (fh != NULL)
1252 new = (struct dnode *)AllocMem(sizeof(struct dnode), MEMF_CLEAR);
1254 if (new != NULL)
1256 new->name = Strdup(rambase, name);
1258 if (new->name != NULL)
1260 new->type = ST_USERDIR;
1261 new->protect = protect;
1262 new->volume = dir->volume;
1263 new->volume->volcount++;
1264 new->usecount = ((ULONG)~0)/2 + 2;
1265 NewList((struct List *)&new->list);
1266 NewList((struct List *)&new->receivers);
1267 AddTail((struct List *)&dir->list, (struct Node *)new);
1268 fh->node = new;
1269 *handle = fh;
1270 DateStamp(&new->date);
1272 D(bug("New (%p): Name = %s\n", new, new->name));
1273 Notify_directoryChange(rambase, NOTIFY_Add, new);
1275 return 0;
1278 FreeMem(new, sizeof(struct dnode));
1281 FreeMem(fh, sizeof(struct filehandle));
1284 return ERROR_NO_FREE_STORE;
1288 static LONG free_lock(struct rambase *rambase, struct filehandle *filehandle)
1290 struct dnode *dnode = filehandle->node;
1292 dnode->usecount = (dnode->usecount - 1) & ((ULONG)~0)/2;
1293 FreeMem(filehandle, sizeof(struct filehandle));
1294 dnode->volume->volcount--;
1296 return 0;
1300 static LONG seek(struct rambase *rambase, struct filehandle *filehandle,
1301 QUAD *posp, LONG mode)
1303 struct fnode *file = (struct fnode *)filehandle->node;
1304 QUAD pos = *posp;
1306 if (file->type != ST_FILE)
1308 return ERROR_OBJECT_WRONG_TYPE;
1311 switch (mode)
1313 case OFFSET_BEGINNING:
1314 break;
1316 case OFFSET_CURRENT:
1317 pos += filehandle->position;
1318 break;
1320 case OFFSET_END:
1321 pos += file->size;
1322 break;
1324 default:
1325 return ERROR_NOT_IMPLEMENTED;
1328 if (pos < 0)
1330 return ERROR_SEEK_ERROR;
1333 *posp = filehandle->position;
1334 filehandle->position = pos;
1336 return 0;
1340 static const ULONG sizes[]=
1343 offsetof(struct ExAllData,ed_Type),
1344 offsetof(struct ExAllData,ed_Size),
1345 offsetof(struct ExAllData,ed_Prot),
1346 offsetof(struct ExAllData,ed_Days),
1347 offsetof(struct ExAllData,ed_Comment),
1348 offsetof(struct ExAllData,ed_OwnerUID),
1349 sizeof(struct ExAllData)
1353 static LONG examine(struct fnode *file,
1354 struct ExAllData *ead,
1355 ULONG size,
1356 ULONG type,
1357 LONG *dirpos)
1359 STRPTR next, end, name;
1361 if (type > ED_OWNER)
1363 return ERROR_BAD_NUMBER;
1366 next = (STRPTR)ead + sizes[type];
1367 end = (STRPTR)ead + size;
1369 if(next>end) /* > is correct. Not >= */
1370 return ERROR_BUFFER_OVERFLOW;
1372 /* Use *dirpos to store information for ExNext()
1373 * *dirpos is copied to fib->fib_DiskKey in Examine()
1375 if (file->type == ST_USERDIR)
1377 *dirpos = (LONG)(((struct dnode*)file)->list.mlh_Head);
1379 else
1381 /* ExNext() should not be called in this case anyway */
1382 *dirpos = (LONG)file;
1385 switch(type)
1387 case ED_OWNER:
1388 ead->ed_OwnerUID = 0;
1389 ead->ed_OwnerGID = 0;
1391 /* Fall through */
1392 case ED_COMMENT:
1393 if (file->comment != NULL)
1395 ead->ed_Comment = next;
1396 name = file->comment;
1398 for (;;)
1400 if (next >= end)
1402 return ERROR_BUFFER_OVERFLOW;
1405 if (!(*next++ = *name++))
1407 break;
1411 else
1413 ead->ed_Comment = NULL;
1416 /* Fall through */
1417 case ED_DATE:
1418 ead->ed_Days = file->date.ds_Days;
1419 ead->ed_Mins = file->date.ds_Minute;
1420 ead->ed_Ticks = file->date.ds_Tick;
1422 /* Fall through */
1423 case ED_PROTECTION:
1424 ead->ed_Prot = file->protect;
1426 /* Fall through */
1427 case ED_SIZE:
1428 ead->ed_Size = file->size;
1430 /* Fall through */
1431 case ED_TYPE:
1432 ead->ed_Type = file->type;
1434 if (((struct vnode *)file)->self == (struct vnode *)file)
1436 ead->ed_Type=ST_ROOT;
1439 /* Fall through */
1440 case ED_NAME:
1441 ead->ed_Name = next;
1442 name = file->name;
1444 for (;;)
1446 if (next >= end)
1448 return ERROR_BUFFER_OVERFLOW;
1451 if (!(*next++ = *name++))
1453 break;
1457 /* Fall through */
1458 case 0:
1459 ead->ed_Next = (struct ExAllData *)(((IPTR)next + AROS_PTRALIGN - 1) & ~(AROS_PTRALIGN - 1));
1462 return 0;
1466 static LONG examine_next(struct rambase *rambase,
1467 struct filehandle *dir,
1468 struct FileInfoBlock *FIB)
1470 struct fnode *file = (struct fnode *)FIB->fib_DiskKey;
1472 ASSERT_VALID_PTR_OR_NULL(file);
1474 if (file->node.mln_Succ == NULL)
1476 return ERROR_NO_MORE_ENTRIES;
1479 FIB->fib_OwnerUID = 0;
1480 FIB->fib_OwnerGID = 0;
1482 FIB->fib_Date.ds_Days = file->date.ds_Days;
1483 FIB->fib_Date.ds_Minute = file->date.ds_Minute;
1484 FIB->fib_Date.ds_Tick = file->date.ds_Tick;
1485 FIB->fib_Protection = file->protect;
1486 FIB->fib_Size = file->size;
1487 FIB->fib_DirEntryType = file->type;
1489 strncpy(FIB->fib_FileName, file->name, MAXFILENAMELENGTH - 1);
1490 strncpy(FIB->fib_Comment, file->comment != NULL ? file->comment : "",
1491 MAXCOMMENTLENGTH - 1);
1493 FIB->fib_DiskKey = (LONG)file->node.mln_Succ;
1495 return 0;
1499 static LONG examine_all(struct filehandle *dir,
1500 struct ExAllData *ead,
1501 struct ExAllControl *eac,
1502 ULONG size,
1503 ULONG type)
1505 STRPTR end;
1506 struct ExAllData *last=NULL;
1507 struct fnode *ent;
1508 LONG error;
1509 LONG dummy; /* not anything is done with this value but passed to examine */
1510 end = (STRPTR)ead + size;
1512 eac->eac_Entries = 0;
1513 if (dir->node->type != ST_USERDIR)
1515 return ERROR_OBJECT_WRONG_TYPE;
1518 ent = (struct fnode *)eac->eac_LastKey;
1520 if (ent == NULL)
1522 ent = (struct fnode *)dir->node->list.mlh_Head;
1523 if (ent->node.mln_Succ) ent->usecount++;
1526 if (ent->node.mln_Succ == NULL)
1528 return ERROR_NO_MORE_ENTRIES;
1531 ent->usecount--;
1535 error = examine(ent, ead, end - (STRPTR)ead, type, &dummy);
1537 if (error == ERROR_BUFFER_OVERFLOW)
1539 if (last == NULL)
1541 return error;
1544 ent->usecount++;
1545 last->ed_Next = NULL;
1546 eac->eac_LastKey = (IPTR)ent;
1548 return 0;
1550 eac->eac_Entries++;
1551 last = ead;
1552 ead = ead->ed_Next;
1553 ent = (struct fnode *)ent->node.mln_Succ;
1555 } while (ent->node.mln_Succ != NULL);
1557 last->ed_Next = NULL;
1558 eac->eac_LastKey = (IPTR)ent;
1560 return ERROR_NO_MORE_ENTRIES;
1564 static LONG rename_object(struct rambase *rambase,
1565 struct filehandle *filehandle,
1566 CONST_STRPTR namea, CONST_STRPTR nameb)
1568 struct dnode *file = filehandle->node;
1569 LONG error = 0, i;
1571 struct dnode *nodea = filehandle->node, *nodeb;
1572 STRPTR dira, dirb, pos = nameb;
1574 error = findname(rambase, &pos, &nodea);
1575 if (!error)
1576 return ERROR_OBJECT_EXISTS;
1578 error = findname(rambase, &namea, &file);
1579 if (error)
1580 return error;
1582 if ((struct dnode *)file->volume == file)
1583 return ERROR_OBJECT_WRONG_TYPE;
1585 if (file->usecount != 0)
1586 return ERROR_OBJECT_IN_USE;
1588 dira = Strdup(rambase, namea);
1589 dirb = Strdup(rambase, nameb);
1591 pos = strrchr(dira, '/');
1592 if (pos)
1594 *pos = '\0';
1595 namea = ++pos;
1597 else
1598 *dira = '\0';
1600 pos = strrchr(dirb, '/');
1601 if (pos)
1603 *pos = '\0';
1604 nameb = ++pos;
1606 else
1607 *dirb = '\0';
1609 D(bug("[Ram] rename (%s,%s)=>(%s,%s)\n", dira, namea, dirb, nameb));
1611 if (*dira == '\0' && *dirb == '\0')
1613 Strfree(rambase, file->name);
1614 file->name = Strdup(rambase, nameb);
1616 else
1618 nodea = filehandle->node;
1619 error = findname(rambase, &dira, &nodea);
1620 if (error)
1621 goto cleanup;
1623 nodeb = filehandle->node;
1624 error = findname(rambase, &dirb, &nodeb);
1625 if (error)
1626 goto cleanup;
1628 if (nodeb != nodea)
1630 Remove((struct Node *)file);
1631 AddTail((struct List *)&nodeb->list, (struct Node *)file);
1634 Strfree(rambase, file->name);
1635 file->name = Strdup(rambase, nameb);
1638 DateStamp(&file->date);
1640 switch (file->type)
1642 case ST_FILE:
1643 Notify_fileChange(rambase, NOTIFY_Delete, (struct fnode *)file);
1644 Notify_fileChange(rambase, NOTIFY_Add, (struct fnode *)file);
1645 break;
1646 case ST_USERDIR:
1647 default:
1648 Notify_directoryChange(rambase, NOTIFY_Delete, file);
1649 Notify_directoryChange(rambase, NOTIFY_Add, file);
1650 break;
1653 cleanup:
1654 Strfree(rambase, dirb);
1655 Strfree(rambase, dira);
1657 return error;
1660 static LONG delete_object(struct rambase *rambase,
1661 struct filehandle *filehandle, CONST_STRPTR name)
1663 struct dnode *file = filehandle->node;
1664 LONG error;
1666 error = findname(rambase, &name, &file);
1668 if (error)
1670 return error;
1673 if ((struct dnode *)file->volume == file)
1675 return ERROR_OBJECT_WRONG_TYPE;
1678 if (file->usecount != 0)
1680 return ERROR_OBJECT_IN_USE;
1683 if (file->protect & FIBF_DELETE)
1685 return ERROR_DELETE_PROTECTED;
1688 if (file->type == ST_USERDIR && file->list.mlh_Head->mln_Succ != NULL)
1690 return ERROR_DIRECTORY_NOT_EMPTY;
1693 delete(rambase, (struct fnode *)file);
1695 return 0;
1699 static int GM_UNIQUENAME(Close)
1701 LIBBASETYPEPTR rambase,
1702 struct IOFileSys *iofs
1705 struct cnode *dev;
1706 struct vnode *vol;
1707 struct dnode *dir;
1708 struct fnode *file;
1710 struct filehandle *handle;
1712 handle = (struct filehandle *)iofs->IOFS.io_Unit;
1713 dev = (struct cnode *)handle->node;
1714 vol = dev->volume;
1716 if (dev->type != ST_LINKDIR || dev->self != dev)
1718 iofs->io_DosError = ERROR_OBJECT_WRONG_TYPE;
1720 return 0;
1723 if (vol->volcount)
1725 iofs->io_DosError = ERROR_OBJECT_IN_USE;
1727 return 0;
1730 free_lock(rambase, handle);
1731 RemDosEntry(vol->doslist);
1732 FreeDosEntry(vol->doslist);
1734 while (vol->list.mlh_Head->mln_Succ != NULL)
1736 dir = (struct dnode *)vol->list.mlh_Head;
1738 if (dir->type == ST_USERDIR)
1740 while((file = (struct fnode *)RemHead((struct List *)&dir->list)) != NULL)
1742 AddTail((struct List *)&vol->list, (struct Node *)dir);
1746 delete(rambase, (struct fnode *)dir);
1749 Strfree(rambase, vol->name);
1750 FreeMem(vol, sizeof(struct vnode));
1752 Strfree(rambase, dev->name);
1753 FreeMem(dev, sizeof(struct cnode));
1755 iofs->io_DosError = 0;
1757 return TRUE;
1761 void processFSM(struct rambase *rambase);
1764 static void deventry(struct rambase *rambase)
1766 ULONG notifyMask;
1767 ULONG fileOpMask;
1768 struct Message *msg;
1771 Init device port. AllocSignal() cannot fail because this is a
1772 freshly created task with all signal bits still free.
1775 rambase->port->mp_SigBit = AllocSignal(-1);
1776 rambase->port->mp_Flags = PA_SIGNAL;
1778 /* Check if there are pending messages that we missed */
1779 if ((msg = GetMsg(rambase->port))) PutMsg(rambase->port, msg);
1781 Notify_initialize(rambase);
1783 notifyMask = 1 << rambase->notifyPort->mp_SigBit;
1785 fileOpMask = 1 << rambase->port->mp_SigBit;
1787 while (TRUE)
1789 ULONG flags;
1791 flags = Wait(fileOpMask | notifyMask);
1793 if (flags & notifyMask)
1795 struct NotifyMessage *nMessage;
1797 D(kprintf("Got replied notify message\n"));
1799 while ((nMessage = (struct NotifyMessage *)GetMsg(rambase->notifyPort)) != NULL)
1801 nMessage->nm_NReq->nr_Flags &= ~NRF_NOT_REPLIED;
1802 FreeVec(nMessage);
1806 if (flags & fileOpMask)
1808 processFSM(rambase);
1814 void processFSM(struct rambase *rambase)
1816 struct IOFileSys *iofs;
1817 struct dnode *dir;
1819 LONG error = 0;
1821 /* Get and process the messages. */
1822 while ((iofs = (struct IOFileSys *)GetMsg(rambase->port)) != NULL)
1824 D(bug("Ram.handler initialized %u\n", iofs->IOFS.io_Command));
1826 switch (iofs->IOFS.io_Command)
1828 case FSA_OPEN:
1830 get handle on a file or directory
1831 Unit *current; current directory / new handle on return
1832 STRPTR name; file- or directoryname
1833 LONG mode; open mode
1836 error = open_(rambase,
1837 (struct filehandle **)&iofs->IOFS.io_Unit,
1838 iofs->io_Union.io_OPEN.io_Filename,
1839 iofs->io_Union.io_OPEN.io_FileMode);
1840 break;
1842 case FSA_OPEN_FILE:
1844 open a file or create a new one
1845 Unit *current; current directory / new handle on return
1846 STRPTR name; file- or directoryname
1847 LONG mode; open mode
1848 LONG protect; protection flags if a new file is created
1851 error = open_file(rambase,
1852 (struct filehandle **)&iofs->IOFS.io_Unit,
1853 iofs->io_Union.io_OPEN_FILE.io_Filename,
1854 iofs->io_Union.io_OPEN_FILE.io_FileMode,
1855 iofs->io_Union.io_OPEN_FILE.io_Protection);
1856 break;
1858 case FSA_READ:
1860 read a number of bytes from a file
1861 Unit *current; filehandle
1862 APTR buffer; data
1863 LONG numbytes; number of bytes to read /
1864 number of bytes read on return,
1865 0 if there are no more bytes in the file
1867 error = read(rambase,
1868 (struct filehandle *)iofs->IOFS.io_Unit,
1869 iofs->io_Union.io_READ.io_Buffer,
1870 &iofs->io_Union.io_READ.io_Length);
1871 break;
1873 case FSA_WRITE:
1875 write a number of bytes to a file
1876 Unit *current; filehandle
1877 APTR buffer; data
1878 LONG numbytes; number of bytes to write /
1879 number of bytes written on return
1881 error = write(rambase,
1882 (struct filehandle *)iofs->IOFS.io_Unit,
1883 iofs->io_Union.io_WRITE.io_Buffer,
1884 &iofs->io_Union.io_WRITE.io_Length);
1885 break;
1887 case FSA_SEEK:
1889 set / read position in file
1890 Unit *current; filehandle
1891 LONG posh;
1892 LONG posl; relative position /
1893 old position on return
1894 LONG mode; one of OFFSET_BEGINNING, OFFSET_CURRENT,
1895 OFFSET_END
1897 error = seek(rambase,
1898 (struct filehandle *)iofs->IOFS.io_Unit,
1899 &iofs->io_Union.io_SEEK.io_Offset,
1900 iofs->io_Union.io_SEEK.io_SeekMode);
1901 break;
1903 case FSA_CLOSE:
1905 /* Get rid of a handle
1906 Unit *current; filehandle */
1908 struct filehandle *handle =
1909 (struct filehandle *)iofs->IOFS.io_Unit;
1911 Notify_fileChange(rambase, NOTIFY_Close,
1912 (struct fnode *)handle->node);
1913 error = free_lock(rambase, handle);
1914 break;
1917 case FSA_EXAMINE:
1919 Get information about the current object
1920 Unit *current; current object
1921 struct ExAllData *ead; buffer to be filled
1922 ULONG size; size of the buffer
1923 ULONG type; type of information to get
1924 iofs->io_DirPos; leave current position so
1925 ExNext() knows where to find
1926 next object
1928 error = examine((struct fnode *)((struct filehandle *)iofs->IOFS.io_Unit)->node,
1929 iofs->io_Union.io_EXAMINE.io_ead,
1930 iofs->io_Union.io_EXAMINE.io_Size,
1931 iofs->io_Union.io_EXAMINE.io_Mode,
1932 &(iofs->io_DirPos));
1933 break;
1935 case FSA_EXAMINE_NEXT:
1937 Get information about the next object
1938 Unit *current; current object
1939 struct FileInfoBlock *fib;
1941 error = examine_next(rambase,
1942 (struct filehandle *)iofs->IOFS.io_Unit,
1943 iofs->io_Union.io_EXAMINE_NEXT.io_fib);
1944 break;
1946 case FSA_EXAMINE_ALL:
1948 Read the current directory
1949 Unit *current; current directory
1950 struct ExAllData *ead; buffer to be filled
1951 ULONG size; size of the buffer
1952 ULONG type; type of information to get
1954 error = examine_all((struct filehandle *)iofs->IOFS.io_Unit,
1955 iofs->io_Union.io_EXAMINE_ALL.io_ead,
1956 iofs->io_Union.io_EXAMINE_ALL.io_eac,
1957 iofs->io_Union.io_EXAMINE_ALL.io_Size,
1958 iofs->io_Union.io_EXAMINE_ALL.io_Mode);
1959 break;
1961 case FSA_CREATE_DIR:
1963 Build lock and open a new directory
1964 Unit *current; current directory
1965 STRPTR name; name of the dir to create
1966 LONG protect; Protection flags for the new dir
1969 // kprintf("Creating directory %s\n",
1970 // iofs->io_Union.io_CREATE_DIR.io_Filename);
1973 error = create_dir(rambase,
1974 (struct filehandle **)&iofs->IOFS.io_Unit,
1975 iofs->io_Union.io_CREATE_DIR.io_Filename,
1976 iofs->io_Union.io_CREATE_DIR.io_Protection);
1977 break;
1979 case FSA_DELETE_OBJECT:
1981 Delete file or directory
1982 Unit *current; current directory
1983 STRPTR name; filename
1985 error = delete_object(rambase,
1986 (struct filehandle *)iofs->IOFS.io_Unit,
1987 iofs->io_Union.io_DELETE_OBJECT.io_Filename);
1988 break;
1990 case FSA_SET_PROTECT:
1993 Set protection bits for a certain file or directory.
1994 Unit *current; current directory
1995 STRPTR name; filename
1996 ULONG protect; new protection bits
1999 CONST_STRPTR name = iofs->io_Union.io_SET_PROTECT.io_Filename;
2001 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
2002 error = findname(rambase, &name, &dir);
2004 if (!error)
2006 dir->protect = iofs->io_Union.io_SET_PROTECT.io_Protection;
2009 break;
2012 case FSA_SET_OWNER:
2015 Set owner and group of the file or directory
2016 Unit *current; current directory
2017 STRPTR name; filename
2018 ULONG UID;
2019 ULONG GID;
2022 CONST_STRPTR name = iofs->io_Union.io_SET_OWNER.io_Filename;
2024 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
2025 error = findname(rambase, &name, &dir);
2027 if(!error)
2031 break;
2034 case FSA_SET_DATE:
2037 Set creation date of the file
2038 Unit *current; current directory
2039 STRPTR name; filename
2040 ULONG days;
2041 ULONG mins;
2042 ULONG ticks; timestamp
2045 CONST_STRPTR name = iofs->io_Union.io_SET_DATE.io_Filename;
2047 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
2048 error = findname(rambase, &name, &dir);
2050 if(!error)
2052 dir->date = iofs->io_Union.io_SET_DATE.io_Date;
2055 break;
2058 case FSA_SET_COMMENT:
2061 Set a comment for the file or directory;
2062 Unit *current; current directory
2063 STRPTR name; filename
2064 STRPTR comment; NUL terminated C string or NULL.
2067 CONST_STRPTR name = iofs->io_Union.io_SET_COMMENT.io_Filename;
2069 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
2070 error = findname(rambase, &name, &dir);
2072 if (!error)
2074 if (iofs->io_Union.io_SET_COMMENT.io_Comment)
2076 STRPTR s = Strdup(rambase,
2077 iofs->io_Union.io_SET_COMMENT.io_Comment);
2078 if (s != NULL)
2080 Strfree(rambase, dir->comment);
2081 dir->comment = s;
2083 else
2085 error = ERROR_NO_FREE_STORE;
2088 else
2090 Strfree(rambase, dir->comment);
2091 dir->comment = NULL;
2095 break;
2098 case FSA_SET_FILE_SIZE:
2100 Set a new size for the file.
2101 Unit *file; filehandle
2102 LONG offh;
2103 LONG offl; offset to current position/
2104 new size on return
2105 LONG mode; relative to what (see Seek)
2107 error = set_file_size(rambase,
2108 (struct filehandle *)iofs->IOFS.io_Unit,
2109 &iofs->io_Union.io_SET_FILE_SIZE.io_Offset,
2110 iofs->io_Union.io_SET_FILE_SIZE.io_SeekMode);
2111 break;
2113 case FSA_IS_FILESYSTEM:
2114 iofs->io_Union.io_IS_FILESYSTEM.io_IsFilesystem = TRUE;
2115 error = 0;
2116 break;
2118 case FSA_DISK_INFO:
2120 struct InfoData *id = iofs->io_Union.io_INFO.io_Info;
2122 id->id_NumSoftErrors = 0;
2123 id->id_UnitNumber = 0;
2124 id->id_DiskState = ID_VALIDATED;
2125 id->id_NumBlocks = AvailMem(MEMF_TOTAL | MEMF_PUBLIC)/BLOCKSIZE;
2126 id->id_NumBlocksUsed = id->id_NumBlocks - AvailMem(MEMF_PUBLIC)/BLOCKSIZE;
2127 id->id_BytesPerBlock = BLOCKSIZE;
2128 id->id_DiskType = ID_DOS_DISK;
2129 id->id_VolumeNode = NULL; /* What is this? */
2130 id->id_InUse = (LONG)TRUE;
2132 error = 0;
2135 break;
2138 case FSA_ADD_NOTIFY:
2140 BOOL ok;
2141 struct NotifyRequest *nr =
2142 iofs->io_Union.io_NOTIFY.io_NotificationRequest;
2143 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
2145 D(kprintf("Adding notification for entity (nr = %s)\n",
2146 nr->nr_FullName));
2148 ok = Notify_addNotification(rambase, fh->node, nr);
2150 if (!ok)
2152 error = ERROR_NO_FREE_STORE;
2155 D(kprintf("Notification now added!\n"));
2157 break;
2159 case FSA_REMOVE_NOTIFY:
2161 struct NotifyRequest *nr =
2162 iofs->io_Union.io_NOTIFY.io_NotificationRequest;
2164 Notify_removeNotification(rambase, nr);
2166 break;
2168 case FSA_RENAME:
2169 error = rename_object(rambase,
2170 (struct filehandle *)iofs->IOFS.io_Unit,
2171 iofs->io_Union.io_RENAME.io_Filename,
2172 iofs->io_Union.io_RENAME.io_NewName);
2173 break;
2175 case FSA_IS_INTERACTIVE:
2176 iofs->io_Union.io_IS_INTERACTIVE.io_IsInteractive = 0;
2177 break;
2179 default:
2180 error = ERROR_NOT_IMPLEMENTED;
2182 D(kprintf("ram_handler, unimplemented FSA: %ld\n", iofs->IOFS.io_Command));
2183 break;
2185 FSA_FILE_MODE
2186 Change or read the mode of a single filehandle
2187 Unit *current; filehandle to change
2188 ULONG newmode; new mode/old mode on return
2189 ULONG mask; bits affected
2191 FSA_MOUNT_MODE
2192 Change or read the mode of the filesystem
2193 Unit *current; filesystem to change
2194 ULONG newmode; new mode/old mode on return
2195 ULONG mask; bits affected
2196 STRPTR passwd; password for MMF_LOCKED
2198 FSA_MAKE_HARDLINK
2199 Create a hard link on a file, directory or soft link
2200 Unit *current; current directory
2201 STRPTR name; softlink name
2202 Unit *target; target handle
2204 FSA_MAKE_SOFTLINK
2205 Create a soft link to another object
2206 Unit *current; current directory
2207 STRPTR name; softlink name
2208 STRPTR target; target name
2210 FSA_READ_LINK
2211 FSA_SERIALIZE_DISK
2212 FSA_WAIT_CHAR
2213 FSA_INFO
2214 FSA_TIMER
2215 FSA_DISK_TYPE
2216 FSA_DISK_CHANGE
2217 FSA_SAME_LOCK
2218 FSA_CHANGE_SIGNAL
2219 FSA_FORMAT
2220 FSA_EXAMINE_ALL
2221 FSA_EXAMINE_FH
2222 FSA_EXAMINE_ALL_END
2227 iofs->io_DosError = error;
2228 ReplyMsg(&iofs->IOFS.io_Message);
2231 #if 0
2232 if (rambase->iofs != NULL)
2234 iofs = rambase->iofs;
2236 if (iofs->IOFS.io_Message.mn_Node.ln_Type == NT_MESSAGE)
2238 abort_notify(rambase, iofs);
2239 iofs->io_DosError = ERROR_BREAK;
2240 rambase->iofs = NULL;
2241 ReplyMsg(&iofs->IOFS.io_Message);
2243 else
2245 rambase->iofs = NULL;
2246 Signal(1, 0);
2249 #endif
2256 /***************************************************************************
2257 ****************************************************************************/
2259 /** Notification stuff **/
2262 * Immediate notification:
2264 * ACTION_RENAME_OBJECT
2265 * ACTION_RENAME_DISK
2266 * ACTION_CREATE_DIR
2267 * ACTION_DELETE_OBJECT
2268 * ACTION_SET_DATE
2271 * Session semantics notification:
2273 * ACTION_WRITE
2274 * ACTION_FINDUPDATE
2275 * ACTION_FINDOUTPUT
2276 * ACTION_SET_FILE_SIZE
2279 * For ram-handler, the only FSA actions currently implemented/affected are
2280 * FSA_WRITE, FSA_CREATE_DIR, FSA_DELETE (and implicitly FSA_OPEN, FSA_CLOSE)
2285 BOOL Notify_initialize(struct rambase *rambase)
2287 rambase->notifyPort = CreateMsgPort();
2289 if (rambase->notifyPort == NULL)
2291 return FALSE;
2294 return TRUE;
2298 void Notify_fileChange(struct rambase *rambase, NType type, struct fnode *file)
2300 switch (type)
2302 case NOTIFY_Open:
2303 break;
2305 case NOTIFY_Write:
2306 D(bug("Setting write flag!\n"));
2307 file->flags |= FILEFLAGS_Changed;
2308 break;
2310 case NOTIFY_Close:
2311 /* Only notify in case the file was changed */
2312 if (file->flags & FILEFLAGS_Changed)
2314 D(bug("Notification on close (file was changed).\n"));
2315 file->flags &= ~FILEFLAGS_Changed;
2316 Notify_notifyTasks(rambase, &file->receivers);
2318 break;
2320 case NOTIFY_Add:
2322 STRPTR fullName;
2323 struct List *receivers;
2325 fullName = getName(rambase, (struct dnode *)file);
2327 D(kprintf("Found full name: %s\n", fullName));
2329 receivers = HashTable_find(rambase, rambase->notifications,
2330 fullName);
2332 if (receivers != NULL)
2334 D(kprintf("Found notification for created file!\n"));
2336 while (!IsListEmpty(receivers))
2338 AddHead((struct List *)&file->receivers,
2339 RemHead(receivers));
2343 HashTable_remove(rambase, rambase->notifications, fullName);
2345 D(bug("Notifying file receivers!\n"));
2346 Notify_notifyTasks(rambase, &file->receivers);
2348 FreeVec(fullName);
2350 break;
2352 case NOTIFY_Delete:
2353 /* It's the same thing as for directories... */
2354 Notify_directoryChange(rambase, NOTIFY_Delete, (struct dnode *)file);
2355 break;
2357 default:
2358 kprintf("Error\n");
2359 break;
2364 void Notify_directoryChange(struct rambase *rambase, NType type,
2365 struct dnode *dir)
2367 switch (type)
2369 case NOTIFY_Open:
2371 STRPTR fullName;
2373 fullName = getName(rambase, dir);
2375 /* TODO: HashTable_apply(ht, fullName, dir); */
2377 FreeVec(fullName);
2379 break;
2381 case NOTIFY_Add:
2383 STRPTR fullName;
2384 struct List *receivers;
2386 fullName = getName(rambase, dir);
2388 D(kprintf("Found full name: %s\n", fullName));
2390 receivers = HashTable_find(rambase, rambase->notifications,
2391 fullName);
2393 if (receivers != NULL)
2395 D(kprintf("Found notification for created directory!\n"));
2397 while (!IsListEmpty(receivers))
2399 AddHead((struct List *)&dir->receivers,
2400 RemHead(receivers));
2404 HashTable_remove(rambase, rambase->notifications, fullName);
2406 FreeVec(fullName);
2409 D(kprintf("Notifying dir receivers!\n"));
2410 Notify_notifyTasks(rambase, &dir->receivers);
2411 break;
2413 case NOTIFY_Delete:
2415 /* As we have deleted a file, we must move the requests for
2416 this file to the hash table */
2417 struct List *receivers = (struct List *)&dir->receivers;
2419 Notify_notifyTasks(rambase, &dir->receivers);
2421 /* Move the Notification request to the hash table as we're going
2422 to delete this directory */
2423 while (!IsListEmpty(receivers))
2425 struct Receiver *rr = (struct Receiver *)RemHead(receivers);
2427 HashTable_insert(rambase, rambase->notifications,
2428 rr->nr->nr_FullName, rr);
2432 break;
2434 default:
2435 kprintf("Error\n");
2436 break;
2439 // kprintf("Returning from Notify_dirChange()\n");
2443 /* TODO: Implement support for NRF_WAIT_REPLY */
2444 void Notify_notifyTasks(struct rambase *rambase, struct MinList *notifications)
2446 struct Receiver *rr;
2448 // kprintf("Inside notifytasks, not = %p\n", notifications);
2450 ForeachNode((struct List *)notifications, rr)
2452 struct NotifyRequest *nr = rr->nr;
2454 if (nr->nr_Flags & NRF_SEND_MESSAGE &&
2455 !(nr->nr_Flags & NRF_WAIT_REPLY && nr->nr_Flags & NRF_NOT_REPLIED))
2457 struct NotifyMessage *nm = AllocVec(sizeof(struct NotifyMessage),
2458 MEMF_PUBLIC | MEMF_CLEAR);
2460 if (nm == NULL)
2462 return;
2465 nm->nm_ExecMessage.mn_ReplyPort = rambase->notifyPort;
2466 nm->nm_ExecMessage.mn_Length = sizeof(struct NotifyMessage);
2467 nm->nm_NReq = nr;
2468 nr->nr_Flags |= NRF_NOT_REPLIED;
2470 PutMsg(nr->nr_stuff.nr_Msg.nr_Port, &nm->nm_ExecMessage);
2472 else if (nr->nr_Flags & NRF_SEND_SIGNAL)
2474 Signal(nr->nr_stuff.nr_Signal.nr_Task,
2475 1 << nr->nr_stuff.nr_Signal.nr_SignalNum);
2480 /* also defined in rom/dos/filesystem_support.c */
2481 STRPTR RamStripVolume(STRPTR name)
2483 STRPTR path = strchr(name, ':');
2484 if (path != NULL)
2485 path++;
2486 else
2487 path = name;
2488 return path;
2491 BOOL Notify_addNotification(struct rambase *rambase, struct dnode *dn,
2492 struct NotifyRequest *nr)
2494 struct dnode *dnTemp = dn;
2495 HashTable *ht = rambase->notifications;
2496 STRPTR name = nr->nr_FullName;
2497 CONST_STRPTR tname = RamStripVolume(name);
2499 /* First: Check if the file is opened */
2500 D(bug("Checking existence of %s\n", tname));
2502 if (findname(rambase, &tname, &dnTemp) == 0)
2504 /* This file was already opened (or at least known by the file
2505 system) */
2507 struct Receiver *rr = AllocVec(sizeof(struct Receiver), MEMF_CLEAR);
2509 if (rr == NULL)
2511 return FALSE;
2514 rr->nr = nr;
2516 if (nr->nr_Flags & NRF_NOTIFY_INITIAL)
2518 struct MinList tempList;
2520 /* Create a temporary list on the stack and add the receiver to
2521 it. Then forget about this and add the node to the receiver
2522 list (below this block). */
2523 NewList((struct List *)&tempList);
2524 AddHead((struct List *)&tempList, &rr->node);
2525 Notify_notifyTasks(rambase, &tempList);
2528 /* Add the receiver node to the file's/directory's list of receivers */
2529 AddTail((struct List *)&dnTemp->receivers, &rr->node);
2531 D(bug("Notification added to node: %s\n", name));
2533 return TRUE;
2535 else
2537 /* This file is not opened */
2539 struct Receiver *rr = AllocVec(sizeof(struct Receiver), MEMF_CLEAR);
2541 if (rr == NULL)
2543 return FALSE;
2546 rr->nr = nr;
2548 HashTable_insert(rambase, ht, name, rr);
2550 return TRUE;
2555 void Notify_removeNotification(struct rambase *rambase,
2556 struct NotifyRequest *nr)
2558 struct dnode *dn = (struct dnode *)rambase->root;
2559 struct Receiver *rr, *rrTemp;
2560 STRPTR name = nr->nr_FullName;
2561 CONST_STRPTR tname = RamStripVolume(name);
2562 struct List *receivers;
2563 BOOL fromTable = FALSE;
2565 if (findname(rambase, &tname, &dn) == 0)
2567 receivers = (struct List *)&dn->receivers;
2569 else
2571 /* This was a request for an entity that doesn't exist yet */
2572 receivers = HashTable_find(rambase, rambase->notifications, name);
2574 if (receivers == NULL)
2576 D(bug("Ram: This should not happen! -- buggy application...\n"));
2577 return;
2580 fromTable = TRUE;
2583 ForeachNodeSafe(&receivers, rr, rrTemp)
2585 if (rr->nr == nr)
2587 Remove((struct Node *)rr);
2588 FreeVec(rr);
2589 break;
2593 if (fromTable)
2595 /* If we removed a request for a file that doesn't exist yet --
2596 if this was the only notification request for that file, remove
2597 also the hash entry. */
2598 if (IsListEmpty((struct List *)receivers))
2600 HashTable_remove(rambase, rambase->notifications, name);
2605 static STRPTR getName(struct rambase *rambase, struct dnode *dn)
2607 struct dnode *dnTemp = dn;
2609 ULONG length;
2610 STRPTR fullName;
2611 CONST_STRPTR slash = "/";
2612 CONST_STRPTR nextSlash = slash;
2613 ULONG partLen;
2615 /* First, calculate the size of the complete filename */
2616 length = strlen(dn->name) + 2; /* Add trailing 0 byte and possible '/' */
2618 while (findname(rambase, &slash, &dnTemp) == 0)
2620 slash = nextSlash;
2621 length += 1 + strlen(dnTemp->name); /* Add '/' byte */
2624 /* The MEMF_CLEAR is necessary for the while loop below to work */
2625 fullName = AllocVec(length, MEMF_PUBLIC | MEMF_CLEAR);
2627 if (fullName == NULL)
2629 return NULL;
2632 dnTemp = dn;
2633 fullName += length - 1;
2635 fullName -= strlen(dn->name) + 1;
2636 strcpy(fullName, dn->name);
2638 slash = "/";
2639 nextSlash = slash;
2640 while (findname(rambase, &slash, &dnTemp) != ERROR_OBJECT_NOT_FOUND)
2642 slash = nextSlash;
2643 partLen = strlen(dnTemp->name);
2645 fullName -= partLen + 1;
2646 strcpy(fullName, dnTemp->name);
2648 if ((struct vnode *)dnTemp == dnTemp->volume)
2649 fullName[partLen] = ':'; /* Root of Ram Disk */
2650 else
2651 fullName[partLen] = '/'; /* Replace 0 with '/' */
2654 return fullName;
2657 ADD2INITLIB(GM_UNIQUENAME(Init),0)
2658 ADD2OPENDEV(GM_UNIQUENAME(Open),0)
2659 ADD2CLOSEDEV(GM_UNIQUENAME(Close),0)
2660 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge),0)