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

[MiNT] New MiNTlib & FreeMiNT functions



Here's the patches to add fdopendir/fchdir/dirfd support to FreeMiNT and
MiNTlib.

There's also support for...

* Opening directories read-only using the standard open call (this was
really a bug before and now it's fixed). This also needs updated
filesystem drivers (patches included for those)

* O_DIRECTORY, O_NOFOLLOW & O_NOATIME support, again filesystem driver
updates are needed here for those that can support it (patches included)

Let me know if anyone can spot any problems with these. But I've been
testing coreutils with them and all is pretty good at the moment.

Thanks,

Alan.


Index: dirent/SRCFILES
===================================================================
RCS file: /mint/mintlib/dirent/SRCFILES,v
retrieving revision 1.1
diff -u -r1.1 SRCFILES
--- dirent/SRCFILES	18 Jan 2001 02:17:08 -0000	1.1
+++ dirent/SRCFILES	22 Feb 2008 09:43:50 -0000
@@ -7,6 +7,8 @@
 SRCFILES = \
 	alphasort.c \
 	closedir.c \
+	dirfd.c \
+	fdopendir.c \
 	opendir.c \
 	readdir.c \
 	scandir.c \
Index: include/unistd.h
===================================================================
RCS file: /mint/mintlib/include/unistd.h,v
retrieving revision 1.11
diff -u -r1.11 unistd.h
--- include/unistd.h	6 Dec 2005 19:08:17 -0000	1.11
+++ include/unistd.h	22 Feb 2008 09:43:50 -0000
@@ -392,12 +392,10 @@
 extern int __chdir (__const char *__path) __THROW;
 
 #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
-#ifndef __MINT__
 /* Change the process's working directory to the one FD is open on.  */
 extern int fchdir (int __fd) __THROW;
 extern int __fchdir (int __fd) __THROW;
 #endif
-#endif
 
 /* Get the pathname of the current working directory,
    and put it in SIZE bytes of BUF.  Returns NULL if the
Index: include/bits/fcntl.h
===================================================================
RCS file: /mint/mintlib/include/bits/fcntl.h,v
retrieving revision 1.1
diff -u -r1.1 fcntl.h
--- include/bits/fcntl.h	19 Jul 2001 21:00:50 -0000	1.1
+++ include/bits/fcntl.h	22 Feb 2008 09:43:50 -0000
@@ -36,6 +36,12 @@
 #define	O_EXCL		0x800		/* error if file exists */
 #define O_NOCTTY	0x4000		/* do not open new controlling tty */
 
+#ifdef __USE_GNU
+# define O_DIRECTORY	0x10000		/* Must be a directory.	 */
+# define O_NOFOLLOW	0x20000		/* Do not follow links.	 */
+# define O_NOATIME	0x40000		/* Do not set atime.  */
+#endif
+
 /* File status flags for `open' and `fcntl'.  */
 #define	O_APPEND	0x1000		/* position at EOF */
 #define _REALO_APPEND	0x08		/* this is what MiNT uses */
Index: include/mint/mintbind.h
===================================================================
RCS file: /mint/mintlib/include/mint/mintbind.h,v
retrieving revision 1.14
diff -u -r1.14 mintbind.h
--- include/mint/mintbind.h	22 Dec 2005 09:35:54 -0000	1.14
+++ include/mint/mintbind.h	22 Feb 2008 09:43:50 -0000
@@ -606,6 +606,12 @@
 /* 0x17f */
 #define Fchown16(name, uid, gid, follow_links) \
 		trap_1_wlwww(0x180, (long)(name), (short)(uid), (short)(gid), (short)follow_links)
+#define Fchdir(fh) \
+		trap_1_ww(0x181, (short)(fh))
+#define Ffdopendir(fh) \
+		trap_1_ww(0x182, (short)(fh))
+#define Fdirfd(handle) \
+		trap_1_wl(0x183, (long)(handle))
 
 __END_DECLS
 
Index: include/sys/dirent.h
===================================================================
RCS file: /mint/mintlib/include/sys/dirent.h,v
retrieving revision 1.4
diff -u -r1.4 dirent.h
--- include/sys/dirent.h	14 Mar 2002 20:48:59 -0000	1.4
+++ include/sys/dirent.h	22 Feb 2008 09:43:50 -0000
@@ -69,6 +69,14 @@
 extern DIR *__opendir (__const char *__name) __THROW;
 extern DIR *opendir (__const char *__name) __THROW;
 
+#ifdef __USE_GNU
+/* Same as opendir, but open the stream on the file descriptor FD.
+
+   This function is a possible cancellation point and therefore not
+   marked with __THROW.  */
+extern DIR *fdopendir (int __fd);
+#endif
+
 /* Close the directory stream DIRP.
    Return 0 if successful, -1 if not.  */
 extern int __closedir (DIR *__dirp) __THROW;
@@ -104,6 +112,9 @@
 
 #if defined __USE_BSD || defined __USE_MISC
 
+/* Return the file descriptor used by DIRP.  */
+extern int dirfd (DIR *__dirp) __THROW __nonnull ((1));
+
 /* Scan the directory DIR, calling SELECTOR on each directory entry.
    Entries for which SELECT returns nonzero are individually malloc'd,
    sorted using qsort with CMP, and collected in a malloc'd array in
Index: syscall/syscalls.master
===================================================================
RCS file: /mint/mintlib/syscall/syscalls.master,v
retrieving revision 1.4
diff -u -r1.4 syscalls.master
--- syscall/syscalls.master	22 Dec 2005 09:37:57 -0000	1.4
+++ syscall/syscalls.master	22 Feb 2008 09:43:52 -0000
@@ -518,9 +518,9 @@
 
 0x180	Fchown16	(const char *name, short uid, short gid,
 			 short follow) /* since 1.16 */
-0x181	undefined
-0x182	undefined
-0x183	undefined
+0x181	Fchdir		(short fd) /* since 1.17 */
+0x182	Ffdopendir	(short fd) /* since 1.17 */
+0x183	Fdirfd		(long handle) /* since 1.17 */
 0x184	undefined
 0x185	undefined
 0x186	undefined
Index: unix/SRCFILES
===================================================================
RCS file: /mint/mintlib/unix/SRCFILES,v
retrieving revision 1.13
diff -u -r1.13 SRCFILES
--- unix/SRCFILES	16 Jan 2004 11:15:27 -0000	1.13
+++ unix/SRCFILES	22 Feb 2008 09:43:53 -0000
@@ -18,6 +18,7 @@
 	dup.c \
 	dup2.c \
 	execve.c \
+	fchdir.c \
 	fchmod.c \
 	fchown.c \
 	fcntl.c \
Index: unix/open.c
===================================================================
RCS file: /mint/mintlib/unix/open.c,v
retrieving revision 1.6
diff -u -r1.6 open.c
--- unix/open.c	6 Dec 2005 19:28:07 -0000	1.6
+++ unix/open.c	22 Feb 2008 09:43:53 -0000
@@ -110,21 +110,34 @@
 		modemask = O_ACCMODE;
 	}
 	
