[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

MiNT 1.09 extension: /dev/fd/*



This patch implements the /dev/fd directory, denoting the open file
descriptors of the current process. This is a generalisation of
/dev/std{in,out,err}.

I have implemented this for Bash-1.13, which uses it for process
substitution; unfortunately this doesn't work because of the blocking
fork() :-(. Anyway, i think this is a nice thing.

--- orig/biosfs.c	Tue Aug 17 21:23:18 1993
+++ biosfs.c	Sat Nov 20 19:50:40 1993
@@ -136,6 +136,7 @@
 	{"stdin", &fakedev, 0, 0, 0, 0},  /* handle 0 (stdin) */
 	{"stdout", &fakedev, 1, 0, 0, 0}, /* handle 1 (stdout) */
 	{"stderr", &fakedev, 2, 0, 0, 0}, /* handle 2 (stderr) */
+	{"fd", &fakedev, S_IFDIR, 0, 0, 0}, /* file descriptor directory */
 
 /* other miscellaneous devices */
 	{"mouse", &mouse_device, 0, 0, 0, 0},
@@ -157,6 +158,11 @@
 	{"", 0, 0, 0, 0, 0}
 };
 
+/* Does the fcookie fc refer to the \dev\fd directory? */
+#define IS_FD_DIR(fc) ((fc)->aux == S_IFDIR)
+/* Does the fcookie fc refer to a file in the \dev\fd directory? */
+#define IS_FD_ENTRY(fc) ((fc)->index > 0 && (fc)->index <= MAX_OPEN-MIN_HANDLE)
+
 struct bios_file *broot, *bdevlast;
 
 /* a file pointer for BIOS device 1, provided only for insurance
@@ -234,9 +240,41 @@
 	struct bios_file *b;
 
 	if (dir->index != 0) {
+	  /* Check for \dev\fd directory */
+	  if (!IS_FD_DIR (dir))
+	    {
 		DEBUG(("bios_lookup: bad directory"));
 		return EPTHNF;
+	    }
+	  if (!*name || (name[0] == '.' && name[1] == 0))
+	    {
+	      *fc = *dir;
+	      return 0;
+	    }
+	  if (!strcmp (name, ".."))
+	    {
+	      /* Root directory */
+	      fc->fs = &bios_filesys;
+	      fc->dev = dir->dev;
+	      fc->index = 0L;
+	      return 0;
+	    }
+	  if (isdigit (*name) || *name == '-')
+	    {
+	      int fd = (int) atol (name);
+	      if (fd >= MIN_HANDLE && fd < MAX_OPEN)
+		{
+		  fc->fs = &bios_filesys;
+		  fc->dev = dir->dev;
+		  fc->aux = fd;
+		  fc->index = fd - MIN_HANDLE + 1;
+		  return 0;
+		}
+	    }
+	  DEBUG (("bios_lookup: name(%s) not found", name));
+	  return EFILNF;
 	}
