/* * 'Ramfs': a (resizable) ramdisk file system * by Thierry Bousch * * We make the standing assumption that sizeof(int)==2, that all functions * pass their arguments on the stack, and that d0-d1/a0-a1 are the only * scratch registers. Oh well, you need an ANSI compiler too... * * Version: 1.1 (may 93) * Revision history: * 1.0 Added version number, and macro-ized TRACE so that it is possible * to compile with or without debug information. * 1.1 Added setuid, setgid and sticky bit for directories. Macro-ized * also DEBUG, ALERT and FATAL. */ #include #include "atarierr.h" #include "filesys.h" #define VERSION "1.1" /* * You may edit the following constants: * * RAMDRV drive identifier (here R:) * RAMFILE_MAX maximum length of a filename * BLKSIZE chunk size (must be a power of two) * * Define the symbols NO_{TRACE,DEBUG,ALERT,FATAL} to disable trace, * debug, alert and fatal calls, respectively. */ #define RAMDRV ('R'-'A') #define RAMFILE_MAX 29 #define BLKSIZE 512L #define NO_TRACE /* * this points to the structure that has all the useful functions that * the kernel told us about */ struct kerinfo *kernel; #define CCONWS (void)(*kernel->dos_tab[0x09]) #define RWABS (*kernel->bios_tab[4]) #define GETBPB (void *)(*kernel->bios_tab[7]) #define Timestamp (*kernel->dos_tab[0x2c]) #define Datestamp (*kernel->dos_tab[0x2a]) #define Domain() (*kernel->dos_tab[0x119])(-1) #define FreeMemory() (*kernel->dos_tab[0x48])(-1L) #define Getpid (*kernel->dos_tab[0x10b]) #define Getuid (*kernel->dos_tab[0x10f]) #define Getgid (*kernel->dos_tab[0x114]) #define Geteuid (*kernel->dos_tab[0x138]) #define Getegid (*kernel->dos_tab[0x139]) #define Kmalloc (*kernel->kmalloc) #define Kfree (*kernel->kfree) #define Stricmp (*kernel->stricmp) #define Strlwr (*kernel->strlwr) #define Unixtime (*kernel->unixtim) #define Dostime (*kernel->dostim) #define Denyshare (*kernel->denyshare) #define Denylock (*kernel->denylock) #ifndef NULL # define NULL ((void *)0L) #endif /* Useful macros */ #define IS_DIRECTORY(s) (((s)->mode & S_IFMT) == S_IFDIR) #define IS_SYMLINK(s) (((s)->mode & S_IFMT) == S_IFLNK) #define IS_SETUID(s) ((s)->mode & S_ISUID) #define IS_SETGID(s) ((s)->mode & S_ISGID) #define IS_STICKY(s) ((s)->mode & S_ISVTX) /* Conditional debugging */ #ifdef NO_DEBUG # define DEBUG(x) #else # define DEBUG(x) (*kernel->debug)x #endif #ifdef NO_ALERT # define ALERT(x) #else # define ALERT(x) (*kernel->alert)x #endif #ifdef NO_TRACE # define TRACE(x) #else # define TRACE(x) (*kernel->trace)x #endif #ifdef NO_FATAL # define FATAL(x) #else # define FATAL(x) (*kernel->fatal)x #endif /* Forward declarations of the file system functions */ long ram_root (int drv, fcookie *fc); long ram_lookup (fcookie *dir, char *name, fcookie *fc); long ram_creat (fcookie *dir, char *name, unsigned mode, int attrib, fcookie *fc); DEVDRV* ram_getdev (fcookie *fc, long *devsp); long ram_getxattr (fcookie *fc, XATTR *xattr); long ram_chattr (fcookie *fc, int attrib); long ram_chown (fcookie *fc, int uid, int gid); long ram_chmode (fcookie *fc, unsigned mode); long ram_mkdir (fcookie *fc, char *name, unsigned mode); long ram_rmdir (fcookie *dir, char *name); long ram_remove (fcookie *dir, char *name); long ram_getname (fcookie *root, fcookie *dir, char *pathname); long ram_rename (fcookie *olddir, char *oldname, fcookie *newdir, char *newname); long ram_opendir (DIR *dirh, int flags); long ram_readdir (DIR *dirh, char *nm, int nmlen, fcookie *fc); long ram_rewinddir (DIR *dirh); long ram_closedir (DIR *dirh); long ram_pathconf (fcookie *dir, int which); long ram_dfree (fcookie *dir, long *buf); long ram_writelabel (fcookie *dir, char *name); long ram_readlabel (fcookie *dir, char *name, int namelen); long ram_symlink (fcookie *dir, char *name, char *to); long ram_readlink (fcookie *dir, char *buf, int len); long ram_hardlink (fcookie *fromdir, char *fromname, fcookie *todir, char *toname); long ram_fscntl (fcookie *dir, char *name, int cmd, long arg); long ram_dskchng (int drv); /* Forward declarations of the device driver functions */ long ram_open (FILEPTR *f); long ram_write (FILEPTR *f, char *buf, long bytes); long ram_read (FILEPTR *f, char *buf, long bytes); long ram_lseek (FILEPTR *f, long where, int whence); long ram_ioctl (FILEPTR *f, int mode, void *buf); long ram_datime (FILEPTR *f, int *time, int rwflag); long ram_close (FILEPTR *f, int pid); long ram_select (FILEPTR *f, long p, int mode); void ram_unselect (FILEPTR *f, long p, int mode); /* * Here is the structure used for ram files. The "next" field points to * the following file/dir in that directory. The "up" field points to the * directory the file/dir is in, or NULL for the root directory. The * "down" field is only used by subdirectories and points to the first * entry in that subdirectory. "lst" is the list of open FILEPTRs for * this file. "length" is the actual length, "data" the actual data, and * "avail" is the length of the ram block allocated for "data". * The field "unlink" is non-null only when the file is marked as deleted * and must be removed on close. * * Note that all the memory is allocated in one block: it may cause trouble * with big files if the memory is fragmented. */ typedef struct ramfile { struct ramfile *next, *up, *down; char filename[RAMFILE_MAX+1]; int uid, gid, unlink; short time, date; unsigned mode; FILEPTR *lst; long length, avail; char *data; } RAMFILE; RAMFILE ramroot; DEVDRV ram_device = { ram_open, ram_write, ram_read, ram_lseek, ram_ioctl, ram_datime, ram_close, ram_select, ram_unselect }; FILESYS ram_filesys = { (FILESYS *)0, 0, ram_root, ram_lookup, ram_creat, ram_getdev, ram_getxattr, ram_chattr, ram_chown, ram_chmode, ram_mkdir, ram_rmdir, ram_remove, ram_getname, ram_rename, ram_opendir, ram_readdir, ram_rewinddir, ram_closedir, ram_pathconf, ram_dfree, ram_writelabel, ram_readlabel, ram_symlink, ram_readlink, ram_hardlink, ram_fscntl, ram_dskchng }; #define DRIVE_MAP *(unsigned long *)(0x4c2L) /* * This function is called by the kernel when the * file system is being loaded, and should return the file system * structure */ FILESYS *ram_init (struct kerinfo *k) { kernel = k; CCONWS("Ramdisk filesystem for MiNT (Version " VERSION ", compiled " __DATE__ ") by T.Bousch\r\n"); /* Add drive 'R' to the list of Bios drives */ DRIVE_MAP |= (1UL << RAMDRV); TRACE(("ram_init: initialize filesystem")); ramroot.next = ramroot.up = ramroot.down = NULL; ramroot.unlink = 0; ramroot.filename[0] = 0; ramroot.uid = ramroot.gid = 0; ramroot.time = Timestamp(); ramroot.date = Datestamp(); ramroot.mode = S_IFDIR | DEFAULT_DIRMODE; ramroot.lst = NULL; ramroot.length = ramroot.avail = 0L; ramroot.data = NULL; return &ram_filesys; } long ram_root (int drv, fcookie *fc) { if ((unsigned)drv == RAMDRV) { TRACE(("ram_root: drive %c: is a ramdisk", 'A' + RAMDRV)); fc->fs = &ram_filesys; fc->dev = drv; fc->index = (long) &ramroot; return 0; } else { fc->fs = NULL; /* Not our drive */ return EDRIVE; } } long ram_lookup (fcookie *dir, char *name, fcookie *fc) { RAMFILE *s, *d; TRACE(("ram_lookup: search name [%s]", name)); d = (RAMFILE *)dir->index; if (!d || !IS_DIRECTORY(d)) { DEBUG(("ram_lookup: bad directory")); return EPTHNF; } /* Empty name and "." are the directory itself */ if (!*name || !Stricmp(name, ".")) { *fc = *dir; return 0; } /* ".." could be a mount point */ if (!Stricmp(name, "..")) { s = d->up; if (s) { fc->index = (long)s; fc->fs = &ram_filesys; fc->dev = RAMDRV; return 0; } else { *fc = *dir; return EMOUNT; } } for (s = d->down; s; s = s->next) { if (!Stricmp(s->filename,name)) break; } if (!s) { DEBUG(("ram_lookup: name [%s] not found", name)); return EFILNF; } else { fc->index = (long)s; fc->fs = &ram_filesys; fc->dev = RAMDRV; } return 0; } long ram_getxattr (fcookie *fc, XATTR *xattr) { RAMFILE *s; TRACE(("ram_getxattr: get file attributes")); xattr->blksize = BLKSIZE; xattr->dev = RAMDRV; xattr->nlink = 1; s = (RAMFILE *)fc->index; xattr->index = (long)s; xattr->uid = s->uid; xattr->gid = s->gid; xattr->size = s->length; xattr->nblocks = (s->avail + BLKSIZE - 1) / BLKSIZE; xattr->mtime = xattr->ctime = xattr->atime = s->time; xattr->mdate = xattr->cdate = xattr->adate = s->date; xattr->mode = s->mode; xattr->attr = ((s->mode & (S_IWUSR|S_IWGRP|S_IWOTH)) ? 0 : FA_RDONLY) | (IS_DIRECTORY(s) ? FA_DIR : 0); return 0; } long ram_chattr (fcookie *fc, int attrib) { RAMFILE *s; TRACE(("ram_chattr: new attrib 0%o", attrib)); s = (RAMFILE *)fc->index; if (attrib & FA_RDONLY) { s->mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH); } else if ( !(s->mode & (S_IWUSR|S_IWGRP|S_IWOTH)) ) { s->mode |= (S_IWUSR|S_IWGRP|S_IWOTH); } return 0; } long ram_chown (fcookie *fc, int uid, int gid) { RAMFILE *s; TRACE(("ram_chown: new owner is %d.%d", uid, gid)); s = (RAMFILE *)fc->index; s->uid = uid; s->gid = gid; return 0; } long ram_chmode (fcookie *fc, unsigned mode) { RAMFILE *s; TRACE(("ram_chmode: new mode 0%o", mode)); s = (RAMFILE *)fc->index; s->mode = (s->mode & S_IFMT) | (mode & ~S_IFMT); return 0; } /* * This routine removes a file or directory marked as deleted if * nobody needs it anymore */ static void unlink (RAMFILE *s) { RAMFILE *d, *t, **old; if (s->lst == NULL && s->unlink != 0) { d = s->up; old = &d->down; for (t = d->down; t && t != s; t = t->next) old = &t->next; if (!t) { ALERT(("ram_unlink: file not found")); return; } *old = s->next; Kfree(s->data); Kfree(s); d->time = Timestamp(); d->date = Datestamp(); } } long ram_remove (fcookie *dir, char *name) { RAMFILE *d, *s; TRACE(("ram_remove: delete file [%s]", name)); d = (RAMFILE *)dir->index; for (s = d->down; s; s = s->next) { if (!Stricmp(s->filename, name)) break; } if (!s) { DEBUG(("ram_remove: file [%s] not found", name)); return EFILNF; } if (IS_DIRECTORY(s)) { DEBUG(("ram_remove: [%s] is a directory", name)); return EACCDN; } /* If d is sticky, check that we own the file */ if (IS_STICKY(d) && Geteuid() && s->uid != Getuid()) { DEBUG(("ram_remove: not owner")); return EACCDN; } s->unlink++; unlink(s); return 0; } long ram_getname (fcookie *root, fcookie *dir, char *pathname) { RAMFILE *s, *d; char buf[PATH_MAX]; *pathname = 0; /* empty string */ d = (RAMFILE *)root->index; s = (RAMFILE *)dir->index; while (s) { if (s == d) { TRACE(("ram_getname: returned [%s]", pathname)); return 0; } strcpy(buf, "\\"); strcat(buf, s->filename); strcat(buf, pathname); strcpy(pathname, buf); s = s->up; } DEBUG(("ram_getname: path not found")); return EPTHNF; /* not found */ } long ram_rename (fcookie *olddir, char *oldname, fcookie *newdir, char *newname) { RAMFILE *s, *d, *dold, *dnew, **old; TRACE(("ram_rename: mv %s %s", oldname, newname)); /* Verify that "newname" doesn't exist */ dnew = (RAMFILE *)newdir->index; for (s = dnew->down; s; s = s->next) if (!Stricmp(s->filename, newname)) { DEBUG(("ram_rename: file already exists")); return EACCDN; } /* Verify that "oldname" exists */ dold = (RAMFILE *)olddir->index; old = &dold->down; for (s = dold->down; s; s = s->next) if (!Stricmp(s->filename, oldname)) break; else old = &s->next; if (!s) { DEBUG(("ram_rename: file not found")); return EFILNF; } /* Verify that "newdir" is not a subdirectory of "name" */ for (d = dnew; d; d = d->up) if (d == s) { DEBUG(("ram_rename: invalid move")); return EACCDN; } strncpy(s->filename, newname, RAMFILE_MAX); s->filename[RAMFILE_MAX] = 0; if (dold != dnew) { /* Rename across directories */ TRACE(("ram_rename: move across directories")); *old = s->next; s->next = dnew->down; dnew->down = s; s->up = dnew; } dold->time = dnew->time = Timestamp(); dold->date = dnew->date = Datestamp(); return 0; } long ram_opendir (DIR *dirh, int flags) { RAMFILE *d; TRACE(("ram_opendir: open directory")); dirh->index = 0; d = (RAMFILE *)dirh->fc.index; *(RAMFILE **)(&dirh->fsstuff) = d->down; /* next file */ return 0; } long ram_rewinddir (DIR *dirh) { RAMFILE *d; TRACE(("ram_rewinddir: rewind directory")); dirh->index = 0; d = (RAMFILE *)dirh->fc.index; *(RAMFILE **)(&dirh->fsstuff) = d->down; /* next file */ return 0; } long ram_closedir (DIR *dirh) { TRACE(("ram_closedir: close directory")); return 0; } long ram_readdir (DIR *dirh, char *name, int namelen, fcookie *fc) { int i; int giveindex = (dirh->flags == 0); RAMFILE *s; char *Filename; i = dirh->index++; s = (RAMFILE *)dirh->fc.index; /* Current directory */ if (i == 0) { /* The "." entry is the first one */ Filename = "."; } else if (i == 1 && s->up != NULL) { /* The ".." entry is the second one */ s = s->up; Filename = ".."; } else { /* Any regular entry */ s = *(RAMFILE **)(&dirh->fsstuff); if (!s) { TRACE(("ram_readdir: no more files")); return ENMFIL; } *(RAMFILE **)(&dirh->fsstuff) = s->next; Filename = s->filename; } TRACE(("ram_readdir: entry %d: %s", i, Filename)); fc->index = (long)s; fc->fs = &ram_filesys; fc->dev = RAMDRV; if (giveindex) { namelen -= (int)sizeof(long); if (namelen <= 0) return ERANGE; *((long *)name) = (long)s; name += sizeof(long); } if (namelen <= strlen(Filename)) { DEBUG(("ram_readdir: name too long")); return ENAMETOOLONG; } strcpy(name, Filename); return 0; } long ram_pathconf (fcookie *dir, int which) { TRACE(("ram_pathconf: limit %d", which)); switch(which) { case -1: return DP_MAXREQ; case DP_IOPEN: return UNLIMITED; /* no internal limit on open files */ case DP_MAXLINKS: return 1; /* we don't have hard links */ case DP_PATHMAX: return PATH_MAX; /* max. path length */ case DP_NAMEMAX: return RAMFILE_MAX; /* max. length of individual name */ case DP_ATOMIC: return UNLIMITED; /* all writes are atomic */ case DP_TRUNC: return DP_AUTOTRUNC; /* file names are truncated */ default: DEBUG(("ram_pathconf: invalid parameter")); return EINVFN; } } /* * The following (recursive) function calculates the total size of a * file or directory */ static long mem_used (RAMFILE *d) { long used = 0L; RAMFILE *s; if (!IS_DIRECTORY(d)) return d->avail; /* If it's not a regular file or a symbolic link, then */ for (s = d->down; s; s = s->next) used += mem_used(s); return used; } long ram_dfree (fcookie *dir, long *buf) { long memfree, memused; TRACE(("ram_dfree: getting free disk space")); memfree = FreeMemory(); memused = mem_used(&ramroot); *buf++ = memfree / BLKSIZE; /* free blocks */ *buf++ = (memfree + memused) / BLKSIZE; /* total nb of blocks */ *buf++ = BLKSIZE; /* sector size */ *buf = 1; /* 1 sector per block */ return 0; } long ram_writelabel (fcookie *dir, char *name) { DEBUG(("ram_writelabel: not implemented")); return EINVFN; } long ram_readlabel (fcookie *dir, char *name, int namelen) { DEBUG(("ram_readlabel: not implemented")); return EINVFN; } long ram_hardlink (fcookie *fromdir, char *fromname, fcookie *todir, char *toname) { DEBUG(("ram_hardlink: invalid function")); return EINVFN; } long ram_fscntl (fcookie *dir, char *name, int cmd, long arg) { DEBUG(("ram_fscntl: nothing available")); return EINVFN; /* Nothing for now */ } long ram_dskchng (int drv) { TRACE(("ram_dskchng: ram disk changed ?")); return 0; /* No media change on a ram disk! */ } DEVDRV *ram_getdev (fcookie *fc, long *devsp) { RAMFILE *s; TRACE(("ram_getdev: find device driver")); s = (RAMFILE *)fc->index; *devsp = (long)s; return &ram_device; } /* * Create a ram file. This function is used for regular files _and_ * directories */ static long create_ram_file (fcookie *dir, char *name, unsigned mode, fcookie *fc) { RAMFILE *s, *d; TRACE(("create_ram_file: file [%s] mode 0%o", name, mode)); /* Does this name already exist ? */ d = (RAMFILE *)dir->index; for (s = d->down; s; s = s->next) { if (!Stricmp(s->filename, name)) { DEBUG(("create_ram_file: file exists")); return EACCDN; } } /* The names "", "." and ".." are reserved */ if (!*name || !Stricmp(name, ".") || !Stricmp(name, "..")) { DEBUG(("create_ram_file: invalid filename")); return EACCDN; } s = (RAMFILE *)Kmalloc(sizeof(RAMFILE)); if (!s) { ALERT(("create_ram_file: out of memory")); return ENSMEM; } strncpy(s->filename, name, RAMFILE_MAX); s->filename[RAMFILE_MAX] = 0; /* * If the directory has the bits Setuid or Setgid set, then the * file inherits the uid or gid of its parent: */ s->uid = IS_SETUID(d) ? d->uid : Getuid(); s->gid = IS_SETGID(d) ? d->gid : Getgid(); s->mode = mode; s->lst = NULL; s->length = s->avail = 0L; s->data = NULL; s->time = d->time = Timestamp(); s->date = d->date = Datestamp(); s->next = d->down; d->down = s; s->down = NULL; s->up = d; s->unlink = 0; fc->fs = &ram_filesys; fc->index = (long)s; fc->dev = dir->dev; return 0; } long ram_creat (fcookie *dir, char *name, unsigned mode, int attrib, fcookie *fc) { TRACE(("ram_creat: create regular file")); return create_ram_file (dir, name, mode|S_IFREG, fc); } long ram_mkdir (fcookie *fc, char *name, unsigned mode) { fcookie Dummy; TRACE(("ram_mkdir: make directory")); return create_ram_file (fc, name, mode|S_IFDIR, &Dummy); } long ram_rmdir (fcookie *dir, char *name) { RAMFILE *d, *s; TRACE(("ram_rmdir: remove directory [%s]", name)); d = (RAMFILE *)dir->index; for (s = d->down; s; s = s->next) { if (!Stricmp(s->filename, name)) break; } if (!s) { DEBUG(("ram_rmdir: directory [%s] not found", name)); return EFILNF; } if (!IS_DIRECTORY(s) && !IS_SYMLINK(s)) { DEBUG(("ram_rmdir: [%s] isn't a directory", name)); return EACCDN; } if (IS_DIRECTORY(s) && s->down) { DEBUG(("ram_rmdir: directory [%s] isn't empty", name)); return EACCDN; } /* If d is sticky, check that we own the subdirectory */ if (IS_STICKY(d) && Geteuid() && s->uid != Getuid()) { DEBUG(("ram_rmdir: not owner")); return EACCDN; } s->unlink++; unlink(s); return 0; } long ram_symlink (fcookie *dir, char *name, char *to) { RAMFILE *s; fcookie Fc; long ret, len; TRACE(("ram_symlink: create symbolic link")); ret = create_ram_file (dir, name, 0777|S_IFLNK, &Fc); if (ret == 0) { s = (RAMFILE *)Fc.index; len = strlen(to) + 1; s->data = Kmalloc(len); if (!s->data) { ALERT(("ram_symlink: out of memory")); s->unlink++; unlink(s); return ENSMEM; } s->length = s->avail = len; strcpy(s->data, to); } return ret; } long ram_readlink (fcookie *dir, char *buf, int len) { RAMFILE *s; s = (RAMFILE *)dir->index; if (!IS_SYMLINK(s)) { DEBUG(("ram_readlink: not a symbolic link")); return EACCDN; } if (s->length > len) { DEBUG(("ram_readlink: name too long")); return ENAMETOOLONG; } strcpy(buf, s->data); TRACE(("ram_readlink: returned [%s]", buf)); return 0; } /* * The ram disk driver */ static void enlarge_ramfile (RAMFILE *s, long new_size) { char *data2; long quantum; /* We choose bigger blocks for big files */ quantum = (new_size > 16*BLKSIZE ? 4 : 1) * BLKSIZE; /* * Round to the next multiple of quantum; we assume that * quantum is a power of two !! */ new_size = (new_size + quantum - 1) & ~(quantum - 1); data2 = (char *)Kmalloc(new_size); if (data2) { bcopy(s->data, data2, s->length); Kfree(s->data); s->data = data2; s->avail = new_size; } else ALERT(("enlarge_ramfile: out of memory")); } long ram_open (FILEPTR *f) { RAMFILE *s; TRACE(("ram_open: open file")); s = (RAMFILE *)f->devinfo; /* Check the sharing mode */ if (Denyshare(s->lst, f)) { DEBUG(("ram_open: sharing modes conflict")); return EACCDN; } if (f->flags & O_TRUNC) { /* truncate the file */ if (s->lst) { /* Can it happen ? */ ALERT(("ram_open: O_TRUNC without O_EXCL")); return EACCDN; } else { Kfree(s->data); s->length = s->avail = 0L; s->data = 0; } } f->next = s->lst; s->lst = f; return 0; } long ram_close (FILEPTR *f, int pid) { RAMFILE *s; FILEPTR **old, *g; TRACE(("ram_close: close file")); if (f->links == 0) { s = (RAMFILE *)f->devinfo; old = &(s->lst); for (g = s->lst; g; g = g->next) { if (g == f) break; old = &(g->next); } if (g == NULL) ALERT(("ram_close: FILEPTR not found")); else *old = f->next; unlink(s); } return 0; } long ram_write (FILEPTR *f, char *buf, long nbytes) { RAMFILE *s; long new_size; s = (RAMFILE *)f->devinfo; new_size = nbytes + f->pos; if (new_size > s->avail) enlarge_ramfile(s, new_size); /* Hope that the file is big enough now */ if (new_size > s->avail) nbytes = s->avail - f->pos; /* Copy the data */ TRACE(("ram_write: %ld bytes from pos %ld", nbytes, f->pos)); bcopy(buf, s->data + f->pos, nbytes); /* Update the file status */ f->pos += nbytes; if (f->pos > s->length) s->length = f->pos; s->time = Timestamp(); s->date = Datestamp(); return nbytes; } long ram_read (FILEPTR *f, char *buf, long nbytes) { RAMFILE *s; s = (RAMFILE *)f->devinfo; if (nbytes + f->pos > s->length) nbytes = s->length - f->pos; /* Copy the data */ TRACE(("ram_read: %ld bytes from pos %ld", nbytes, f->pos)); bcopy(s->data + f->pos, buf, nbytes); f->pos += nbytes; return nbytes; } /* File locking code not yet implemented */ long ram_ioctl (FILEPTR *f, int mode, void *buf) { TRACE(("ram_ioctl: mode %d", mode)); if (mode == FIONREAD || mode == FIONWRITE) { *((long *)buf) = 1; return 0; } else if (mode == F_SETLK || mode == F_GETLK) { DEBUG(("ram_ioctl: locking not implemented")); return EINVFN; } DEBUG(("ram_ioctl: invalid function")); return EINVFN; } long ram_lseek(FILEPTR *f, long where, int whence) { RAMFILE *s; long newpos; TRACE(("ram_lseek: goto %d, mode %d", where, whence)); s = (RAMFILE *)f->devinfo; switch(whence) { case 0: newpos = where; break; case 1: newpos = f->pos + where; break; case 2: newpos = s->length - where; break; default: DEBUG(("ram_lseek: invalid mode")); return EINVFN; } if (newpos < 0 || newpos > s->length) { TRACE(("ram_lseek: out of range")); return ERANGE; } f->pos = newpos; return newpos; } long ram_datime (FILEPTR *f, int *timeptr, int rwflag) { RAMFILE *s; s = (RAMFILE *)f->devinfo; if (rwflag) { TRACE(("ram_datime: set time and date")); s->time = *timeptr++; s->date = *timeptr; } else { TRACE(("ram_datime: get time and date")); *timeptr++ = s->time; *timeptr = s->date; } return 0; } long ram_select (FILEPTR *f, long p, int mode) { TRACE(("ram_select: always ready")); return 1; /* We're always ready */ } void ram_unselect (FILEPTR *f, long p, int mode) { TRACE(("ram_unselect: nothing to do")); /* Nothing for us to do */ }