-	rv = __quickstat (filename, &sb, 0);
+	if (iomode & O_NOFOLLOW)
+		rv = __quickstat (filename, &sb, 1);
+	else
+		rv = __quickstat (filename, &sb, 0);
+
 	/* The code used to call Fstat.  Emulate this here.  */
 	if (rv != 0)
 		rv = -errno;
 	
 	if (rv == 0)		/* file exists */
 	{
-		if (S_ISDIR (sb.st_mode)) {
-	    		/* FIXME: It is actually not forbidden to open a 
-	    		   directory for reading only.  What should we return 
-	    		   then?  */
-	    		__set_errno (EISDIR);
-	    		return -1;
+		if (S_ISLNK (sb.st_mode) && (iomode & O_NOFOLLOW)) {
+			__set_errno(ELOOP);
+			return -1;
 		}
 		
+		if (S_ISDIR (sb.st_mode)) {
+			if ((iomode & O_ACCMODE) != O_RDONLY) {
+	    			__set_errno (EISDIR);
+	    			return -1;
+			}
+		} else {
+			if (iomode & O_DIRECTORY) {
+				__set_errno(ENOTDIR);
+				return -1;
+			}
+		}
+
 		if ((iomode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
 			__set_errno (EEXIST);
 			/* return __SMALLEST_VALID_HANDLE - 1; */
--- /dev/null	2008-02-19 08:39:24.529481651 +0000
+++ dirent/fdopendir.c	2008-02-22 09:51:46.605614796 +0000
@@ -0,0 +1,39 @@
+/*
+ * Ffdopendir implemented by Alan Hourihane <alanh@fairlite.co.uk>
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <limits.h>
+#include <dirent.h>
+#include <errno.h>
+#include <mint/mintbind.h>
+#include "lib.h"
+
+DIR *
+__fdopendir (int fd)
+{
+	DIR *d;
+	long r;
+
+	d = malloc(sizeof(DIR));
+	if (!d) {
+		__set_errno (ENOMEM);
+		return d;
+	}
+
+	r = Ffdopendir(fd);
+	if (r < 0) {
+		free(d);
+		__set_errno(-r);
+		return NULL;
+	}
+
+	d->handle = r;
+	d->buf.d_off = 0;
+	d->status = 0;
+
+	return d;
+}
+weak_alias (__fdopendir, fdopendir)
--- /dev/null	2008-02-19 08:39:24.529481651 +0000
+++ dirent/dirfd.c	2008-02-22 09:52:36.011614852 +0000
@@ -0,0 +1,33 @@
+/*
+ * Fdirfd implemented by Alan Hourihane <alanh@fairlite.co.uk>
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <limits.h>
+#include <dirent.h>
+#include <errno.h>
+#include <mint/mintbind.h>
+#include "lib.h"
+
+int
+__dirfd (DIR *dir)
+{
+	int r;
+	
+	if (!dir) {
+		__set_errno(EBADF);
+		return -1;
+	}
+
+	r = Fdirfd(dir->handle);
+
+	if (r < 0) {
+		__set_errno(-r);
+		return -1;
+	}
+
+	return r;
+}
+weak_alias (__dirfd, dirfd)
--- /dev/null	2008-02-19 08:39:24.529481651 +0000
+++ unix/fchdir.c	2008-02-22 09:51:27.179614750 +0000
@@ -0,0 +1,31 @@
+/*
+ * Fchdir implemented by Alan Hourihane <alanh@fairlite.co.uk>
+ */
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <support.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <mint/mintbind.h>
+
+#include "lib.h"
+
+int
+__fchdir (int fd)
+{
+	int r = Fchdir(fd);
+
+	if (r < 0) {
+		__set_errno(-r);
+		return -1;
+	}
+
+	return 0;
+}
+weak_alias (__fchdir, fchdir)
Index: sys/dosdir.c
===================================================================
RCS file: /mint/freemint/sys/dosdir.c,v
retrieving revision 1.27
diff -u -r1.27 dosdir.c
--- sys/dosdir.c	13 Jul 2007 21:32:48 -0000	1.27
+++ sys/dosdir.c	22 Feb 2008 09:38:48 -0000
@@ -1389,6 +1389,22 @@
 
 	if (dirh->fc.fs)
 	{
+		int i;
+
+		/* If we've assigned a file descriptor to this cookie from
+		 * Fdirfd, then we need to ensure we close it now too.
+		 */
+		for (i = MIN_HANDLE; i < p->p_fd->nfiles; i++)
+		{
+			FILEPTR *f = p->p_fd->ofiles[i];
+
+			if (f && f->fc.index == dirh->fc.index &&
+				 f->fc.dev == dirh->fc.dev) {
+				do_close(p, f);
+				DEBUG (("Removing file descriptor %d", i));
+				FD_REMOVE (p, i);
+			}
+		}
 		r = xfs_closedir (dirh->fc.fs, dirh);
 		release_cookie (&dirh->fc);
 	}
@@ -2086,3 +2102,240 @@
 	release_cookie (&fc);
 	return r;
 }
+
+/*
+ * GEMDOS extension: Fchdir(fd)
+ *
+ * sets the current directory from a file descriptor
+ */
+long _cdecl
+sys_f_chdir (short fd)
+{
+	struct proc *p = get_curproc();
+	FILEPTR	*f;
+	XATTR xattr;
+	int drv;
+	struct cwd *cwd = p->p_cwd;
+	long r;
+
+	r = GETFILEPTR (&p, &fd, &f);
+	if (r) return r;
+
+	if (!(f->fc.fs))
+	{
+		DEBUG (("Ffchdir: not a valid filesystem"));
+		return ENOSYS;
+	}
+
+	r = xfs_getxattr (f->fc.fs, &(f->fc), &xattr);
+	if (r)
+	{
+		DEBUG (("Ffchdir(%i): couldn't get directory attributes", fd));
+		return r;
+	}
+
+	if (!(xattr.attr & FA_DIR))
+	{
+		DEBUG (("Ffchdir(%i): not a directory", fd));
+		return ENOTDIR;
+	}
+
+	if (denyaccess (p->p_cred->ucr, &xattr, S_IXOTH))
+	{
+		DEBUG (("Ffchdir(%i): access denied", fd));
+		return EACCES;
+	}
+
+	/* watch out for symbolic links; if c:\foo is a link to d:\bar, then
+	 * "cd c:\foo" should also change the drive to d:
+	 */
+	drv = cwd->curdrv;
+	if (drv != UNIDRV && f->fc.dev != cwd->root[drv].dev)
+	{
+		int i;
+
+		for (i = 0; i < NUM_DRIVES; i++)
+		{
+			if (cwd->root[i].dev == f->fc.dev
+				&& cwd->root[i].fs == f->fc.fs)
+			{
+				if (cwd->curdrv == drv)
+					cwd->curdrv = i;
+
+				drv = i;
+				break;
+			}
+		}
+	}
+
+	release_cookie (&cwd->curdir[drv]);
+	dup_cookie(&cwd->curdir[drv], &f->fc);
+
+	return E_OK;
+}
+
+/*
+ * GEMDOS extension: fdopendir
+ *
+ * opendir with a file descriptor
+ */
+long _cdecl
+sys_f_opendir (short fd)
+{
+	struct proc *p = get_curproc();
+	FILEPTR	*f;
+	fcookie *dir;
+	long r;
+	DIR *dirh;
+	ushort mode;
+
+	r = GETFILEPTR (&p, &fd, &f);
+	if (r) return r;
+
+	if (!(f->fc.fs))
+	{
+		DEBUG (("Ffdopendir: not a valid filesystem"));
+		return ENOSYS;
+	}
+
+	dir = &(f->fc);
+	r = dir_access (p->p_cred->ucr, dir, S_IROTH, &mode);
+	if (r)
+	{
+		DEBUG (("Ffdopendir(%i): read permission denied", fd));
+		return r;
+	}
+
+	dirh = kmalloc (sizeof (*dirh));
+	if (!dirh)
+	{
+		DEBUG (("Ffdopendir(%i): out of memory", fd));
+		return ENOMEM;
+	}
+
+	dup_cookie(&dirh->fc, dir);
+	dirh->index = 0;
+	dirh->flags = 0;
+	r = xfs_opendir (dirh->fc.fs, dirh, dirh->flags);
+	if (r)
+	{
+		DEBUG (("Ffdopendir(%i): fdopendir returned %ld", fd, r));
+		kfree (dirh);
+		return r;
+	}
+
+	/* we keep a chain of open directories so that if a process
+	 * terminates without closing them all, we can clean up
+	 */
+	dirh->next = p->p_fd->searches;
+	p->p_fd->searches = dirh;
+
+	assert(((long) dirh) > 0);
+	return (long) dirh;
+}
+
+/*
+ * GEMDOS extension: fdirfd
+ *
+ * a file descriptor from DIR*
+ */
+long _cdecl
+sys_f_dirfd (long handle)
+{
+	struct proc *p = get_curproc();
+	DIR *dirh = (DIR *)handle;
+	FILEPTR *fp = NULL;
+	short fd = MIN_OPEN - 1;
+	DIR **where;
+	long r;
+	long devsp;
+	DEVDRV *dev;
+
+	where = &p->p_fd->searches;
+	while (*where && *where != dirh)
+		where = &((*where)->next);
+
+	if (!*where)
+	{
+		DEBUG (("Fdirfd: not an open directory"));
+		return EBADF;
+	}
+
+	if (!dirh->fc.fs)
+	{
+		DEBUG (("Fdirfd: not a valid filesystem"));
+		return EBADF;
+	}
+
+	/* locate previously handed fd */
+	{
+		int i;
+
+		/* If we've assigned a file descriptor to this cookie from
+		 * Fdirfd, then we can hand back the same descriptor.
+		 */
+		for (i = MIN_HANDLE; i < p->p_fd->nfiles; i++)
+		{
+			FILEPTR *f = p->p_fd->ofiles[i];
+
+			if (f && f->fc.index == dirh->fc.index &&
+				 f->fc.dev == dirh->fc.dev) {
+
+				DEBUG(("Same descriptor %d found",i));
+
+				return i;
+			}
+		}
+	}
+
+	dev = xfs_getdev (dirh->fc.fs, &dirh->fc, &devsp);
+	if (!dev)
+	{
+		DEBUG (("Fdirfd: device driver not found (%li)", devsp));
+		return devsp ? devsp : EINTERNAL;
+	}
+
+	r = FD_ALLOC (p, &fd, MIN_OPEN);
+	if (r) goto error;
+
+	r = FP_ALLOC (p, &fp);
+	if (r) goto error;
+
+	if (dev == &fakedev)
+	{
+		/* fake BIOS devices */
+		FILEPTR *fpfake;
+
+		assert (p->p_fd);
+
+		fpfake = p->p_fd->ofiles[devsp];
+		if (!fpfake || fpfake == (FILEPTR *) 1) {
+			r = EBADF;
+			goto error;
+		}
+
+		fpfake->links--;
+		FP_FREE (fp);
+
+		fp = fpfake;
+		fpfake->links++;
+	} else {
+		fp->links = 1;
+		fp->flags = O_RDONLY;
+		fp->pos = 0;
+		fp->devinfo = devsp;
+		fp->dev = dev;
+		dup_cookie(&fp->fc, &dirh->fc);
+	}
+
+	/* activate the fp, default is to close non-standard files on exec */
+	FP_DONE (p, fp, fd, FD_CLOEXEC);
+
+	return fd;
+
+error:
+	if (fd >= MIN_OPEN) FD_REMOVE (p, fd);
+	if (fp) { fp->links--; FP_FREE (fp); }
+
+	return r;
+}
Index: sys/dosdir.h
===================================================================
RCS file: /mint/freemint/sys/dosdir.h,v
retrieving revision 1.7
diff -u -r1.7 dosdir.h
--- sys/dosdir.h	8 Dec 2004 11:29:12 -0000	1.7
+++ sys/dosdir.h	22 Feb 2008 09:38:48 -0000
@@ -52,6 +52,9 @@
 long _cdecl sys_d_writelabel 	(const char *path, const char *label);
 long _cdecl sys_d_chroot	(const char *dir);
 long _cdecl sys_f_stat64	(int flag, const char *name, STAT *stat);
+long _cdecl sys_f_chdir		(short fd);
+long _cdecl sys_f_opendir	(short fd);
+long _cdecl sys_f_dirfd		(long handle);
 
 
 # endif /* _dosdir_h */
Index: sys/fatfs.c
===================================================================
RCS file: /mint/freemint/sys/fatfs.c,v
retrieving revision 1.42
diff -u -r1.42 fatfs.c
--- sys/fatfs.c	13 Jul 2007 21:32:48 -0000	1.42
+++ sys/fatfs.c	22 Feb 2008 09:38:49 -0000
@@ -8073,9 +8073,9 @@
 		return EACCES;
 	}
 
-	if (c->info.attr & FA_LABEL || c->info.attr & FA_DIR)
+	if (c->info.attr & FA_LABEL || ((c->info.attr & FA_DIR) && ((f->flags & O_RWMODE) != O_RDONLY)))
 	{
-		FAT_DEBUG (("fatfs_open: leave failure, not a valid file"));
+		FAT_DEBUG (("fatfs_open: leave failure, not a valid file or read-only directory"));
 		return EACCES;
 	}
 
Index: sys/k_fds.c
===================================================================
RCS file: /mint/freemint/sys/k_fds.c,v
retrieving revision 1.20
diff -u -r1.20 k_fds.c
--- sys/k_fds.c	13 Jul 2007 21:32:48 -0000	1.20
+++ sys/k_fds.c	22 Feb 2008 09:38:50 -0000
@@ -362,9 +366,9 @@
 
 	DEBUG(("do_open(%s): mode 0x%x", name, xattr.mode));
 
-	/* we don't do directories
+	/* we don't do directories other than read-only
 	 */
-	if (S_ISDIR(xattr.mode))
+	if (S_ISDIR(xattr.mode) && ((rwmode & O_RWMODE) != O_RDONLY))
 	{
 		DEBUG(("do_open(%s): file is a directory", name));
 		release_cookie (&dir);
Index: sys/proc_help.c
===================================================================
RCS file: /mint/freemint/sys/proc_help.c,v
retrieving revision 1.30
diff -u -r1.30 proc_help.c
--- sys/proc_help.c	13 Jul 2007 21:32:49 -0000	1.30
+++ sys/proc_help.c	22 Feb 2008 09:38:50 -0000
@@ -538,18 +538,6 @@
 		;
 	}
 	
-	/* close all files */
-	for (i = MIN_HANDLE; i < p_fd->nfiles; i++)
-	{
-		f = p_fd->ofiles[i];
-		
-		if (f)
-		{
-			p_fd->ofiles[i] = NULL;
-			do_close (p, f);
-		}
-	}
-	
 	/* close any unresolved Fsfirst/Fsnext directory searches */
 	for (i = 0; i < NUM_SEARCH; i++)
 	{
@@ -580,6 +568,18 @@
 			dirh = nexth;
 		}
 	}
+
+	/* close all files */
+	for (i = MIN_HANDLE; i < p_fd->nfiles; i++)
+	{
+		f = p_fd->ofiles[i];
+		
+		if (f)
+		{
+			p_fd->ofiles[i] = NULL;
+			do_close (p, f);
+		}
+	}
 	
 	if (p_fd->nfiles > NDFILE)
 		kfree (p_fd->ofiles);
Index: sys/ramfs.c
===================================================================
RCS file: /mint/freemint/sys/ramfs.c,v
retrieving revision 1.14
diff -u -r1.14 ramfs.c
--- sys/ramfs.c	13 Jul 2007 21:32:49 -0000	1.14
+++ sys/ramfs.c	22 Feb 2008 09:38:51 -0000
@@ -2036,8 +2036,10 @@
 
 	if (!IS_REG (c))
 	{
-		RAM_DEBUG (("ramfs: ram_open: leave failure, not a valid file"));
-		return EACCES;
+		if (!(IS_DIR (c) && ((f->flags & O_RWMODE) == O_RDONLY))) {
+			RAM_DEBUG (("ramfs: ram_open: leave failure, not a valid file"));
+			return EACCES;
+		}
 	}
 
 	if (((f->flags & O_RWMODE) == O_WRONLY)
@@ -2368,7 +2370,8 @@
 		f->pos += bytes;
 	}
 
-	if (!((c->s->flags & MS_NOATIME)
+	if (!((f->flags & O_NOATIME) 
+	        || (c->s->flags & MS_NOATIME)
 		|| (c->s->flags & MS_RDONLY)
 		|| IS_IMMUTABLE (c)))
 	{
Index: sys/syscall_vectors.c
===================================================================
RCS file: /mint/freemint/sys/syscall_vectors.c,v
retrieving revision 1.33
diff -u -r1.33 syscall_vectors.c
--- sys/syscall_vectors.c	2 Aug 2004 21:19:20 -0000	1.33
+++ sys/syscall_vectors.c	22 Feb 2008 09:38:51 -0000
@@ -519,9 +519,9 @@
 	/* 0x17f */		sys_enosys,		/* sys_munmap */
 
 	/* 0x180 */		sys_f_chown16,	/* 1.16 */
-	/* 0x181 */		sys_enosys,		/* reserved */
-	/* 0x182 */		sys_enosys,		/* reserved */
-	/* 0x183 */		sys_enosys,		/* reserved */
+	/* 0x181 */		sys_f_chdir,	/* 1.17 */
+	/* 0x182 */		sys_f_opendir,	/* 1.17 */
+	/* 0x183 */		sys_f_dirfd,	/* 1.17 */
 	/* 0x184 */		sys_enosys,		/* reserved */
 	/* 0x185 */		sys_enosys,		/* reserved */
 	/* 0x186 */		sys_enosys,		/* reserved */
Index: sys/syscalls.master
===================================================================
RCS file: /mint/freemint/sys/syscalls.master,v
retrieving revision 1.27
diff -u -r1.27 syscalls.master
--- sys/syscalls.master	2 Jun 2006 08:14:32 -0000	1.27
+++ sys/syscalls.master	22 Feb 2008 09:38:51 -0000
@@ -518,9 +518,9 @@
 
 0x180	Fchown16	(const char *name, short uid, short gid,
 			 short follow) /* since 1.16 */
-0x181	undefined
-0x182	undefined
-0x183	undefined
+0x181	Fchdir		(short fd) /* since 1.17 */
+0x182	Ffdopendir	(short fd) /* since 1.17 */
+0x183	Fdirfd		(long handle) /* since 1.17 */
 0x184	undefined
 0x185	undefined
 0x186	undefined
Index: sys/mint/fcntl.h
===================================================================
RCS file: /mint/freemint/sys/mint/fcntl.h,v
retrieving revision 1.2
diff -u -r1.2 fcntl.h
--- sys/mint/fcntl.h	13 Jun 2001 20:21:42 -0000	1.2
+++ sys/mint/fcntl.h	22 Feb 2008 09:38:52 -0000
@@ -65,6 +65,10 @@
 # define O_TRUNC	0x00000400	/* truncate file to 0 bytes if it does exist */
 # define O_EXCL		0x00000800	/* error if file exists */
 
+/* extension must match mintlib */
+# define O_NOATIME	0x00040000	/* Do not set atime.  */
+
+
 # if 0
 /* XXX missing */
 # define O_SHLOCK	0x000000	/* open with shared file lock */
Index: sys/xfs/ext2fs/ext2dev.c
===================================================================
RCS file: /mint/freemint/sys/xfs/ext2fs/ext2dev.c,v
retrieving revision 1.9
diff -u -r1.9 ext2dev.c
--- sys/xfs/ext2fs/ext2dev.c	13 Jul 2007 21:32:53 -0000	1.9
+++ sys/xfs/ext2fs/ext2dev.c	22 Feb 2008 09:38:53 -0000
@@ -72,8 +72,11 @@
 	
 	if (!EXT2_ISREG (le2cpu16 (c->in.i_mode)))
 	{
-		DEBUG (("Ext2-FS [%c]: e_open: not a regular file (#%ld)", f->fc.dev+'A', c->inode));
-		return EACCES;
+		if (!(EXT2_ISDIR (le2cpu16 (c->in.i_mode)) && 
+		     ((f->flags & O_RWMODE) == O_RDONLY))) {
+			DEBUG (("Ext2-FS [%c]: e_open: not a regular file or read-only directory (#%ld)", f->fc.dev+'A', c->inode));
+			return EACCES;
+		}
 	}
 	
 	if (((f->flags & O_RWMODE) == O_WRONLY)
@@ -516,7 +519,10 @@
 	}
 	
 out:
-	if (!((s->s_flags & MS_NOATIME) || (s->s_flags & MS_RDONLY) || IS_IMMUTABLE (c)))
+	if (!((f->flags & O_NOATIME) 
+	     || (s->s_flags & MS_NOATIME) 
+	     || (s->s_flags & MS_RDONLY) 
+	     || IS_IMMUTABLE (c)))
 	{
 		c->in.i_atime = cpu2le32 (CURRENT_TIME);
 		mark_inode_dirty (c);
Index: sys/xfs/minixfs/minixdev.c
===================================================================
RCS file: /mint/freemint/sys/xfs/minixfs/minixdev.c,v
retrieving revision 1.6
diff -u -r1.6 minixdev.c
--- sys/xfs/minixfs/minixdev.c	13 Jul 2007 22:48:36 -0000	1.6
+++ sys/xfs/minixfs/minixdev.c	22 Feb 2008 09:38:53 -0000
@@ -63,8 +63,10 @@
 	
 	if (!IS_REG (rip))
 	{
-		DEBUG (("Minix-FS (%c): m_open: not a regular file.", f->fc.dev+'A'));
-		return EACCES;
+		if (!(IS_DIR (rip) && ((f->flags & O_RWMODE) == O_RDONLY))) {
+			DEBUG (("Minix-FS (%c): m_open: not a regular file.", f->fc.dev+'A'));
+			return EACCES;
+		}
 	}
 	
 	/* Set up f_cache structure */
@@ -468,7 +470,8 @@
 	}
 	
 out:
-	__update_rip (f->fc.index, &rip, f->fc.dev, f->pos, mode);
+	if (!(f->flags & O_NOATIME))
+		__update_rip (f->fc.index, &rip, f->fc.dev, f->pos, mode);
 	
 	return done;	
 }