+
 /* special case: an empty name in a directory means that directory */
 /* so does "." */
 	if (!*name || (name[0] == '.' && name[1] == 0)) {
@@ -270,6 +308,7 @@
 {
 	FILEPTR *f;
 	struct bios_file *b = (struct bios_file *)fc->index;
+	long r;
 
 	xattr->index = fc->index;
 	xattr->dev = fc->dev;
@@ -279,18 +318,42 @@
 	xattr->blksize = 1;
 	xattr->mtime = xattr->atime = xattr->ctime = timestamp;
 	xattr->mdate = xattr->adate = xattr->cdate = datestamp;
-	if (fc->index == 0) {		/* root directory? */
+	if (fc->index == 0 || IS_FD_DIR (fc)) { /* root or fd directory? */
 		xattr->mode = S_IFDIR | DEFAULT_DIRMODE;
 		xattr->attr = FA_DIR;
+	}
+	else if (IS_FD_ENTRY (fc)) {
+	    /* u:\dev\fd\... */
+	    f = curproc->handle[(int) fc->aux];
+	    if (f)
+	      {
+		r = (*f->fc.fs->getxattr) (&f->fc, xattr);
+		if (r < 0)
+		  return r;
+#if 0
+		/* Not sure if needed. Try without it for now */
+		xattr->index = fc->index;
+		xattr->dev = fc->dev;
+#endif
+	      }
+	    else
+	      {
+		xattr->mode = S_IFCHR | DEFAULT_MODE;
+		xattr->attr = 0;
+	      }
 	} else if (b->device == 0) {	/* symbolic link? */
 		xattr->mode = S_IFLNK | DEFAULT_DIRMODE;
 	} else if (b->device == &fakedev &&
 		(f = curproc->handle[b->private]) != 0)
 	{
 	    /* u:\dev\stdin, u:\dev\stdout, etc. */
-	    (*f->fc.fs->getxattr) (&f->fc, xattr);
+	    r = (*f->fc.fs->getxattr) (&f->fc, xattr);
+	    if (r < 0)
+	      return r;
+#if 0
 	    xattr->index = fc->index;
 	    xattr->dev = fc->dev;
+#endif
 	} else {
 		xattr->mode = S_IFCHR | DEFAULT_MODE;
 		xattr->attr = 0;
@@ -357,7 +420,10 @@
 {
 	struct bios_file *b, **lastb;
 
-	UNUSED(dir);
+	/* Don't allow removal in the fd directory */
+	if (IS_FD_DIR (dir))
+	  return EACCDN;
+
 	lastb = &broot;
 	for (b = broot; b; b = *(lastb = &b->next)) {
 		if (!stricmp(b->name, name)) break;
@@ -382,12 +448,22 @@
 	fcookie *root, *dir; char *pathname;
 	int size;
 {
-	char *foo = ((struct bios_file *)dir->index)->name;
+	char *foo;
 
-	UNUSED(root);
-	if (dir->index == 0 && size > 0)
-		*pathname = 0;
-	else if (strlen(foo) < size)
+	if (size == 0)
+	  return ERANGE;
+	if (root->index == dir->index)
+	  {
+	    *pathname = 0;
+	    return 0;
+	  }
+	/* DIR must point to the fd directory */
+	if (!IS_FD_DIR (dir))
+	  return EINTRN;
+	*pathname++ = '\\';
+	size--;
+	foo = ((struct bios_file *)dir->index)->name;
+	if (strlen(foo) < size)
 		strcpy(pathname, foo);
 	else
 		return ERANGE;
@@ -401,18 +477,22 @@
 	fcookie *newdir;
 	const char *newname;
 {
-	struct bios_file *b;
-
-	UNUSED(olddir); UNUSED(newdir);
+	struct bios_file *b, *be = 0;
 
-/* BUG: we should check to see if "newname" already exists */
+	if (IS_FD_DIR (olddir) || IS_FD_DIR (newdir))
+	  return EACCDN;
 
 	for (b = broot; b; b = b->next) {
-		if (!stricmp(b->name, oldname)) {
-			strncpy(b->name, newname, BNAME_MAX);
-			return 0;
-		}
-	}
+		if (!stricmp(b->name, oldname))
+		  be = b;
+		else if (!stricmp (b->name, newname))
+		  return EACCDN;
+	}
+	if (be)
+	  {
+	    strncpy(be->name, newname, BNAME_MAX);
+	    return 0;
+	  }
 	return EFILNF;
 }
 
@@ -423,7 +503,7 @@
 {
 	UNUSED(flags);
 
-	if (dirh->fc.index != 0) {
+	if (dirh->fc.index != 0 && !IS_FD_DIR (&dirh->fc)) {
 		DEBUG(("bios_opendir: bad directory"));
 		return EPTHNF;
 	}
@@ -440,6 +520,31 @@
 	struct bios_file *b;
 	int giveindex = dirh->flags == 0;
 	int i;
+	char buf[5];
+
+	if (IS_FD_DIR (&dirh->fc))
+	  {
+	    i = dirh->index++;
+	    if (i + MIN_HANDLE >= MAX_OPEN)
+	      return ENMFIL;
+	    fc->fs = &bios_filesys;
+	    fc->index = i + 1;
+	    fc->aux = i + MIN_HANDLE;
+	    fc->dev = dirh->fc.dev;
+	    if (giveindex)
+	      {
+		namelen -= (int) sizeof (long);
+		if (namelen <= 0)
+		  return ERANGE;
+		*(long *) name = (long) i + 1;
+		name += sizeof (long);
+	      }
+	    ksprintf (buf, "%d", i + MIN_HANDLE);
+	    strncpy (name, buf, namelen-1);
+	    if (strlen (buf) >= namelen)
+	      return ENAMETOOLONG;
+	    return 0;
+	  }
 
 	b = broot;
 	i = dirh->index++;
@@ -551,7 +656,9 @@
 {
 	struct bios_file *b;
 
-	UNUSED(dir);
+	if (IS_FD_DIR (dir))
+	  return EINVFN;
+
 	if ((unsigned)cmd == DEV_INSTALL) {
 		struct dev_descr *d = (struct dev_descr *)arg;
 
@@ -609,6 +716,9 @@
 	long r;
 	fcookie fc;
 
+	if (IS_FD_DIR (dir))
+	  return EACCDN;
+
 	r = bios_lookup(dir, name, &fc);
 	if (r == 0) return EACCDN;	/* file already exists */
 	if (r != EFILNF) return r;	/* some other error */
@@ -640,6 +750,8 @@
 {
 	struct bios_file *b = (struct bios_file *)fc->index;
 
+	if (IS_FD_DIR (fc) || IS_FD_ENTRY (fc))
+	  return EINVFN;
 	if (!b) return EINVFN;
 	if (b->device) return EINVFN;
 
@@ -758,6 +870,13 @@
 {
 	struct bios_file *b;
 
+	/* Check for \dev\fd\... */
+	if (IS_FD_ENTRY (fc))
+	  {
+	    *devsp = (int) fc->aux;
+	    return &fakedev;
+	  }
+
 	b = (struct bios_file *)fc->index;
 
 	if (b->device && b->device != &fakedev)