more rendering corrections
[AROS.git] / workbench / devs / ram_handler / ram_handler.c
blobba516d0b8e711a86df7e767e4893fc67440bb1db
1 /*
2 Copyright © 1995-2008, 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/battclock.h>
22 #include <proto/dos.h>
23 #include <resources/battclock.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>
38 #include "HashTable.h"
40 static void deventry();
42 #include LC_LIBDEFS_FILE
44 #define NRF_NOT_REPLIED NRF_MAGIC
47 /* Device node */
48 struct cnode
50 struct MinNode node;
51 LONG type; /* ST_LINKDIR */
52 STRPTR name; /* Link's name */
53 struct cnode *self; /* Pointer to top of structure */
54 struct hnode *link; /* NULL */
55 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
56 ULONG protect; /* 0 */
57 STRPTR comment; /* NULL */
58 struct vnode *volume; /* Pointer to volume */
59 struct DosList *doslist; /* Pointer to doslist entry */
62 /* Volume node */
63 struct vnode
65 struct MinNode node;
66 LONG type; /* ST_USERDIR */
67 STRPTR name; /* Directory name */
68 struct vnode *self; /* Points to top of structure */
69 struct hnode *link; /* This one is linked to me */
70 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
71 ULONG protect; /* 0 */
72 STRPTR comment; /* NULL */
73 struct MinList receivers;
74 struct DateStamp date;
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 STRPTR 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 STRPTR comment; /* Some comment */
91 struct MinList receivers;
92 struct DateStamp date;
93 struct MinList list; /* Contents of directory */
96 /* File node */
97 struct fnode
99 struct MinNode node;
100 LONG type; /* ST_FILE */
101 STRPTR name; /* Filename */
102 struct vnode *volume; /* Volume's root directory */
103 struct hnode *link; /* This one is linked to me */
104 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
105 ULONG protect; /* protection bits */
106 STRPTR comment; /* Some file comment */
107 struct MinList receivers;
108 struct DateStamp date;
109 ULONG flags;
110 LONG size; /* Filesize */
111 UBYTE *blocks[16]; /* Upto 0x1000 bytes */
112 UBYTE **iblocks[4]; /* Upto 0x41000 bytes */
113 UBYTE ***i2block; /* Upto 0x1041000 bytes */
114 UBYTE ****i3block; /* Upto 0x101041000 bytes */
117 /* Softlink node */
118 struct snode
120 struct MinNode node;
121 LONG type; /* ST_SOFTLINK */
122 STRPTR name; /* Link's name */
123 struct vnode *volume; /* Volume's root directory */
124 struct hnode *link; /* This one is hardlinked to me */
125 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
126 ULONG protect; /* protection bits */
127 STRPTR comment; /* Some file comment */
128 char *contents; /* Contents of soft link */
131 /* Hardlink node */
132 struct hnode
134 struct MinNode node;
135 LONG type; /* ST_LINKDIR */
136 STRPTR name; /* Link's name */
137 struct vnode *volume; /* Volume's root directory */
138 struct hnode *link; /* This one is hardlinked to me */
139 LONG usecount; /* >0 usecount locked:+(~0ul/2+1) */
140 ULONG protect; /* protection bits */
141 STRPTR comment; /* Some file comment */
142 struct hnode *orig; /* original object */
145 /*****************************************************************************/
147 #define FILEFLAGS_Changed 1
149 static STRPTR getName(struct rambase *rambase, struct dnode *dn);
151 typedef enum
153 NOTIFY_Add,
154 NOTIFY_Delete,
155 NOTIFY_Write,
156 NOTIFY_Close,
157 NOTIFY_Open,
158 } NType;
160 void Notify_notifyTasks(struct rambase *rambase,
161 struct MinList *notifications);
163 BOOL Notify_initialize(struct rambase *rambase);
164 void Notify_fileChange(struct rambase *rambase, NType type,
165 struct fnode *file);
166 void Notify_directoryChange(struct rambase *rambase, NType type,
167 struct dnode *dir);
170 BOOL Notify_addNotification(struct rambase *rambase, struct dnode *dn,
171 struct NotifyRequest *nr);
172 void Notify_removeNotification(struct rambase *rambase,
173 struct NotifyRequest *nr);
175 /****************************************************************************/
178 #define BLOCKSIZE 256
179 #define PBLOCKSIZE (256*sizeof(UBYTE *))
181 struct filehandle
183 struct dnode *node;
184 IPTR position;
187 static int OpenDev(LIBBASETYPEPTR rambase, struct IOFileSys *iofs);
189 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR rambase)
191 /* This function is single-threaded by exec by calling Forbid. */
193 struct MsgPort *port;
194 struct Task *task;
195 struct SignalSemaphore *semaphore;
196 APTR stack;
198 port = (struct MsgPort *)AllocMem(sizeof(struct MsgPort),
199 MEMF_PUBLIC | MEMF_CLEAR
201 if (port != NULL)
203 rambase->port = port;
204 NewList(&port->mp_MsgList);
205 port->mp_Node.ln_Type = NT_MSGPORT;
206 port->mp_SigBit = SIGB_SINGLE;
208 task = (struct Task *)AllocMem(sizeof(struct Task),
209 MEMF_PUBLIC | MEMF_CLEAR
212 if (task != NULL)
214 port->mp_SigTask = task;
215 port->mp_Flags = PA_IGNORE;
216 NewList(&task->tc_MemEntry);
217 task->tc_Node.ln_Type = NT_TASK;
218 task->tc_Node.ln_Name = "ram.handler task";
220 stack = AllocMem(AROS_STACKSIZE, MEMF_PUBLIC);
222 if (stack != NULL)
224 struct TagItem tasktags[] =
226 {TASKTAG_ARG1, (IPTR)rambase},
227 {TAG_DONE }
230 task->tc_SPLower = stack;
231 task->tc_SPUpper = (BYTE *)stack + AROS_STACKSIZE;
232 #if AROS_STACK_GROWS_DOWNWARDS
233 task->tc_SPReg = (BYTE *)task->tc_SPUpper - SP_OFFSET;
234 #else
235 task->tc_SPReg = (BYTE *)task->tc_SPLower + SP_OFFSET;
236 #endif
238 semaphore = (struct SignalSemaphore *)AllocMem(sizeof(struct SignalSemaphore),
239 MEMF_PUBLIC | MEMF_CLEAR
242 if (semaphore != NULL)
244 rambase->sigsem = semaphore;
245 InitSemaphore(semaphore);
248 * Modules compiled with noexpunge always have seglist == NULL
249 * The seglist is not kept as it is not needed because the module never
250 * can be expunged
251 if (rambase->seglist==NULL) /* Are we a ROM module? * /
254 struct DeviceNode *dn;
255 /* Install RAM: handler into device list
257 * KLUDGE: ram.handler should create only one device node, depending on
258 * the startup packet it gets. The mountlists for RAM: should be into dos.library bootstrap
259 * routines.
262 if((dn = AllocMem(sizeof (struct DeviceNode) + 4 + 3 + 2, MEMF_CLEAR|MEMF_PUBLIC)))
264 struct IOFileSys dummyiofs;
266 if (OpenDev(rambase, &dummyiofs))
268 BSTR s = MKBADDR(((IPTR)dn + sizeof(struct DeviceNode) + 3) & ~3);
270 ((struct Library *)rambase)->lib_OpenCnt++;
272 AROS_BSTR_putchar(s, 0, 'R');
273 AROS_BSTR_putchar(s, 1, 'A');
274 AROS_BSTR_putchar(s, 2, 'M');
275 AROS_BSTR_setstrlen(s, 3);
277 dn->dn_Type = DLT_DEVICE;
278 dn->dn_Ext.dn_AROS.dn_Unit = dummyiofs.IOFS.io_Unit;
279 dn->dn_Ext.dn_AROS.dn_Device = dummyiofs.IOFS.io_Device;
280 dn->dn_Handler = NULL;
281 dn->dn_Startup = NULL;
282 dn->dn_Name = s;
283 dn->dn_Ext.dn_AROS.dn_DevName = AROS_BSTR_ADDR(dn->dn_Name);
285 if (AddDosEntry((struct DosList *)dn))
286 if (NewAddTask(task, deventry, NULL, tasktags) != NULL)
287 return TRUE;
290 FreeMem(dn, sizeof (struct DeviceNode));
293 /* else
294 if (NewAddTask(task, deventry, NULL, tasktags) != NULL)
295 return TRUE;
297 FreeMem(semaphore, sizeof(struct SignalSemaphore));
300 FreeMem(stack, AROS_STACKSIZE);
303 FreeMem(task, sizeof(struct Task));
306 FreeMem(port, sizeof(struct MsgPort));
309 return FALSE;
313 /***************************************************************************/
315 void nullDelete(struct rambase *rambase, void *key, struct List *list)
317 // struct Receiver *rr;
318 // struct Node *tempNode;
320 // ForeachNodeSafe(list, rr, tempNode)
321 // {
322 // Remove(&rr->node);
323 // FreeVec(rr);
324 // }
326 FreeVec(key);
328 /* The list is part of the HashNode so we shouldn't free that */
332 ULONG stringHash(struct rambase *rambase, const void *key)
334 STRPTR str = (STRPTR)key;
335 ULONG val = 1;
337 while (*str != 0)
339 val *= ToLower(*str++);
340 val <<= 2;
343 return val;
346 static int
347 my_strcasecmp(struct rambase *rambase, const void *s1, const void *s2)
349 return strcasecmp(s1, s2);
352 /****************************************************************************/
355 STRPTR Strdup(struct rambase *rambase, CONST_STRPTR string)
357 CONST_STRPTR s2 = string;
358 STRPTR s3;
360 while(*s2++)
363 s3 = (STRPTR)AllocVec(s2 - string, MEMF_ANY);
365 if (s3 != NULL)
367 CopyMem(string, s3, s2 - string);
370 return s3;
374 void Strfree(struct rambase *rambase, STRPTR string)
376 FreeVec(string);
380 static int GM_UNIQUENAME(Open)
382 LIBBASETYPEPTR rambase,
383 struct IOFileSys *iofs,
384 ULONG unitnum,
385 ULONG flags
388 /* Mark Message as recently used. */
389 iofs->IOFS.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
391 return OpenDev(rambase, iofs);
394 static void GetCurrentDate(LIBBASETYPEPTR rambase, struct DateStamp *date)
396 APTR BattClockBase = NULL;
397 ULONG secs = 0;
399 DateStamp(date);
400 if (date->ds_Days != 0)
401 return;
403 BattClockBase = OpenResource(BATTCLOCKNAME);
404 if (BattClockBase)
405 secs = ReadBattClock();
407 date->ds_Days = secs / (60 * 60 * 24);
408 secs %= (60 * 60 * 24);
409 date->ds_Minute = secs / 60;
410 date->ds_Tick = 0;
413 static int OpenDev(LIBBASETYPEPTR rambase, struct IOFileSys *iofs)
415 struct filehandle *fhv, *fhc;
416 struct vnode *vol;
417 struct cnode *dev;
418 struct DeviceList *dlv;
420 iofs->IOFS.io_Error = ERROR_NO_FREE_STORE;
422 fhv = (struct filehandle*)AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
424 if (fhv != NULL)
426 fhc = (struct filehandle*)AllocMem(sizeof(struct filehandle),
427 MEMF_CLEAR);
429 if (fhc != NULL)
431 vol = (struct vnode *)AllocMem(sizeof(struct vnode), MEMF_CLEAR);
433 if (vol != NULL)
435 dev = (struct cnode *)AllocMem(sizeof(struct cnode),
436 MEMF_CLEAR);
437 GetCurrentDate(rambase, &vol->date);
439 if (dev != NULL)
441 vol->name = Strdup(rambase, "Ram Disk");
443 if (vol->name != NULL)
445 dlv = (struct DeviceList *)MakeDosEntry("Ram Disk",
446 DLT_VOLUME);
448 if (dlv != NULL)
450 vol->type = ST_USERDIR;
451 vol->self = vol;
452 vol->doslist = (struct DosList *)dlv;
453 vol->protect = 0UL;
454 NewList((struct List *)&vol->list);
455 NewList((struct List *)&vol->receivers);
456 fhv->node = (struct dnode *)vol;
457 dlv->dl_Ext.dl_AROS.dol_Unit = (struct Unit *)fhv;
458 dlv->dl_Ext.dl_AROS.dol_Device = &rambase->device;
459 dlv->dl_VolumeDate = vol->date;
460 dev->type = ST_LINKDIR;
461 dev->self = dev;
462 dev->volume=vol;
463 fhc->node = (struct dnode *)dev;
464 iofs->IOFS.io_Unit = (struct Unit *)fhc;
465 iofs->IOFS.io_Device = &rambase->device;
466 AddDosEntry((struct DosList *)dlv);
467 rambase->root = vol;
468 iofs->IOFS.io_Error = 0;
470 rambase->notifications =
471 HashTable_new(rambase, 100, stringHash,
472 my_strcasecmp, nullDelete);
474 return TRUE;
477 Strfree(rambase, vol->name);
480 FreeMem(dev, sizeof(struct cnode));
483 FreeMem(vol, sizeof(struct vnode));
486 FreeMem(fhc, sizeof(struct filehandle));
489 FreeMem(fhv, sizeof(struct filehandle));
492 iofs->IOFS.io_Error = IOERR_OPENFAIL;
494 return FALSE;
497 static int GM_UNIQUENAME(Expunge)(LIBBASETYPEPTR rambase)
500 This function is single-threaded by exec by calling Forbid.
501 Never break the Forbid() or strange things might happen.
504 /* Kill device task and free all resources */
505 RemTask(rambase->port->mp_SigTask);
506 FreeMem(rambase->sigsem, sizeof(struct SignalSemaphore));
507 FreeMem(((struct Task *)rambase->port->mp_SigTask)->tc_SPLower,
508 AROS_STACKSIZE);
509 FreeMem(rambase->port->mp_SigTask, sizeof(struct Task));
510 FreeMem(rambase->port, sizeof(struct MsgPort));
512 return TRUE;
516 AROS_LH1(void, beginio,
517 AROS_LHA(struct IOFileSys *, iofs, A1),
518 struct rambase *, rambase, 5, Ram)
520 AROS_LIBFUNC_INIT
522 /* WaitIO will look into this */
523 iofs->IOFS.io_Message.mn_Node.ln_Type = NT_MESSAGE;
525 /* Nothing is done quick */
526 iofs->IOFS.io_Flags &= ~IOF_QUICK;
528 /* So let the device task do it */
529 PutMsg(rambase->port, &iofs->IOFS.io_Message);
531 AROS_LIBFUNC_EXIT
535 AROS_LH1(LONG, abortio,
536 AROS_LHA(struct IOFileSys *, iofs, A1),
537 struct rambase *, rambase, 6, Ram)
539 AROS_LIBFUNC_INIT
540 return 0;
541 AROS_LIBFUNC_EXIT
545 static LONG getblock(struct rambase *rambase, struct fnode *file, LONG block,
546 int mode, UBYTE **result)
548 ULONG a, i;
549 UBYTE **p, **p2;
551 if (block < 0x10)
553 p = &file->blocks[block];
554 block= 0 ;
555 i = 0;
557 else if (block < 0x410)
559 block -= 0x10;
560 p = (UBYTE **)&file->iblocks[block/0x100];
561 block &= 0xff;
562 i = 1;
564 else if(block < 0x10410)
566 block -= 0x410;
567 p = (UBYTE **)&file->i2block;
568 i = 2;
570 else
572 block -= 0x10410;
573 p = (UBYTE **)&file->i3block;
574 i = 3;
577 switch (mode)
579 case -1:
580 p2 = (UBYTE **)*p;
582 if (!block)
584 *p = NULL;
587 p = p2;
589 while (i-- && p != NULL)
591 a = (block >> i*8) & 0xff;
592 p2 = (UBYTE **)p[a];
594 if (!(block & ((1 << i*8) - 1)))
596 p[a] = NULL;
598 if (!a)
600 FreeMem(p, PBLOCKSIZE);
604 p = p2;
607 if (p != NULL)
609 FreeMem(p, BLOCKSIZE);
612 break;
614 case 0:
615 p = (UBYTE **)*p;
617 while (i-- && p != NULL)
619 p = ((UBYTE ***)p)[(block >> i*8) & 0xff];
622 *result = (UBYTE *)p;
623 break;
625 case 1:
626 while (i--)
628 if (*p == NULL)
630 *p= AllocMem(PBLOCKSIZE, MEMF_CLEAR);
632 if (*p == NULL)
634 return ERROR_NO_FREE_STORE;
638 p = (UBYTE **)*p + ((block >> i*8) & 0xff);
641 if (*p == NULL)
643 *p = AllocMem(BLOCKSIZE, MEMF_CLEAR);
645 if (*p == NULL)
647 return ERROR_NO_FREE_STORE;
651 *result = *p;
652 break;
653 } /* switch (mode) */
655 return 0;
659 static void zerofill(UBYTE *address, ULONG size)
661 while (size--)
663 *address++ = 0;
668 static void shrinkfile(struct rambase *rambase, struct fnode *file, LONG size)
670 ULONG blocks, block;
671 UBYTE *p;
673 blocks = (size + BLOCKSIZE - 1)/BLOCKSIZE;
674 block = (file->size + BLOCKSIZE - 1)/BLOCKSIZE;
676 for(;block-- > blocks;)
678 (void)getblock(rambase, file, block, -1, &p);
681 if (size & 0xff)
683 (void)getblock(rambase, file, size, 0, &p);
685 if (p != NULL)
687 zerofill(p + (size & 0xff), -size & 0xff);
691 file->size = size;
695 static void delete(struct rambase *rambase, struct fnode *file)
697 struct hnode *link, *new, *more;
698 struct Node *node;
700 Strfree(rambase, file->name);
701 Strfree(rambase, file->comment);
702 Remove((struct Node *)file);
704 if (file->type == ST_LINKDIR)
706 /* It is a link. Remove it from the chain. */
708 link = ((struct hnode *)file)->orig;
709 ((struct hnode *)file)->orig = NULL;
710 file->type = link->type;
712 while((struct fnode *)link->link != file)
714 link = link->link;
717 link->link = file->link;
719 else if (file->link != NULL)
721 /* If there is a hard link to the object make the link the original */
723 link = file->link;
724 link->type = file->type;
725 more = new->link;
727 while (more != NULL)
729 more->orig = new;
730 more = more->link;
733 switch (file->type)
735 case ST_USERDIR:
736 while((node = RemHead((struct List *)&((struct dnode *)file)->list)) != NULL)
737 AddTail((struct List *)&((struct dnode *)file)->list, node);
738 break;
740 case ST_FILE:
741 CopyMemQuick(&file->size, &((struct fnode *)new)->size,
742 sizeof(struct fnode) - offsetof(struct fnode, size));
743 zerofill((UBYTE *)&file->size,
744 sizeof(struct fnode) - offsetof(struct fnode, size));
745 break;
747 case ST_SOFTLINK:
748 ((struct snode *)new)->contents = ((struct snode *)file)->contents;
749 ((struct snode *)file)->contents = NULL;
750 break;
752 } /* else if (file->link != NULL) */
754 switch (file->type)
756 case ST_USERDIR:
757 Notify_directoryChange(rambase, NOTIFY_Delete, (struct dnode *)file);
759 FreeMem(file, sizeof(struct dnode));
761 return;
763 case ST_FILE:
764 Notify_fileChange(rambase, NOTIFY_Delete, file);
766 shrinkfile(rambase, file, 0);
767 FreeMem(file, sizeof(struct fnode));
769 return;
771 case ST_SOFTLINK:
772 Strfree(rambase, ((struct snode *)file)->contents);
773 FreeMem(file, sizeof(struct snode));
775 return;
780 static int fstrcmp(struct rambase *rambase, CONST_STRPTR s1, CONST_STRPTR s2)
782 for (;;)
784 if (ToLower(*s1) != ToLower(*s2))
786 return *s1 || *s2 != '/';
789 if (!*s1)
791 return 0;
794 s1++;
795 s2++;
800 /* Find a node for a given name */
801 static LONG findname(struct rambase *rambase, CONST_STRPTR *name,
802 struct dnode **dnode)
804 struct dnode *cur = *dnode;
805 CONST_STRPTR rest = *name;
807 for (;;)
809 if (cur->type == ST_LINKDIR)
811 cur = (struct dnode *)((struct hnode *)cur)->orig;
814 if (!*rest)
816 break;
819 if (*rest == '/')
821 if ((struct dnode *)cur->volume == cur)
823 return ERROR_OBJECT_NOT_FOUND;
826 while (cur->node.mln_Pred != NULL)
828 cur = (struct dnode *)cur->node.mln_Pred;
831 cur = (struct dnode *)((BYTE *)cur - offsetof(struct dnode, list));
833 else
835 if (cur->type == ST_SOFTLINK)
837 *dnode = cur;
838 *name = rest;
840 return ERROR_IS_SOFT_LINK;
843 if (cur->type != ST_USERDIR)
845 return ERROR_DIR_NOT_FOUND;
848 *dnode = cur;
849 cur = (struct dnode *)cur->list.mlh_Head;
851 for (;;)
853 if (cur->node.mln_Succ == NULL)
855 *name = rest;
857 return ERROR_OBJECT_NOT_FOUND;
860 if (!fstrcmp(rambase, cur->name, rest))
862 break;
865 cur = (struct dnode *)cur->node.mln_Succ;
869 while (*rest)
871 if (*rest++ == '/')
873 break;
878 *dnode = cur;
880 return 0;
884 static LONG set_file_size(struct rambase *rambase, struct filehandle *handle,
885 QUAD *offp, LONG mode)
887 struct fnode *file = (struct fnode *)handle->node;
888 QUAD size = *offp;
890 if (file->type != ST_FILE)
892 return ERROR_OBJECT_WRONG_TYPE;
895 switch(mode)
897 case OFFSET_BEGINNING:
898 break;
900 case OFFSET_CURRENT:
901 size += handle->position;
902 break;
904 case OFFSET_END:
905 size += file->size;
906 break;
908 default:
909 return ERROR_NOT_IMPLEMENTED;
912 if (size < 0)
914 return ERROR_SEEK_ERROR;
917 if (size < file->size)
919 shrinkfile(rambase, file, size);
922 file->size = *offp = size;
924 return 0;
928 static LONG read(struct rambase *rambase, struct filehandle *handle,
929 APTR buffer, LONG *numbytes)
931 struct fnode *file = (struct fnode *)handle->node;
932 ULONG num = *numbytes;
933 ULONG size = file->size;
934 ULONG block, offset;
935 UBYTE *buf = buffer, *p;
937 if (handle->position >= size)
939 num = 0;
941 else if (handle->position + num > size)
943 num = size - handle->position;
946 block = handle->position/BLOCKSIZE;
947 offset = handle->position & (BLOCKSIZE - 1);
948 size = BLOCKSIZE - offset;
950 while (num)
952 if (size > num)
954 size = num;
957 (void)getblock(rambase, file, block, 0, &p);
959 if (p != NULL)
961 CopyMem(p + offset, buffer, size);
963 else
965 zerofill(buffer, size);
968 buffer += size;
969 num -= size;
970 block++;
971 offset = 0;
972 size = BLOCKSIZE;
975 *numbytes = (UBYTE *)buffer - buf;
976 handle->position += *numbytes;
978 return 0;
982 static LONG write(struct rambase *rambase, struct filehandle *handle,
983 UBYTE *buffer, LONG *numbytes)
985 struct fnode *file = (struct fnode *)handle->node;
986 ULONG num = *numbytes;
987 ULONG size = file->size;
988 ULONG block, offset;
989 UBYTE *buf = buffer, *p;
990 LONG error = 0;
992 if ((LONG)(handle->position + num) < 0)
994 return ERROR_OBJECT_TOO_LARGE;
997 Notify_fileChange(rambase, NOTIFY_Write, file);
999 block = handle->position/BLOCKSIZE;
1000 offset = handle->position & (BLOCKSIZE - 1);
1001 size = BLOCKSIZE - offset;
1003 while (num)
1005 if (size > num)
1007 size = num;
1010 error = getblock(rambase, file, block, 1, &p);
1012 if (error)
1014 break;
1017 CopyMem(buffer, p + offset, size);
1018 buffer += size;
1019 num -= size;
1020 block++;
1021 offset = 0;
1022 size = BLOCKSIZE;
1025 *numbytes = (UBYTE *)buffer - buf;
1026 handle->position += *numbytes;
1027 DateStamp(&file->date);
1029 if (handle->position > file->size)
1031 file->size = handle->position;
1034 return error;
1038 static LONG lock(struct dnode *dir, ULONG mode)
1040 if ((mode & FMF_EXECUTE) && (dir->protect & FMF_EXECUTE))
1042 return ERROR_NOT_EXECUTABLE;
1045 if ((mode & FMF_WRITE) && (dir->protect & FMF_WRITE))
1047 return ERROR_WRITE_PROTECTED;
1050 if ((mode & FMF_READ) && (dir->protect & FMF_READ))
1052 return ERROR_READ_PROTECTED;
1055 if (mode & FMF_LOCK)
1057 if (dir->usecount)
1059 return ERROR_OBJECT_IN_USE;
1062 dir->usecount = ((ULONG)~0)/2 + 1;
1064 else
1066 if (dir->usecount < 0)
1068 return ERROR_OBJECT_IN_USE;
1072 dir->usecount++;
1073 dir->volume->volcount++;
1075 return 0;
1079 static LONG open_(struct rambase *rambase, struct filehandle **handle,
1080 CONST_STRPTR name, ULONG mode)
1082 struct dnode *dir = (*handle)->node;
1083 struct filehandle *fh;
1084 LONG error;
1086 fh = (struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1088 if (fh != NULL)
1090 error = findname(rambase, &name, &dir);
1092 if (!error)
1094 error = lock(dir, mode);
1096 if (!error)
1098 fh->node = dir;
1099 *handle = fh;
1101 if (dir->type == ST_FILE)
1103 Notify_fileChange(rambase, NOTIFY_Open,
1104 (struct fnode *)dir);
1106 else if (dir->type == ST_USERDIR)
1108 D(kprintf("Notifying OPEN at dir %s\n", dir->name));
1109 Notify_directoryChange(rambase, NOTIFY_Open, dir);
1112 return 0;
1116 FreeMem(fh, sizeof(struct filehandle));
1118 else
1120 error = ERROR_NO_FREE_STORE;
1123 return error;
1127 static LONG open_file(struct rambase *rambase, struct filehandle **handle,
1128 CONST_STRPTR name, ULONG mode, ULONG protect)
1130 struct dnode *dir = (*handle)->node;
1131 struct filehandle *fh;
1132 LONG error = 0;
1134 fh = AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1136 if (fh != NULL)
1138 error = findname(rambase, &name, &dir);
1140 if ((mode & FMF_CREATE) && error == ERROR_OBJECT_NOT_FOUND)
1142 CONST_STRPTR s = name;
1143 struct fnode *file;
1145 while (*s)
1147 if (*s++ == '/')
1149 return error;
1153 file = (struct fnode *)AllocMem(sizeof(struct fnode), MEMF_CLEAR);
1154 DateStamp(&file->date);
1156 if (file != NULL)
1158 file->name = Strdup(rambase, name);
1160 if (file->name != NULL)
1162 file->type = ST_FILE;
1163 file->protect = protect;
1164 file->volume = dir->volume;
1165 NewList((struct List *)&file->receivers);
1166 AddTail((struct List *)&dir->list, (struct Node *)file);
1167 error = lock((struct dnode *)file, mode);
1169 if (!error)
1171 fh->node = (struct dnode *)file;
1172 *handle = fh;
1174 Notify_fileChange(rambase, NOTIFY_Add, file);
1176 return 0;
1179 Strfree(rambase, file->name);
1182 FreeMem(file,sizeof(struct fnode));
1185 error = ERROR_NO_FREE_STORE;
1187 else if (!error)
1189 if (dir->type != ST_FILE)
1191 error = ERROR_OBJECT_WRONG_TYPE;
1193 else
1195 error = lock(dir, mode);
1197 if (!error)
1199 /* stegerg */
1200 if (mode & FMF_CLEAR)
1202 shrinkfile(rambase, (struct fnode *)dir, 0);
1203 dir->protect = protect;
1205 /* end stegerg */
1207 fh->node = dir;
1208 *handle = fh;
1210 return 0;
1213 } /* else if (!error) */
1215 FreeMem(fh, sizeof(struct filehandle));
1218 return error;
1222 static LONG create_dir(struct rambase *rambase, struct filehandle **handle,
1223 CONST_STRPTR name, ULONG protect)
1225 struct dnode *dir = (*handle)->node, *new;
1226 struct filehandle *fh;
1227 LONG error;
1229 if (dir->protect & FIBF_WRITE)
1231 return ERROR_WRITE_PROTECTED;
1234 error = findname(rambase, &name, &dir);
1236 if (!error)
1238 return ERROR_OBJECT_EXISTS;
1241 if (error != ERROR_OBJECT_NOT_FOUND)
1243 return error;
1246 if (strchr(name, '/') != NULL)
1248 return error;
1251 fh = AllocMem(sizeof(struct filehandle), MEMF_CLEAR);
1253 if (fh != NULL)
1255 new = (struct dnode *)AllocMem(sizeof(struct dnode), MEMF_CLEAR);
1257 if (new != NULL)
1259 new->name = Strdup(rambase, name);
1261 if (new->name != NULL)
1263 new->type = ST_USERDIR;
1264 new->protect = protect;
1265 new->volume = dir->volume;
1266 new->volume->volcount++;
1267 new->usecount = ((ULONG)~0)/2 + 2;
1268 NewList((struct List *)&new->list);
1269 NewList((struct List *)&new->receivers);
1270 AddTail((struct List *)&dir->list, (struct Node *)new);
1271 fh->node = new;
1272 *handle = fh;
1273 DateStamp(&new->date);
1275 D(bug("New (%p): Name = %s\n", new, new->name));
1276 Notify_directoryChange(rambase, NOTIFY_Add, new);
1278 return 0;
1281 FreeMem(new, sizeof(struct dnode));
1284 FreeMem(fh, sizeof(struct filehandle));
1287 return ERROR_NO_FREE_STORE;
1291 static LONG free_lock(struct rambase *rambase, struct filehandle *filehandle)
1293 struct dnode *dnode = filehandle->node;
1295 dnode->usecount = (dnode->usecount - 1) & ((ULONG)~0)/2;
1296 FreeMem(filehandle, sizeof(struct filehandle));
1297 dnode->volume->volcount--;
1299 return 0;
1303 static LONG seek(struct rambase *rambase, struct filehandle *filehandle,
1304 QUAD *posp, LONG mode)
1306 struct fnode *file = (struct fnode *)filehandle->node;
1307 QUAD pos = *posp;
1309 if (file->type != ST_FILE)
1311 return ERROR_OBJECT_WRONG_TYPE;
1314 switch (mode)
1316 case OFFSET_BEGINNING:
1317 break;
1319 case OFFSET_CURRENT:
1320 pos += filehandle->position;
1321 break;
1323 case OFFSET_END:
1324 pos += file->size;
1325 break;
1327 default:
1328 return ERROR_NOT_IMPLEMENTED;
1331 if (pos < 0)
1333 return ERROR_SEEK_ERROR;
1336 *posp = filehandle->position;
1337 filehandle->position = pos;
1339 return 0;
1343 static const ULONG sizes[]=
1346 offsetof(struct ExAllData,ed_Type),
1347 offsetof(struct ExAllData,ed_Size),
1348 offsetof(struct ExAllData,ed_Prot),
1349 offsetof(struct ExAllData,ed_Days),
1350 offsetof(struct ExAllData,ed_Comment),
1351 offsetof(struct ExAllData,ed_OwnerUID),
1352 sizeof(struct ExAllData)
1356 static LONG examine(struct fnode *file,
1357 struct ExAllData *ead,
1358 ULONG size,
1359 ULONG type,
1360 LONG *dirpos)
1362 STRPTR next, end, name;
1364 if (type > ED_OWNER)
1366 return ERROR_BAD_NUMBER;
1369 next = (STRPTR)ead + sizes[type];
1370 end = (STRPTR)ead + size;
1372 if(next>end) /* > is correct. Not >= */
1373 return ERROR_BUFFER_OVERFLOW;
1375 /* Use *dirpos to store information for ExNext()
1376 * *dirpos is copied to fib->fib_DiskKey in Examine()
1378 if (file->type == ST_USERDIR)
1380 *dirpos = (LONG)(((struct dnode*)file)->list.mlh_Head);
1382 else
1384 /* ExNext() should not be called in this case anyway */
1385 *dirpos = (LONG)file;
1388 switch(type)
1390 case ED_OWNER:
1391 ead->ed_OwnerUID = 0;
1392 ead->ed_OwnerGID = 0;
1394 /* Fall through */
1395 case ED_COMMENT:
1396 if (file->comment != NULL)
1398 ead->ed_Comment = next;
1399 name = file->comment;
1401 for (;;)
1403 if (next >= end)
1405 return ERROR_BUFFER_OVERFLOW;
1408 if (!(*next++ = *name++))
1410 break;
1414 else
1416 ead->ed_Comment = NULL;
1419 /* Fall through */
1420 case ED_DATE:
1421 ead->ed_Days = file->date.ds_Days;
1422 ead->ed_Mins = file->date.ds_Minute;
1423 ead->ed_Ticks = file->date.ds_Tick;
1425 /* Fall through */
1426 case ED_PROTECTION:
1427 ead->ed_Prot = file->protect;
1429 /* Fall through */
1430 case ED_SIZE:
1431 ead->ed_Size = file->size;
1433 /* Fall through */
1434 case ED_TYPE:
1435 ead->ed_Type = file->type;
1437 if (((struct vnode *)file)->self == (struct vnode *)file)
1439 ead->ed_Type=ST_ROOT;
1442 /* Fall through */
1443 case ED_NAME:
1444 ead->ed_Name = next;
1445 name = file->name;
1447 for (;;)
1449 if (next >= end)
1451 return ERROR_BUFFER_OVERFLOW;
1454 if (!(*next++ = *name++))
1456 break;
1460 /* Fall through */
1461 case 0:
1462 ead->ed_Next = (struct ExAllData *)(((IPTR)next + AROS_PTRALIGN - 1) & ~(AROS_PTRALIGN - 1));
1465 return 0;
1469 static LONG examine_next(struct rambase *rambase,
1470 struct filehandle *dir,
1471 struct FileInfoBlock *FIB)
1473 struct fnode *file = (struct fnode *)FIB->fib_DiskKey;
1475 ASSERT_VALID_PTR_OR_NULL(file);
1477 if (file->node.mln_Succ == NULL)
1479 return ERROR_NO_MORE_ENTRIES;
1482 FIB->fib_OwnerUID = 0;
1483 FIB->fib_OwnerGID = 0;
1485 FIB->fib_Date.ds_Days = file->date.ds_Days;
1486 FIB->fib_Date.ds_Minute = file->date.ds_Minute;
1487 FIB->fib_Date.ds_Tick = file->date.ds_Tick;
1488 FIB->fib_Protection = file->protect;
1489 FIB->fib_Size = file->size;
1490 FIB->fib_DirEntryType = file->type;
1492 strncpy(FIB->fib_FileName, file->name, MAXFILENAMELENGTH - 1);
1493 strncpy(FIB->fib_Comment, file->comment != NULL ? file->comment : "",
1494 MAXCOMMENTLENGTH - 1);
1496 FIB->fib_DiskKey = (LONG)file->node.mln_Succ;
1498 return 0;
1502 static LONG examine_all(struct filehandle *dir,
1503 struct ExAllData *ead,
1504 struct ExAllControl *eac,
1505 ULONG size,
1506 ULONG type)
1508 STRPTR end;
1509 struct ExAllData *last=NULL;
1510 struct fnode *ent;
1511 LONG error;
1512 LONG dummy; /* not anything is done with this value but passed to examine */
1513 end = (STRPTR)ead + size;
1515 eac->eac_Entries = 0;
1516 if (dir->node->type != ST_USERDIR)
1518 return ERROR_OBJECT_WRONG_TYPE;
1521 ent = (struct fnode *)eac->eac_LastKey;
1523 if (ent == NULL)
1525 ent = (struct fnode *)dir->node->list.mlh_Head;
1526 if (ent->node.mln_Succ) ent->usecount++;
1529 if (ent->node.mln_Succ == NULL)
1531 return ERROR_NO_MORE_ENTRIES;
1534 ent->usecount--;
1538 error = examine(ent, ead, end - (STRPTR)ead, type, &dummy);
1540 if (error == ERROR_BUFFER_OVERFLOW)
1542 if (last == NULL)
1544 return error;
1547 ent->usecount++;
1548 last->ed_Next = NULL;
1549 eac->eac_LastKey = (IPTR)ent;
1551 return 0;
1553 eac->eac_Entries++;
1554 last = ead;
1555 ead = ead->ed_Next;
1556 ent = (struct fnode *)ent->node.mln_Succ;
1558 } while (ent->node.mln_Succ != NULL);
1560 last->ed_Next = NULL;
1561 eac->eac_LastKey = (IPTR)ent;
1563 return ERROR_NO_MORE_ENTRIES;
1567 static LONG rename_object(struct rambase *rambase,
1568 struct filehandle *filehandle,
1569 CONST_STRPTR namea, CONST_STRPTR nameb)
1571 struct dnode *file = filehandle->node;
1572 LONG error = 0, i;
1574 struct dnode *nodea = filehandle->node, *nodeb;
1575 STRPTR dira, dirb, pos = nameb;
1577 error = findname(rambase, &pos, &nodea);
1578 if (!error)
1579 return ERROR_OBJECT_EXISTS;
1581 error = findname(rambase, &namea, &file);
1582 if (error)
1583 return error;
1585 if ((struct dnode *)file->volume == file)
1586 return ERROR_OBJECT_WRONG_TYPE;
1588 if (file->usecount != 0)
1589 return ERROR_OBJECT_IN_USE;
1591 dira = Strdup(rambase, namea);
1592 dirb = Strdup(rambase, nameb);
1594 pos = strrchr(dira, '/');
1595 if (pos)
1597 *pos = '\0';
1598 namea = ++pos;
1600 else
1601 *dira = '\0';
1603 pos = strrchr(dirb, '/');
1604 if (pos)
1606 *pos = '\0';
1607 nameb = ++pos;
1609 else
1610 *dirb = '\0';
1612 D(bug("[Ram] rename (%s,%s)=>(%s,%s)\n", dira, namea, dirb, nameb));
1614 if (*dira == '\0' && *dirb == '\0')
1616 Strfree(rambase, file->name);
1617 file->name = Strdup(rambase, nameb);
1619 else
1621 nodea = filehandle->node;
1622 error = findname(rambase, &dira, &nodea);
1623 if (error)
1624 goto cleanup;
1626 nodeb = filehandle->node;
1627 error = findname(rambase, &dirb, &nodeb);
1628 if (error)
1629 goto cleanup;
1631 if (nodeb != nodea)
1633 Remove((struct Node *)file);
1634 AddTail((struct List *)&nodeb->list, (struct Node *)file);
1637 Strfree(rambase, file->name);
1638 file->name = Strdup(rambase, nameb);
1641 DateStamp(&file->date);
1643 switch (file->type)
1645 case ST_FILE:
1646 Notify_fileChange(rambase, NOTIFY_Delete, (struct fnode *)file);
1647 Notify_fileChange(rambase, NOTIFY_Add, (struct fnode *)file);
1648 break;
1649 case ST_USERDIR:
1650 default:
1651 Notify_directoryChange(rambase, NOTIFY_Delete, file);
1652 Notify_directoryChange(rambase, NOTIFY_Add, file);
1653 break;
1656 cleanup:
1657 Strfree(rambase, dirb);
1658 Strfree(rambase, dira);
1660 return error;
1663 static LONG delete_object(struct rambase *rambase,
1664 struct filehandle *filehandle, CONST_STRPTR name)
1666 struct dnode *file = filehandle->node;
1667 LONG error;
1669 error = findname(rambase, &name, &file);
1671 if (error)
1673 return error;
1676 if ((struct dnode *)file->volume == file)
1678 return ERROR_OBJECT_WRONG_TYPE;
1681 if (file->usecount != 0)
1683 return ERROR_OBJECT_IN_USE;
1686 if (file->protect & FIBF_DELETE)
1688 return ERROR_DELETE_PROTECTED;
1691 if (file->type == ST_USERDIR && file->list.mlh_Head->mln_Succ != NULL)
1693 return ERROR_DIRECTORY_NOT_EMPTY;
1696 delete(rambase, (struct fnode *)file);
1698 return 0;
1702 static int GM_UNIQUENAME(Close)
1704 LIBBASETYPEPTR rambase,
1705 struct IOFileSys *iofs
1708 struct cnode *dev;
1709 struct vnode *vol;
1710 struct dnode *dir;
1711 struct fnode *file;
1713 struct filehandle *handle;
1715 handle = (struct filehandle *)iofs->IOFS.io_Unit;
1716 dev = (struct cnode *)handle->node;
1717 vol = dev->volume;
1719 if (dev->type != ST_LINKDIR || dev->self != dev)
1721 iofs->io_DosError = ERROR_OBJECT_WRONG_TYPE;
1723 return 0;
1726 if (vol->volcount)
1728 iofs->io_DosError = ERROR_OBJECT_IN_USE;
1730 return 0;
1733 free_lock(rambase, handle);
1734 RemDosEntry(vol->doslist);
1735 FreeDosEntry(vol->doslist);
1737 while (vol->list.mlh_Head->mln_Succ != NULL)
1739 dir = (struct dnode *)vol->list.mlh_Head;
1741 if (dir->type == ST_USERDIR)
1743 while((file = (struct fnode *)RemHead((struct List *)&dir->list)) != NULL)
1745 AddTail((struct List *)&vol->list, (struct Node *)dir);
1749 delete(rambase, (struct fnode *)dir);
1752 Strfree(rambase, vol->name);
1753 FreeMem(vol, sizeof(struct vnode));
1755 Strfree(rambase, dev->name);
1756 FreeMem(dev, sizeof(struct cnode));
1758 iofs->io_DosError = 0;
1760 return TRUE;
1764 void processFSM(struct rambase *rambase);
1767 static void deventry(struct rambase *rambase)
1769 ULONG notifyMask;
1770 ULONG fileOpMask;
1771 struct Message *msg;
1774 Init device port. AllocSignal() cannot fail because this is a
1775 freshly created task with all signal bits still free.
1778 rambase->port->mp_SigBit = AllocSignal(-1);
1779 rambase->port->mp_Flags = PA_SIGNAL;
1781 /* Check if there are pending messages that we missed */
1782 if ((msg = GetMsg(rambase->port))) PutMsg(rambase->port, msg);
1784 Notify_initialize(rambase);
1786 notifyMask = 1 << rambase->notifyPort->mp_SigBit;
1788 fileOpMask = 1 << rambase->port->mp_SigBit;
1790 while (TRUE)
1792 ULONG flags;
1794 flags = Wait(fileOpMask | notifyMask);
1796 if (flags & notifyMask)
1798 struct NotifyMessage *nMessage;
1800 D(kprintf("Got replied notify message\n"));
1802 while ((nMessage = (struct NotifyMessage *)GetMsg(rambase->notifyPort)) != NULL)
1804 nMessage->nm_NReq->nr_Flags &= ~NRF_NOT_REPLIED;
1805 FreeVec(nMessage);
1809 if (flags & fileOpMask)
1811 processFSM(rambase);
1817 void processFSM(struct rambase *rambase)
1819 struct IOFileSys *iofs;
1820 struct dnode *dir;
1822 LONG error = 0;
1824 /* Get and process the messages. */
1825 while ((iofs = (struct IOFileSys *)GetMsg(rambase->port)) != NULL)
1827 D(bug("Ram.handler initialized %u\n", iofs->IOFS.io_Command));
1829 switch (iofs->IOFS.io_Command)
1831 case FSA_OPEN:
1833 get handle on a file or directory
1834 Unit *current; current directory / new handle on return
1835 STRPTR name; file- or directoryname
1836 LONG mode; open mode
1839 error = open_(rambase,
1840 (struct filehandle **)&iofs->IOFS.io_Unit,
1841 iofs->io_Union.io_OPEN.io_Filename,
1842 iofs->io_Union.io_OPEN.io_FileMode);
1843 break;
1845 case FSA_OPEN_FILE:
1847 open a file or create a new one
1848 Unit *current; current directory / new handle on return
1849 STRPTR name; file- or directoryname
1850 LONG mode; open mode
1851 LONG protect; protection flags if a new file is created
1854 error = open_file(rambase,
1855 (struct filehandle **)&iofs->IOFS.io_Unit,
1856 iofs->io_Union.io_OPEN_FILE.io_Filename,
1857 iofs->io_Union.io_OPEN_FILE.io_FileMode,
1858 iofs->io_Union.io_OPEN_FILE.io_Protection);
1859 break;
1861 case FSA_READ:
1863 read a number of bytes from a file
1864 Unit *current; filehandle
1865 APTR buffer; data
1866 LONG numbytes; number of bytes to read /
1867 number of bytes read on return,
1868 0 if there are no more bytes in the file
1870 error = read(rambase,
1871 (struct filehandle *)iofs->IOFS.io_Unit,
1872 iofs->io_Union.io_READ.io_Buffer,
1873 &iofs->io_Union.io_READ.io_Length);
1874 break;
1876 case FSA_WRITE:
1878 write a number of bytes to a file
1879 Unit *current; filehandle
1880 APTR buffer; data
1881 LONG numbytes; number of bytes to write /
1882 number of bytes written on return
1884 error = write(rambase,
1885 (struct filehandle *)iofs->IOFS.io_Unit,
1886 iofs->io_Union.io_WRITE.io_Buffer,
1887 &iofs->io_Union.io_WRITE.io_Length);
1888 break;
1890 case FSA_SEEK:
1892 set / read position in file
1893 Unit *current; filehandle
1894 LONG posh;
1895 LONG posl; relative position /
1896 old position on return
1897 LONG mode; one of OFFSET_BEGINNING, OFFSET_CURRENT,
1898 OFFSET_END
1900 error = seek(rambase,
1901 (struct filehandle *)iofs->IOFS.io_Unit,
1902 &iofs->io_Union.io_SEEK.io_Offset,
1903 iofs->io_Union.io_SEEK.io_SeekMode);
1904 break;
1906 case FSA_CLOSE:
1908 /* Get rid of a handle
1909 Unit *current; filehandle */
1911 struct filehandle *handle =
1912 (struct filehandle *)iofs->IOFS.io_Unit;
1914 Notify_fileChange(rambase, NOTIFY_Close,
1915 (struct fnode *)handle->node);
1916 error = free_lock(rambase, handle);
1917 break;
1920 case FSA_EXAMINE:
1922 Get information about the current object
1923 Unit *current; current object
1924 struct ExAllData *ead; buffer to be filled
1925 ULONG size; size of the buffer
1926 ULONG type; type of information to get
1927 iofs->io_DirPos; leave current position so
1928 ExNext() knows where to find
1929 next object
1931 error = examine((struct fnode *)((struct filehandle *)iofs->IOFS.io_Unit)->node,
1932 iofs->io_Union.io_EXAMINE.io_ead,
1933 iofs->io_Union.io_EXAMINE.io_Size,
1934 iofs->io_Union.io_EXAMINE.io_Mode,
1935 &(iofs->io_DirPos));
1936 break;
1938 case FSA_EXAMINE_NEXT:
1940 Get information about the next object
1941 Unit *current; current object
1942 struct FileInfoBlock *fib;
1944 error = examine_next(rambase,
1945 (struct filehandle *)iofs->IOFS.io_Unit,
1946 iofs->io_Union.io_EXAMINE_NEXT.io_fib);
1947 break;
1949 case FSA_EXAMINE_ALL:
1951 Read the current directory
1952 Unit *current; current directory
1953 struct ExAllData *ead; buffer to be filled
1954 ULONG size; size of the buffer
1955 ULONG type; type of information to get
1957 error = examine_all((struct filehandle *)iofs->IOFS.io_Unit,
1958 iofs->io_Union.io_EXAMINE_ALL.io_ead,
1959 iofs->io_Union.io_EXAMINE_ALL.io_eac,
1960 iofs->io_Union.io_EXAMINE_ALL.io_Size,
1961 iofs->io_Union.io_EXAMINE_ALL.io_Mode);
1962 break;
1964 case FSA_CREATE_DIR:
1966 Build lock and open a new directory
1967 Unit *current; current directory
1968 STRPTR name; name of the dir to create
1969 LONG protect; Protection flags for the new dir
1972 // kprintf("Creating directory %s\n",
1973 // iofs->io_Union.io_CREATE_DIR.io_Filename);
1976 error = create_dir(rambase,
1977 (struct filehandle **)&iofs->IOFS.io_Unit,
1978 iofs->io_Union.io_CREATE_DIR.io_Filename,
1979 iofs->io_Union.io_CREATE_DIR.io_Protection);
1980 break;
1982 case FSA_DELETE_OBJECT:
1984 Delete file or directory
1985 Unit *current; current directory
1986 STRPTR name; filename
1988 error = delete_object(rambase,
1989 (struct filehandle *)iofs->IOFS.io_Unit,
1990 iofs->io_Union.io_DELETE_OBJECT.io_Filename);
1991 break;
1993 case FSA_SET_PROTECT:
1996 Set protection bits for a certain file or directory.
1997 Unit *current; current directory
1998 STRPTR name; filename
1999 ULONG protect; new protection bits
2002 CONST_STRPTR name = iofs->io_Union.io_SET_PROTECT.io_Filename;
2004 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
2005 error = findname(rambase, &name, &dir);
2007 if (!error)
2009 dir->protect = iofs->io_Union.io_SET_PROTECT.io_Protection;
2012 break;
2015 case FSA_SET_OWNER:
2018 Set owner and group of the file or directory
2019 Unit *current; current directory
2020 STRPTR name; filename
2021 ULONG UID;
2022 ULONG GID;
2025 CONST_STRPTR name = iofs->io_Union.io_SET_OWNER.io_Filename;
2027 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
2028 error = findname(rambase, &name, &dir);
2030 if(!error)
2034 break;
2037 case FSA_SET_DATE:
2040 Set creation date of the file
2041 Unit *current; current directory
2042 STRPTR name; filename
2043 ULONG days;
2044 ULONG mins;
2045 ULONG ticks; timestamp
2048 CONST_STRPTR name = iofs->io_Union.io_SET_DATE.io_Filename;
2050 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
2051 error = findname(rambase, &name, &dir);
2053 if(!error)
2055 dir->date = iofs->io_Union.io_SET_DATE.io_Date;
2058 break;
2061 case FSA_SET_COMMENT:
2064 Set a comment for the file or directory;
2065 Unit *current; current directory
2066 STRPTR name; filename
2067 STRPTR comment; NUL terminated C string or NULL.
2070 CONST_STRPTR name = iofs->io_Union.io_SET_COMMENT.io_Filename;
2072 dir = ((struct filehandle *)iofs->IOFS.io_Unit)->node;
2073 error = findname(rambase, &name, &dir);
2075 if (!error)
2077 if (iofs->io_Union.io_SET_COMMENT.io_Comment)
2079 STRPTR s = Strdup(rambase,
2080 iofs->io_Union.io_SET_COMMENT.io_Comment);
2081 if (s != NULL)
2083 Strfree(rambase, dir->comment);
2084 dir->comment = s;
2086 else
2088 error = ERROR_NO_FREE_STORE;
2091 else
2093 Strfree(rambase, dir->comment);
2094 dir->comment = NULL;
2098 break;
2101 case FSA_SET_FILE_SIZE:
2103 Set a new size for the file.
2104 Unit *file; filehandle
2105 LONG offh;
2106 LONG offl; offset to current position/
2107 new size on return
2108 LONG mode; relative to what (see Seek)
2110 error = set_file_size(rambase,
2111 (struct filehandle *)iofs->IOFS.io_Unit,
2112 &iofs->io_Union.io_SET_FILE_SIZE.io_Offset,
2113 iofs->io_Union.io_SET_FILE_SIZE.io_SeekMode);
2114 break;
2116 case FSA_IS_FILESYSTEM:
2117 iofs->io_Union.io_IS_FILESYSTEM.io_IsFilesystem = TRUE;
2118 error = 0;
2119 break;
2121 case FSA_DISK_INFO:
2123 struct InfoData *id = iofs->io_Union.io_INFO.io_Info;
2125 id->id_NumSoftErrors = 0;
2126 id->id_UnitNumber = 0;
2127 id->id_DiskState = ID_VALIDATED;
2128 id->id_NumBlocks = AvailMem(MEMF_TOTAL | MEMF_PUBLIC)/BLOCKSIZE;
2129 id->id_NumBlocksUsed = id->id_NumBlocks - AvailMem(MEMF_PUBLIC)/BLOCKSIZE;
2130 id->id_BytesPerBlock = BLOCKSIZE;
2131 id->id_DiskType = ID_DOS_DISK;
2132 id->id_VolumeNode = NULL; /* What is this? */
2133 id->id_InUse = (LONG)TRUE;
2135 error = 0;
2138 break;
2141 case FSA_ADD_NOTIFY:
2143 BOOL ok;
2144 struct NotifyRequest *nr =
2145 iofs->io_Union.io_NOTIFY.io_NotificationRequest;
2146 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
2148 D(kprintf("Adding notification for entity (nr = %s)\n",
2149 nr->nr_FullName));
2151 ok = Notify_addNotification(rambase, fh->node, nr);
2153 if (!ok)
2155 error = ERROR_NO_FREE_STORE;
2158 D(kprintf("Notification now added!\n"));
2160 break;
2162 case FSA_REMOVE_NOTIFY:
2164 struct NotifyRequest *nr =
2165 iofs->io_Union.io_NOTIFY.io_NotificationRequest;
2167 Notify_removeNotification(rambase, nr);
2169 break;
2171 case FSA_RENAME:
2172 error = rename_object(rambase,
2173 (struct filehandle *)iofs->IOFS.io_Unit,
2174 iofs->io_Union.io_RENAME.io_Filename,
2175 iofs->io_Union.io_RENAME.io_NewName);
2176 break;
2178 case FSA_IS_INTERACTIVE:
2179 iofs->io_Union.io_IS_INTERACTIVE.io_IsInteractive = 0;
2180 break;
2182 default:
2183 error = ERROR_NOT_IMPLEMENTED;
2185 D(kprintf("ram_handler, unimplemented FSA: %ld\n", iofs->IOFS.io_Command));
2186 break;
2188 FSA_FILE_MODE
2189 Change or read the mode of a single filehandle
2190 Unit *current; filehandle to change
2191 ULONG newmode; new mode/old mode on return
2192 ULONG mask; bits affected
2194 FSA_MOUNT_MODE
2195 Change or read the mode of the filesystem
2196 Unit *current; filesystem to change
2197 ULONG newmode; new mode/old mode on return
2198 ULONG mask; bits affected
2199 STRPTR passwd; password for MMF_LOCKED
2201 FSA_MAKE_HARDLINK
2202 Create a hard link on a file, directory or soft link
2203 Unit *current; current directory
2204 STRPTR name; softlink name
2205 Unit *target; target handle
2207 FSA_MAKE_SOFTLINK
2208 Create a soft link to another object
2209 Unit *current; current directory
2210 STRPTR name; softlink name
2211 STRPTR target; target name
2213 FSA_READ_LINK
2214 FSA_SERIALIZE_DISK
2215 FSA_WAIT_CHAR
2216 FSA_INFO
2217 FSA_TIMER
2218 FSA_DISK_TYPE
2219 FSA_DISK_CHANGE
2220 FSA_SAME_LOCK
2221 FSA_CHANGE_SIGNAL
2222 FSA_FORMAT
2223 FSA_EXAMINE_ALL
2224 FSA_EXAMINE_FH
2225 FSA_EXAMINE_ALL_END
2230 iofs->io_DosError = error;
2231 ReplyMsg(&iofs->IOFS.io_Message);
2234 #if 0
2235 if (rambase->iofs != NULL)
2237 iofs = rambase->iofs;
2239 if (iofs->IOFS.io_Message.mn_Node.ln_Type == NT_MESSAGE)
2241 abort_notify(rambase, iofs);
2242 iofs->io_DosError = ERROR_BREAK;
2243 rambase->iofs = NULL;
2244 ReplyMsg(&iofs->IOFS.io_Message);
2246 else
2248 rambase->iofs = NULL;
2249 Signal(1, 0);
2252 #endif
2259 /***************************************************************************
2260 ****************************************************************************/
2262 /** Notification stuff **/
2265 * Immediate notification:
2267 * ACTION_RENAME_OBJECT
2268 * ACTION_RENAME_DISK
2269 * ACTION_CREATE_DIR
2270 * ACTION_DELETE_OBJECT
2271 * ACTION_SET_DATE
2274 * Session semantics notification:
2276 * ACTION_WRITE
2277 * ACTION_FINDUPDATE
2278 * ACTION_FINDOUTPUT
2279 * ACTION_SET_FILE_SIZE
2282 * For ram-handler, the only FSA actions currently implemented/affected are
2283 * FSA_WRITE, FSA_CREATE_DIR, FSA_DELETE (and implicitly FSA_OPEN, FSA_CLOSE)
2288 BOOL Notify_initialize(struct rambase *rambase)
2290 rambase->notifyPort = CreateMsgPort();
2292 if (rambase->notifyPort == NULL)
2294 return FALSE;
2297 return TRUE;
2301 void Notify_fileChange(struct rambase *rambase, NType type, struct fnode *file)
2303 switch (type)
2305 case NOTIFY_Open:
2306 break;
2308 case NOTIFY_Write:
2309 D(bug("Setting write flag!\n"));
2310 file->flags |= FILEFLAGS_Changed;
2311 break;
2313 case NOTIFY_Close:
2314 /* Only notify in case the file was changed */
2315 if (file->flags & FILEFLAGS_Changed)
2317 D(bug("Notification on close (file was changed).\n"));
2318 file->flags &= ~FILEFLAGS_Changed;
2319 Notify_notifyTasks(rambase, &file->receivers);
2321 break;
2323 case NOTIFY_Add:
2325 STRPTR fullName;
2326 struct List *receivers;
2328 fullName = getName(rambase, (struct dnode *)file);
2330 D(kprintf("Found full name: %s\n", fullName));
2332 receivers = HashTable_find(rambase, rambase->notifications,
2333 fullName);
2335 if (receivers != NULL)
2337 D(kprintf("Found notification for created file!\n"));
2339 while (!IsListEmpty(receivers))
2341 AddHead((struct List *)&file->receivers,
2342 RemHead(receivers));
2346 HashTable_remove(rambase, rambase->notifications, fullName);
2348 D(bug("Notifying file receivers!\n"));
2349 Notify_notifyTasks(rambase, &file->receivers);
2351 FreeVec(fullName);
2353 break;
2355 case NOTIFY_Delete:
2356 /* It's the same thing as for directories... */
2357 Notify_directoryChange(rambase, NOTIFY_Delete, (struct dnode *)file);
2358 break;
2360 default:
2361 kprintf("Error\n");
2362 break;
2367 void Notify_directoryChange(struct rambase *rambase, NType type,
2368 struct dnode *dir)
2370 switch (type)
2372 case NOTIFY_Open:
2374 STRPTR fullName;
2376 fullName = getName(rambase, dir);
2378 /* TODO: HashTable_apply(ht, fullName, dir); */
2380 FreeVec(fullName);
2382 break;
2384 case NOTIFY_Add:
2386 STRPTR fullName;
2387 struct List *receivers;
2389 fullName = getName(rambase, dir);
2391 D(kprintf("Found full name: %s\n", fullName));
2393 receivers = HashTable_find(rambase, rambase->notifications,
2394 fullName);
2396 if (receivers != NULL)
2398 D(kprintf("Found notification for created directory!\n"));
2400 while (!IsListEmpty(receivers))
2402 AddHead((struct List *)&dir->receivers,
2403 RemHead(receivers));
2407 HashTable_remove(rambase, rambase->notifications, fullName);
2409 FreeVec(fullName);
2412 D(kprintf("Notifying dir receivers!\n"));
2413 Notify_notifyTasks(rambase, &dir->receivers);
2414 break;
2416 case NOTIFY_Delete:
2418 /* As we have deleted a file, we must move the requests for
2419 this file to the hash table */
2420 struct List *receivers = (struct List *)&dir->receivers;
2422 Notify_notifyTasks(rambase, &dir->receivers);
2424 /* Move the Notification request to the hash table as we're going
2425 to delete this directory */
2426 while (!IsListEmpty(receivers))
2428 struct Receiver *rr = (struct Receiver *)RemHead(receivers);
2430 HashTable_insert(rambase, rambase->notifications,
2431 rr->nr->nr_FullName, rr);
2435 break;
2437 default:
2438 kprintf("Error\n");
2439 break;
2442 // kprintf("Returning from Notify_dirChange()\n");
2446 /* TODO: Implement support for NRF_WAIT_REPLY */
2447 void Notify_notifyTasks(struct rambase *rambase, struct MinList *notifications)
2449 struct Receiver *rr;
2451 // kprintf("Inside notifytasks, not = %p\n", notifications);
2453 ForeachNode((struct List *)notifications, rr)
2455 struct NotifyRequest *nr = rr->nr;
2457 if (nr->nr_Flags & NRF_SEND_MESSAGE &&
2458 !(nr->nr_Flags & NRF_WAIT_REPLY && nr->nr_Flags & NRF_NOT_REPLIED))
2460 struct NotifyMessage *nm = AllocVec(sizeof(struct NotifyMessage),
2461 MEMF_PUBLIC | MEMF_CLEAR);
2463 if (nm == NULL)
2465 return;
2468 nm->nm_ExecMessage.mn_ReplyPort = rambase->notifyPort;
2469 nm->nm_ExecMessage.mn_Length = sizeof(struct NotifyMessage);
2470 nm->nm_NReq = nr;
2471 nr->nr_Flags |= NRF_NOT_REPLIED;
2473 PutMsg(nr->nr_stuff.nr_Msg.nr_Port, &nm->nm_ExecMessage);
2475 else if (nr->nr_Flags & NRF_SEND_SIGNAL)
2477 Signal(nr->nr_stuff.nr_Signal.nr_Task,
2478 1 << nr->nr_stuff.nr_Signal.nr_SignalNum);
2483 /* also defined in rom/dos/filesystem_support.c */
2484 STRPTR RamStripVolume(STRPTR name)
2486 STRPTR path = strchr(name, ':');
2487 if (path != NULL)
2488 path++;
2489 else
2490 path = name;
2491 return path;
2494 BOOL Notify_addNotification(struct rambase *rambase, struct dnode *dn,
2495 struct NotifyRequest *nr)
2497 struct dnode *dnTemp = dn;
2498 HashTable *ht = rambase->notifications;
2499 STRPTR name = nr->nr_FullName;
2500 CONST_STRPTR tname = RamStripVolume(name);
2502 /* First: Check if the file is opened */
2503 D(bug("Checking existence of %s\n", tname));
2505 if (findname(rambase, &tname, &dnTemp) == 0)
2507 /* This file was already opened (or at least known by the file
2508 system) */
2510 struct Receiver *rr = AllocVec(sizeof(struct Receiver), MEMF_CLEAR);
2512 if (rr == NULL)
2514 return FALSE;
2517 rr->nr = nr;
2519 if (nr->nr_Flags & NRF_NOTIFY_INITIAL)
2521 struct MinList tempList;
2523 /* Create a temporary list on the stack and add the receiver to
2524 it. Then forget about this and add the node to the receiver
2525 list (below this block). */
2526 NewList((struct List *)&tempList);
2527 AddHead((struct List *)&tempList, &rr->node);
2528 Notify_notifyTasks(rambase, &tempList);
2531 /* Add the receiver node to the file's/directory's list of receivers */
2532 AddTail((struct List *)&dnTemp->receivers, &rr->node);
2534 D(bug("Notification added to node: %s\n", name));
2536 return TRUE;
2538 else
2540 /* This file is not opened */
2542 struct Receiver *rr = AllocVec(sizeof(struct Receiver), MEMF_CLEAR);
2544 if (rr == NULL)
2546 return FALSE;
2549 rr->nr = nr;
2551 HashTable_insert(rambase, ht, name, rr);
2553 return TRUE;
2558 void Notify_removeNotification(struct rambase *rambase,
2559 struct NotifyRequest *nr)
2561 struct dnode *dn = (struct dnode *)rambase->root;
2562 struct Receiver *rr, *rrTemp;
2563 STRPTR name = nr->nr_FullName;
2564 CONST_STRPTR tname = RamStripVolume(name);
2565 struct List *receivers;
2566 BOOL fromTable = FALSE;
2568 if (findname(rambase, &tname, &dn) == 0)
2570 receivers = (struct List *)&dn->receivers;
2572 else
2574 /* This was a request for an entity that doesn't exist yet */
2575 receivers = HashTable_find(rambase, rambase->notifications, name);
2577 if (receivers == NULL)
2579 D(bug("Ram: This should not happen! -- buggy application...\n"));
2580 return;
2583 fromTable = TRUE;
2586 ForeachNodeSafe(&receivers, rr, rrTemp)
2588 if (rr->nr == nr)
2590 Remove((struct Node *)rr);
2591 FreeVec(rr);
2592 break;
2596 if (fromTable)
2598 /* If we removed a request for a file that doesn't exist yet --
2599 if this was the only notification request for that file, remove
2600 also the hash entry. */
2601 if (IsListEmpty((struct List *)receivers))
2603 HashTable_remove(rambase, rambase->notifications, name);
2608 static STRPTR getName(struct rambase *rambase, struct dnode *dn)
2610 struct dnode *dnTemp = dn;
2612 ULONG length;
2613 STRPTR fullName;
2614 CONST_STRPTR slash = "/";
2615 CONST_STRPTR nextSlash = slash;
2616 ULONG partLen;
2618 /* First, calculate the size of the complete filename */
2619 length = strlen(dn->name) + 2; /* Add trailing 0 byte and possible '/' */
2621 while (findname(rambase, &slash, &dnTemp) == 0)
2623 slash = nextSlash;
2624 length += 1 + strlen(dnTemp->name); /* Add '/' byte */
2627 /* The MEMF_CLEAR is necessary for the while loop below to work */
2628 fullName = AllocVec(length, MEMF_PUBLIC | MEMF_CLEAR);
2630 if (fullName == NULL)
2632 return NULL;
2635 dnTemp = dn;
2636 fullName += length - 1;
2638 fullName -= strlen(dn->name) + 1;
2639 strcpy(fullName, dn->name);
2641 slash = "/";
2642 nextSlash = slash;
2643 while (findname(rambase, &slash, &dnTemp) != ERROR_OBJECT_NOT_FOUND)
2645 slash = nextSlash;
2646 partLen = strlen(dnTemp->name);
2648 fullName -= partLen + 1;
2649 strcpy(fullName, dnTemp->name);
2651 if ((struct vnode *)dnTemp == dnTemp->volume)
2652 fullName[partLen] = ':'; /* Root of Ram Disk */
2653 else
2654 fullName[partLen] = '/'; /* Replace 0 with '/' */
2657 return fullName;
2660 ADD2INITLIB(GM_UNIQUENAME(Init),0)
2661 ADD2OPENDEV(GM_UNIQUENAME(Open),0)
2662 ADD2CLOSEDEV(GM_UNIQUENAME(Close),0)
2663 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge),0)