Message-Id: <3.0.1.32.19980202103309.007f6ce0@yacker.xiotech.com> Date: Mon, 02 Feb 1998 10:33:09 -0600 To: djgpp-workers AT delorie DOT com From: Randy Maas Subject: A patch for fsext.txh Cc: bcurrie AT tssc DOT co DOT nz Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=====================_886458789==_" Precedence: bulk --=====================_886458789==_ Content-Type: text/plain; charset="us-ascii" Here is a *much* larger example that has some functionality. My only concern is that it may too much to take in if you want to know what __FSEXT_{get,set}_data does. I've tried to vary the comments -- if describing it one way doesn't help, maybe the other way will. The code is a very stripped down version of a different one I have used; it can be stripped further by doing even less error checking (currently it doesn't set errno). This version does compile without warnings. One possibility, is that the other io functions *could* be emulated, but not provided in the example. ie: ...inside of the switch... case __FSEXT_stat: *RV = my_stat(Args); /* see XYZ for an example of a stat handler */ return 1; Randy randym AT acm DOT org --=====================_886458789==_ Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="fsext.dif" *** src/libc/fsext/fsext.txh~1 Fri Jan 2 00:28:02 1998 --- src/libc/fsext/fsext.txh Mon Feb 2 10:17:26 1998 *************** *** 291,300 **** --- 291,542 ---- to store a descriptor-specific pointer that can later be retrieved by @ref{__FSEXT_get_data}. The pointer is not otherwise used. + This is useful when writing an extension that may be handling several + open psuedo-files. @code{__FSEXT_set_data} can be used when creating or + opening the file to store a pointer to data about the specific file. Later, + when specific operation needs to be done (e.g. read, write, etc.) a + pointer to psuedo-file associated with the file descriptor can be fetched + with @code{__FSEXT_get_data}. + @subheading Return Value Returns the pointer you passed it, or NULL if there was an error. + @subheading Example + /* + This is a example fsext that will simulate a ramdisk. You can create, + open and close files in the /ramdisk directory. These files will exist + only in memory and will not be written to disk. You can read and write + to these files; the other FSEXT functions are implemented. + + Files are not deletable or seekable or such. + Read/write permissions are ignored. + */ + + #include + #include + #include + #include + #include + #include + + typedef struct + @{ + void* Ptr; + off_t Current_Ofs; + size_t Size; + int Opend; + @} _mem_file_t; + + /* A list of our file names, use insque and remque */ + typedef struct _mem_name_t + @{ + struct _mem_name_t* q_forw; + struct _mem_name_t* q_back; + char* Name; + _mem_file_t* FPtr; + @} _mem_name_t; + + static _mem_name_t Head = @{NULL, NULL, NULL@}; + + int my_fsext(__FSEXT_Fnumber Op, int* RV, va_list Args) + @{ + const char* Path; + void* Buffer; + size_t Size; + mode_t Mode; + int fd; + _mem_file_t* MPtr; + _mem_name_t* NPtr; + + if (Op == __FSEXT_open || Op == __FSEXT_creat) + @{ + /* Get the path name */ + Path = va_arg(Args, const char*); + Mode = va_arg(Args, mode_t); + + /* Check that we are dealing the proper folder */ + if (strnicmp("/ramdisk/", Path, 5) != 0) return 0; + @} + + switch (Op) + @{ + case __FSEXT_open: + /* Open an existing memory file or create a new one */ + + /* Check to see if we should create a new file */ + if (! (Mode & (O_CREAT | O_TRUNC))) + @{ + int Found = 0; + + /* Look up the file */ + for (NPtr = Head.q_forw; NPtr; NPtr = NPtr->q_forw) + if (stricmp(Path+9, NPtr->Name)) @{Found = 1; break;@} + + if (!Found) return 0; + + /* Now check to see if it is already opened */ + if (NPtr->FPtr->Opend) + @{ + /* It is already opened */ + *RV = -1; + return 1; + @} + + /* Mark the file as open now */ + NPtr->FPtr->Opend = 1; + + /* Start at the beginning of the file */ + NPtr->FPtr->Current_Ofs = 0; + + /* Set ourselves up with a file descriptor */ + fd = __FSEXT_alloc_fd(my_fsext); + *RV = fd; + + if (fd >= 0) + @{ + /* Associate the file data point with the file descriptor for + fast look up later */ + __FSEXT_set_data(fd, NPtr->FPtr); + @} + + return 1; + @} + /* Otherwise fall-thru and create the file */ + + case __FSEXT_creat: + /* Create a new memory file */ + + /* Nuke any files with the same name */ + for (NPtr = Head.q_forw; NPtr; NPtr = NPtr->q_forw) + if (stricmp(NPtr->Name, Path+9) == 0) + @{ + free(NPtr->Name); + if (NPtr->FPtr) + @{ + free(NPtr->FPtr->Ptr); + free(NPtr->FPtr); + @} + remque((struct qelem*) NPtr); + break; + @} + + /* Prevent any one else from opening it */ + MPtr->Opend = 1; + + /* Allocate some memory to keep info on our fake file */ + MPtr = malloc(sizeof(_mem_file_t)); + if (!MPtr) return 0; + + memset(MPtr, 0, sizeof(_mem_file_t)); + + /* Get a file descriptor we can use */ + fd = __FSEXT_alloc_fd(my_fsext); + if (fd < 0) + @{ + free(MPtr); + return 0; + @} + + /* Now store our note about this file descriptor so we can lookup it + up quickly later. */ + __FSEXT_set_data(fd, MPtr); + + /* Store our name for later look up */ + NPtr = malloc(sizeof(_mem_name_t)); + NPtr->Name = strdup(Path+9); + NPtr->FPtr = MPtr; + insque((struct qelem*) NPtr, (struct qelem*) &Head); + + /* Return the file descriptor */ + *RV = fd; + return 1; + + case __FSEXT_close: + fd = va_arg(Args, int); + + /* Allow others to open this file */ + MPtr = __FSEXT_get_data(fd); + if (MPtr) MPtr->Opend = 0; + + /* Disassociate ourselves from the file descriptor */ + __FSEXT_set_data(fd, NULL); + __FSEXT_set_function(fd, NULL); + + /* Now close the DOS descriptor itself */ + *RV = close(fd); + return 1; + + case __FSEXT_read: + /* Read from our memory file. */ + fd = va_arg(Args, int); + Buffer = va_arg(Args, void*); + Size = va_arg(Args, size_t); + + /* Look up the information about this file */ + MPtr = __FSEXT_get_data(fd); + if (!MPtr) + @{ + *RV = -1; + return 1; + @} + + if (MPtr->Current_Ofs >= MPtr->Size) + @{ + *RV = 0; + return 1; + @} + + if (Size > (MPtr->Size - MPtr->Current_Ofs)) + Size = MPtr->Size - MPtr->Current_Ofs; + + memcpy(Buffer, (char*) MPtr->Ptr+MPtr->Current_Ofs, Size); + MPtr->Current_Ofs += Size; + + *RV = Size; + return 1; + + case __FSEXT_write: + /* Write data to our memory file */ + fd = va_arg(Args, int); + Buffer = va_arg(Args, void*); + Size = va_arg(Args, size_t); + + /* Get the file associated with this descriptor */ + MPtr = __FSEXT_get_data(fd); + if (!MPtr) + @{ + *RV = -1; + return 1; + @} + + /* Do we need to resize our file? */ + if (Size + MPtr->Current_Ofs >= MPtr->Size) + @{ + MPtr->Ptr = realloc(MPtr->Ptr, MPtr->Current_Ofs+Size); + if (!MPtr->Ptr) + @{ + *RV = -1; + return 1; + @} + + MPtr->Size = MPtr->Current_Ofs + Size; + @} + + /* Store the data */ + memcpy((char*)MPtr->Ptr + MPtr->Current_Ofs, Buffer, Size); + MPtr->Current_Ofs += Size; + + /* And return */ + *RV = Size; + return 1; + + default: return 0; /* Not done. */ + @} + @} + + + @c ---------------------------------------------------------------------- @node __FSEXT_get_data, file system @subheading Syntax *************** *** 311,317 **** --- 553,562 ---- to retrieve a descriptor-specific pointer that was previously stored by @ref{__FSEXT_set_data}. The pointer is not otherwise used. + @pxref{__FSEXT_set_data} for an example of how this may be used. + @subheading Return Value Returns the stored pointer, or NULL if there was an error (or no pointer had been stored). --=====================_886458789==_ Content-Type: text/plain; charset="us-ascii" --=====================_886458789==_--