summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2007-01-17 01:42:12 +0000
committerpjd <pjd@FreeBSD.org>2007-01-17 01:42:12 +0000
commit2f68acd7f70c5ec863ae674084f63419cf37801e (patch)
treecc16d091d5d85804bc3b295c3fce1b73aa0ac51e /tools
parent199c2180b10842922c716b5b4dd150d1628f2b88 (diff)
downloadFreeBSD-src-2f68acd7f70c5ec863ae674084f63419cf37801e.zip
FreeBSD-src-2f68acd7f70c5ec863ae674084f63419cf37801e.tar.gz
Add 3436 file system regression tests in 184 files.
Almost all regression tests are based on very flexible fstest tool. They verify correctness (POSIX conformance) of almost all file system-related system calls. The motivation behind this work is my ZFS port and POSIX, who doesn't provide free test suites. Runs on: FreeBSD/UFS, FreeBSD/ZFS, Solaris/UFS, Solaris/ZFS To try it out: # cd fstest # make # find tests/* -type d | xargs prove
Diffstat (limited to 'tools')
-rw-r--r--tools/regression/fstest/LICENSE27
-rw-r--r--tools/regression/fstest/Makefile15
-rw-r--r--tools/regression/fstest/fstest.c995
-rw-r--r--tools/regression/fstest/tests/chflags/00.t178
-rw-r--r--tools/regression/fstest/tests/chflags/01.t20
-rw-r--r--tools/regression/fstest/tests/chflags/02.t18
-rw-r--r--tools/regression/fstest/tests/chflags/03.t25
-rw-r--r--tools/regression/fstest/tests/chflags/04.t19
-rw-r--r--tools/regression/fstest/tests/chflags/05.t35
-rw-r--r--tools/regression/fstest/tests/chflags/06.t21
-rw-r--r--tools/regression/fstest/tests/chflags/07.t54
-rw-r--r--tools/regression/fstest/tests/chflags/08.t70
-rw-r--r--tools/regression/fstest/tests/chflags/09.t82
-rw-r--r--tools/regression/fstest/tests/chflags/10.t62
-rw-r--r--tools/regression/fstest/tests/chflags/11.t70
-rw-r--r--tools/regression/fstest/tests/chflags/12.t43
-rw-r--r--tools/regression/fstest/tests/chflags/13.t14
-rw-r--r--tools/regression/fstest/tests/chmod/00.t161
-rw-r--r--tools/regression/fstest/tests/chmod/01.t18
-rw-r--r--tools/regression/fstest/tests/chmod/02.t15
-rw-r--r--tools/regression/fstest/tests/chmod/03.t22
-rw-r--r--tools/regression/fstest/tests/chmod/04.t17
-rw-r--r--tools/regression/fstest/tests/chmod/05.t31
-rw-r--r--tools/regression/fstest/tests/chmod/06.t19
-rw-r--r--tools/regression/fstest/tests/chmod/07.t31
-rw-r--r--tools/regression/fstest/tests/chmod/08.t59
-rw-r--r--tools/regression/fstest/tests/chmod/09.t37
-rw-r--r--tools/regression/fstest/tests/chmod/10.t12
-rw-r--r--tools/regression/fstest/tests/chmod/11.t53
-rw-r--r--tools/regression/fstest/tests/chown/00.t304
-rw-r--r--tools/regression/fstest/tests/chown/01.t18
-rw-r--r--tools/regression/fstest/tests/chown/02.t15
-rw-r--r--tools/regression/fstest/tests/chown/03.t22
-rw-r--r--tools/regression/fstest/tests/chown/04.t17
-rw-r--r--tools/regression/fstest/tests/chown/05.t32
-rw-r--r--tools/regression/fstest/tests/chown/06.t19
-rw-r--r--tools/regression/fstest/tests/chown/07.t28
-rw-r--r--tools/regression/fstest/tests/chown/08.t53
-rw-r--r--tools/regression/fstest/tests/chown/09.t37
-rw-r--r--tools/regression/fstest/tests/chown/10.t12
-rw-r--r--tools/regression/fstest/tests/conf8
-rw-r--r--tools/regression/fstest/tests/link/00.t151
-rw-r--r--tools/regression/fstest/tests/link/01.t22
-rw-r--r--tools/regression/fstest/tests/link/02.t23
-rw-r--r--tools/regression/fstest/tests/link/03.t28
-rw-r--r--tools/regression/fstest/tests/link/04.t20
-rw-r--r--tools/regression/fstest/tests/link/05.t41
-rw-r--r--tools/regression/fstest/tests/link/06.t43
-rw-r--r--tools/regression/fstest/tests/link/07.t41
-rw-r--r--tools/regression/fstest/tests/link/08.t24
-rw-r--r--tools/regression/fstest/tests/link/09.t18
-rw-r--r--tools/regression/fstest/tests/link/10.t32
-rw-r--r--tools/regression/fstest/tests/link/11.t41
-rw-r--r--tools/regression/fstest/tests/link/12.t55
-rw-r--r--tools/regression/fstest/tests/link/13.t56
-rw-r--r--tools/regression/fstest/tests/link/14.t34
-rw-r--r--tools/regression/fstest/tests/link/15.t38
-rw-r--r--tools/regression/fstest/tests/link/16.t39
-rw-r--r--tools/regression/fstest/tests/link/17.t20
-rw-r--r--tools/regression/fstest/tests/misc.sh96
-rw-r--r--tools/regression/fstest/tests/mkdir/00.t63
-rw-r--r--tools/regression/fstest/tests/mkdir/01.t18
-rw-r--r--tools/regression/fstest/tests/mkdir/02.t13
-rw-r--r--tools/regression/fstest/tests/mkdir/03.t21
-rw-r--r--tools/regression/fstest/tests/mkdir/04.t16
-rw-r--r--tools/regression/fstest/tests/mkdir/05.t29
-rw-r--r--tools/regression/fstest/tests/mkdir/06.t29
-rw-r--r--tools/regression/fstest/tests/mkdir/07.t19
-rw-r--r--tools/regression/fstest/tests/mkdir/08.t53
-rw-r--r--tools/regression/fstest/tests/mkdir/09.t34
-rw-r--r--tools/regression/fstest/tests/mkdir/10.t27
-rw-r--r--tools/regression/fstest/tests/mkdir/11.t36
-rw-r--r--tools/regression/fstest/tests/mkdir/12.t12
-rw-r--r--tools/regression/fstest/tests/mkfifo/00.t63
-rw-r--r--tools/regression/fstest/tests/mkfifo/01.t18
-rw-r--r--tools/regression/fstest/tests/mkfifo/02.t13
-rw-r--r--tools/regression/fstest/tests/mkfifo/03.t21
-rw-r--r--tools/regression/fstest/tests/mkfifo/04.t16
-rw-r--r--tools/regression/fstest/tests/mkfifo/05.t29
-rw-r--r--tools/regression/fstest/tests/mkfifo/06.t29
-rw-r--r--tools/regression/fstest/tests/mkfifo/07.t19
-rw-r--r--tools/regression/fstest/tests/mkfifo/08.t34
-rw-r--r--tools/regression/fstest/tests/mkfifo/09.t27
-rw-r--r--tools/regression/fstest/tests/mkfifo/10.t53
-rw-r--r--tools/regression/fstest/tests/mkfifo/11.t36
-rw-r--r--tools/regression/fstest/tests/mkfifo/12.t12
-rw-r--r--tools/regression/fstest/tests/open/00.t87
-rw-r--r--tools/regression/fstest/tests/open/01.t18
-rw-r--r--tools/regression/fstest/tests/open/02.t14
-rw-r--r--tools/regression/fstest/tests/open/03.t22
-rw-r--r--tools/regression/fstest/tests/open/04.t17
-rw-r--r--tools/regression/fstest/tests/open/05.t29
-rw-r--r--tools/regression/fstest/tests/open/06.t89
-rw-r--r--tools/regression/fstest/tests/open/07.t45
-rw-r--r--tools/regression/fstest/tests/open/08.t19
-rw-r--r--tools/regression/fstest/tests/open/09.t53
-rw-r--r--tools/regression/fstest/tests/open/10.t45
-rw-r--r--tools/regression/fstest/tests/open/11.t39
-rw-r--r--tools/regression/fstest/tests/open/12.t19
-rw-r--r--tools/regression/fstest/tests/open/13.t24
-rw-r--r--tools/regression/fstest/tests/open/14.t37
-rw-r--r--tools/regression/fstest/tests/open/15.t32
-rw-r--r--tools/regression/fstest/tests/open/16.t19
-rw-r--r--tools/regression/fstest/tests/open/17.t15
-rw-r--r--tools/regression/fstest/tests/open/18.t18
-rw-r--r--tools/regression/fstest/tests/open/19.t37
-rw-r--r--tools/regression/fstest/tests/open/20.t25
-rw-r--r--tools/regression/fstest/tests/open/21.t12
-rw-r--r--tools/regression/fstest/tests/open/22.t27
-rw-r--r--tools/regression/fstest/tests/open/23.t16
-rw-r--r--tools/regression/fstest/tests/rename/00.t141
-rw-r--r--tools/regression/fstest/tests/rename/01.t21
-rw-r--r--tools/regression/fstest/tests/rename/02.t26
-rw-r--r--tools/regression/fstest/tests/rename/03.t20
-rw-r--r--tools/regression/fstest/tests/rename/04.t43
-rw-r--r--tools/regression/fstest/tests/rename/05.t41
-rw-r--r--tools/regression/fstest/tests/rename/06.t50
-rw-r--r--tools/regression/fstest/tests/rename/07.t95
-rw-r--r--tools/regression/fstest/tests/rename/08.t95
-rw-r--r--tools/regression/fstest/tests/rename/09.t94
-rw-r--r--tools/regression/fstest/tests/rename/10.t243
-rw-r--r--tools/regression/fstest/tests/rename/11.t24
-rw-r--r--tools/regression/fstest/tests/rename/12.t22
-rw-r--r--tools/regression/fstest/tests/rename/13.t34
-rw-r--r--tools/regression/fstest/tests/rename/14.t34
-rw-r--r--tools/regression/fstest/tests/rename/15.t45
-rw-r--r--tools/regression/fstest/tests/rename/16.t37
-rw-r--r--tools/regression/fstest/tests/rename/17.t20
-rw-r--r--tools/regression/fstest/tests/rename/18.t22
-rw-r--r--tools/regression/fstest/tests/rename/19.t22
-rw-r--r--tools/regression/fstest/tests/rename/20.t35
-rw-r--r--tools/regression/fstest/tests/rmdir/00.t28
-rw-r--r--tools/regression/fstest/tests/rmdir/01.t30
-rw-r--r--tools/regression/fstest/tests/rmdir/02.t14
-rw-r--r--tools/regression/fstest/tests/rmdir/03.t22
-rw-r--r--tools/regression/fstest/tests/rmdir/04.t17
-rw-r--r--tools/regression/fstest/tests/rmdir/05.t19
-rw-r--r--tools/regression/fstest/tests/rmdir/06.t36
-rw-r--r--tools/regression/fstest/tests/rmdir/07.t27
-rw-r--r--tools/regression/fstest/tests/rmdir/08.t27
-rw-r--r--tools/regression/fstest/tests/rmdir/09.t49
-rw-r--r--tools/regression/fstest/tests/rmdir/10.t52
-rw-r--r--tools/regression/fstest/tests/rmdir/11.t40
-rw-r--r--tools/regression/fstest/tests/rmdir/12.t26
-rw-r--r--tools/regression/fstest/tests/rmdir/13.t27
-rw-r--r--tools/regression/fstest/tests/rmdir/14.t32
-rw-r--r--tools/regression/fstest/tests/rmdir/15.t12
-rw-r--r--tools/regression/fstest/tests/symlink/00.t32
-rw-r--r--tools/regression/fstest/tests/symlink/01.t18
-rw-r--r--tools/regression/fstest/tests/symlink/02.t20
-rw-r--r--tools/regression/fstest/tests/symlink/03.t26
-rw-r--r--tools/regression/fstest/tests/symlink/04.t16
-rw-r--r--tools/regression/fstest/tests/symlink/05.t34
-rw-r--r--tools/regression/fstest/tests/symlink/06.t34
-rw-r--r--tools/regression/fstest/tests/symlink/07.t19
-rw-r--r--tools/regression/fstest/tests/symlink/08.t23
-rw-r--r--tools/regression/fstest/tests/symlink/09.t53
-rw-r--r--tools/regression/fstest/tests/symlink/10.t37
-rw-r--r--tools/regression/fstest/tests/symlink/11.t36
-rw-r--r--tools/regression/fstest/tests/symlink/12.t18
-rw-r--r--tools/regression/fstest/tests/truncate/00.t51
-rw-r--r--tools/regression/fstest/tests/truncate/01.t18
-rw-r--r--tools/regression/fstest/tests/truncate/02.t15
-rw-r--r--tools/regression/fstest/tests/truncate/03.t22
-rw-r--r--tools/regression/fstest/tests/truncate/04.t17
-rw-r--r--tools/regression/fstest/tests/truncate/05.t32
-rw-r--r--tools/regression/fstest/tests/truncate/06.t24
-rw-r--r--tools/regression/fstest/tests/truncate/07.t19
-rw-r--r--tools/regression/fstest/tests/truncate/08.t59
-rw-r--r--tools/regression/fstest/tests/truncate/09.t15
-rw-r--r--tools/regression/fstest/tests/truncate/10.t37
-rw-r--r--tools/regression/fstest/tests/truncate/11.t23
-rw-r--r--tools/regression/fstest/tests/truncate/12.t27
-rw-r--r--tools/regression/fstest/tests/truncate/13.t16
-rw-r--r--tools/regression/fstest/tests/truncate/14.t12
-rw-r--r--tools/regression/fstest/tests/unlink/00.t115
-rw-r--r--tools/regression/fstest/tests/unlink/01.t18
-rw-r--r--tools/regression/fstest/tests/unlink/02.t14
-rw-r--r--tools/regression/fstest/tests/unlink/03.t22
-rw-r--r--tools/regression/fstest/tests/unlink/04.t17
-rw-r--r--tools/regression/fstest/tests/unlink/05.t27
-rw-r--r--tools/regression/fstest/tests/unlink/06.t27
-rw-r--r--tools/regression/fstest/tests/unlink/07.t19
-rw-r--r--tools/regression/fstest/tests/unlink/08.t23
-rw-r--r--tools/regression/fstest/tests/unlink/09.t49
-rw-r--r--tools/regression/fstest/tests/unlink/10.t52
-rw-r--r--tools/regression/fstest/tests/unlink/11.t68
-rw-r--r--tools/regression/fstest/tests/unlink/12.t32
-rw-r--r--tools/regression/fstest/tests/unlink/13.t12
189 files changed, 7978 insertions, 0 deletions
diff --git a/tools/regression/fstest/LICENSE b/tools/regression/fstest/LICENSE
new file mode 100644
index 0000000..0638aad
--- /dev/null
+++ b/tools/regression/fstest/LICENSE
@@ -0,0 +1,27 @@
+$FreeBSD$
+
+License for all regression tests available with fstest:
+
+Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/tools/regression/fstest/Makefile b/tools/regression/fstest/Makefile
new file mode 100644
index 0000000..0781730
--- /dev/null
+++ b/tools/regression/fstest/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+CFLAGS+=-DHAS_LCHMOD
+CFLAGS+=-DHAS_CHFLAGS
+CFLAGS+=-DHAS_LCHFLAGS
+#CFLAGS+=-DHAS_TRUNCATE64
+#CFLAGS+=-DHAS_STAT64
+
+all: fstest
+
+fstest: fstest.c
+ gcc -Wall ${CFLAGS} fstest.c -o fstest
+
+clean:
+ rm -f fstest
diff --git a/tools/regression/fstest/fstest.c b/tools/regression/fstest/fstest.c
new file mode 100644
index 0000000..98211d0
--- /dev/null
+++ b/tools/regression/fstest/fstest.c
@@ -0,0 +1,995 @@
+/*-
+ * Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+
+#ifndef HAS_TRUNCATE64
+#define truncate64 truncate
+#endif
+#ifndef HAS_STAT64
+#define stat64 stat
+#define lstat64 lstat
+#endif
+
+#ifndef ALLPERMS
+#define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
+#endif
+
+enum action {
+ ACTION_OPEN,
+ ACTION_CREATE,
+ ACTION_UNLINK,
+ ACTION_MKDIR,
+ ACTION_RMDIR,
+ ACTION_LINK,
+ ACTION_SYMLINK,
+ ACTION_RENAME,
+ ACTION_MKFIFO,
+ ACTION_CHMOD,
+#ifdef HAS_LCHMOD
+ ACTION_LCHMOD,
+#endif
+ ACTION_CHOWN,
+ ACTION_LCHOWN,
+#ifdef HAS_CHFLAGS
+ ACTION_CHFLAGS,
+#endif
+#ifdef HAS_LCHFLAGS
+ ACTION_LCHFLAGS,
+#endif
+ ACTION_TRUNCATE,
+ ACTION_STAT,
+ ACTION_LSTAT,
+};
+
+#define TYPE_NONE 0x0000
+#define TYPE_STRING 0x0001
+#define TYPE_NUMBER 0x0002
+
+#define TYPE_OPTIONAL 0x0100
+
+#define MAX_ARGS 8
+
+struct syscall_desc {
+ char *sd_name;
+ enum action sd_action;
+ int sd_args[MAX_ARGS];
+};
+
+static struct syscall_desc syscalls[] = {
+ { "open", ACTION_OPEN, { TYPE_STRING, TYPE_STRING, TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } },
+ { "create", ACTION_CREATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
+ { "unlink", ACTION_UNLINK, { TYPE_STRING, TYPE_NONE } },
+ { "mkdir", ACTION_MKDIR, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
+ { "rmdir", ACTION_RMDIR, { TYPE_STRING, TYPE_NONE } },
+ { "link", ACTION_LINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
+ { "symlink", ACTION_SYMLINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
+ { "rename", ACTION_RENAME, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
+ { "mkfifo", ACTION_MKFIFO, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
+ { "chmod", ACTION_CHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
+#ifdef HAS_LCHMOD
+ { "lchmod", ACTION_LCHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
+#endif
+ { "chown", ACTION_CHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
+ { "lchown", ACTION_LCHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
+#ifdef HAS_CHFLAGS
+ { "chflags", ACTION_CHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
+#endif
+#ifdef HAS_LCHFLAGS
+ { "lchflags", ACTION_LCHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
+#endif
+ { "truncate", ACTION_TRUNCATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
+ { "stat", ACTION_STAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
+ { "lstat", ACTION_LSTAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
+ { NULL, -1, { TYPE_NONE } }
+};
+
+struct flag {
+ long long f_flag;
+ char *f_str;
+};
+
+static struct flag open_flags[] = {
+#ifdef O_RDONLY
+ { O_RDONLY, "O_RDONLY" },
+#endif
+#ifdef O_WRONLY
+ { O_WRONLY, "O_WRONLY" },
+#endif
+#ifdef O_RDWR
+ { O_RDWR, "O_RDWR" },
+#endif
+#ifdef O_NONBLOCK
+ { O_NONBLOCK, "O_NONBLOCK" },
+#endif
+#ifdef O_APPEND
+ { O_APPEND, "O_APPEND" },
+#endif
+#ifdef O_CREAT
+ { O_CREAT, "O_CREAT" },
+#endif
+#ifdef O_TRUNC
+ { O_TRUNC, "O_TRUNC" },
+#endif
+#ifdef O_EXCL
+ { O_EXCL, "O_EXCL" },
+#endif
+#ifdef O_SHLOCK
+ { O_SHLOCK, "O_SHLOCK" },
+#endif
+#ifdef O_EXLOCK
+ { O_EXLOCK, "O_EXLOCK" },
+#endif
+#ifdef O_DIRECT
+ { O_DIRECT, "O_DIRECT" },
+#endif
+#ifdef O_FSYNC
+ { O_FSYNC, "O_FSYNC" },
+#endif
+#ifdef O_SYNC
+ { O_SYNC, "O_SYNC" },
+#endif
+#ifdef O_NOFOLLOW
+ { O_NOFOLLOW, "O_NOFOLLOW" },
+#endif
+#ifdef O_NOCTTY
+ { O_NOCTTY, "O_NOCTTY" },
+#endif
+ { 0, NULL }
+};
+
+#ifdef HAS_CHFLAGS
+static struct flag chflags_flags[] = {
+#ifdef UF_NODUMP
+ { UF_NODUMP, "UF_NODUMP" },
+#endif
+#ifdef UF_IMMUTABLE
+ { UF_IMMUTABLE, "UF_IMMUTABLE" },
+#endif
+#ifdef UF_APPEND
+ { UF_APPEND, "UF_APPEND" },
+#endif
+#ifdef UF_NOUNLINK
+ { UF_NOUNLINK, "UF_NOUNLINK" },
+#endif
+#ifdef UF_OPAQUE
+ { UF_OPAQUE, "UF_OPAQUE" },
+#endif
+#ifdef SF_ARCHIVED
+ { SF_ARCHIVED, "SF_ARCHIVED" },
+#endif
+#ifdef SF_IMMUTABLE
+ { SF_IMMUTABLE, "SF_IMMUTABLE" },
+#endif
+#ifdef SF_APPEND
+ { SF_APPEND, "SF_APPEND" },
+#endif
+#ifdef SF_NOUNLINK
+ { SF_NOUNLINK, "SF_NOUNLINK" },
+#endif
+#ifdef SF_SNAPSHOT
+ { SF_SNAPSHOT, "SF_SNAPSHOT" },
+#endif
+ { 0, NULL }
+};
+#endif
+
+static const char *err2str(int error);
+
+static void
+usage(void)
+{
+
+ fprintf(stderr, "usage: fstest [-u uid] [-g gid1[,gid2[...]]] syscall args ...\n");
+ exit(1);
+}
+
+static long long
+str2flags(struct flag *tflags, char *sflags)
+{
+ long long flags = 0;
+ unsigned int i;
+ char *f;
+
+ for (f = strtok(sflags, ","); f != NULL; f = strtok(NULL, ",")) {
+ /* Support magic 'none' flag which just reset all flags. */
+ if (strcmp(f, "none") == 0)
+ return (0);
+ for (i = 0; tflags[i].f_str != NULL; i++) {
+ if (strcmp(tflags[i].f_str, f) == 0)
+ break;
+ }
+ if (tflags[i].f_str == NULL) {
+ fprintf(stderr, "unknown flag '%s'\n", f);
+ exit(1);
+ }
+ flags |= tflags[i].f_flag;
+ }
+ return (flags);
+}
+
+#ifdef HAS_CHFLAGS
+static char *
+flags2str(struct flag *tflags, long long flags)
+{
+ static char sflags[1024];
+ unsigned int i;
+
+ sflags[0] = '\0';
+ for (i = 0; tflags[i].f_str != NULL; i++) {
+ if (flags & tflags[i].f_flag) {
+ if (sflags[0] != '\0')
+ strlcat(sflags, ",", sizeof(sflags));
+ strlcat(sflags, tflags[i].f_str, sizeof(sflags));
+ }
+ }
+ if (sflags[0] == '\0')
+ strlcpy(sflags, "none", sizeof(sflags));
+ return (sflags);
+}
+#endif
+
+static struct syscall_desc *
+find_syscall(const char *name)
+{
+ int i;
+
+ for (i = 0; syscalls[i].sd_name != NULL; i++) {
+ if (strcmp(syscalls[i].sd_name, name) == 0)
+ return (&syscalls[i]);
+ }
+ return (NULL);
+}
+
+static void
+show_stat(struct stat64 *sp, const char *what)
+{
+
+ if (strcmp(what, "mode") == 0)
+ printf("0%o", (unsigned int)(sp->st_mode & ALLPERMS));
+ else if (strcmp(what, "inode") == 0)
+ printf("%lld", (long long)sp->st_ino);
+ else if (strcmp(what, "nlink") == 0)
+ printf("%lld", (long long)sp->st_nlink);
+ else if (strcmp(what, "uid") == 0)
+ printf("%d", (int)sp->st_uid);
+ else if (strcmp(what, "gid") == 0)
+ printf("%d", (int)sp->st_gid);
+ else if (strcmp(what, "size") == 0)
+ printf("%lld", (long long)sp->st_size);
+ else if (strcmp(what, "blocks") == 0)
+ printf("%lld", (long long)sp->st_blocks);
+ else if (strcmp(what, "atime") == 0)
+ printf("%lld", (long long)sp->st_atime);
+ else if (strcmp(what, "mtime") == 0)
+ printf("%lld", (long long)sp->st_mtime);
+ else if (strcmp(what, "ctime") == 0)
+ printf("%lld", (long long)sp->st_ctime);
+#ifdef HAS_CHFLAGS
+ else if (strcmp(what, "flags") == 0)
+ printf("%s", flags2str(chflags_flags, sp->st_flags));
+#endif
+ else if (strcmp(what, "type") == 0) {
+ switch (sp->st_mode & S_IFMT) {
+ case S_IFIFO:
+ printf("fifo");
+ break;
+ case S_IFCHR:
+ printf("char");
+ break;
+ case S_IFDIR:
+ printf("dir");
+ break;
+ case S_IFBLK:
+ printf("block");
+ break;
+ case S_IFREG:
+ printf("regular");
+ break;
+ case S_IFLNK:
+ printf("symlink");
+ break;
+ case S_IFSOCK:
+ printf("socket");
+ break;
+ default:
+ printf("unknown");
+ break;
+ }
+ } else {
+ printf("unknown");
+ }
+}
+
+static void
+show_stats(struct stat64 *sp, char *what)
+{
+ const char *s = "";
+ char *w;
+
+ for (w = strtok(what, ","); w != NULL; w = strtok(NULL, ",")) {
+ printf("%s", s);
+ show_stat(sp, w);
+ s = ",";
+ }
+ printf("\n");
+}
+
+static unsigned int
+call_syscall(struct syscall_desc *scall, char *argv[])
+{
+ struct stat64 sb;
+ long long flags;
+ unsigned int i;
+ char *endp;
+ int rval;
+ union {
+ char *str;
+ long long num;
+ } args[MAX_ARGS];
+
+ /*
+ * Verify correctness of the arguments.
+ */
+ for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) {
+ if (scall->sd_args[i] == TYPE_NONE) {
+ if (argv[i] == NULL || strcmp(argv[i], ":") == 0)
+ break;
+ fprintf(stderr, "too many arguments [%s]\n", argv[i]);
+ exit(1);
+ } else {
+ if (argv[i] == NULL || strcmp(argv[i], ":") == 0) {
+ if (scall->sd_args[i] & TYPE_OPTIONAL)
+ break;
+ fprintf(stderr, "too few arguments\n");
+ exit(1);
+ }
+ if (scall->sd_args[i] & TYPE_STRING) {
+ if (strcmp(argv[i], "NULL") == 0)
+ args[i].str = NULL;
+ else if (strcmp(argv[i], "DEADCODE") == 0)
+ args[i].str = (void *)0xdeadc0de;
+ else
+ args[i].str = argv[i];
+ } else if (scall->sd_args[i] & TYPE_NUMBER) {
+ args[i].num = strtoll(argv[i], &endp, 0);
+ if (*endp != '\0' && !isspace((unsigned char)*endp)) {
+ fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp);
+ exit(1);
+ }
+ }
+ }
+ }
+ /*
+ * Call the given syscall.
+ */
+#define NUM(n) (args[(n)].num)
+#define STR(n) (args[(n)].str)
+ switch (scall->sd_action) {
+ case ACTION_OPEN:
+ flags = str2flags(open_flags, STR(1));
+ if (flags & O_CREAT) {
+ if (i == 2) {
+ fprintf(stderr, "too few arguments\n");
+ exit(1);
+ }
+ rval = open(STR(0), flags, (mode_t)NUM(2));
+ } else {
+ if (i == 3) {
+ fprintf(stderr, "too many arguments\n");
+ exit(1);
+ }
+ rval = open(STR(0), flags);
+ }
+ break;
+ case ACTION_CREATE:
+ rval = open(STR(0), O_CREAT | O_EXCL, NUM(1));
+ if (rval >= 0)
+ close(rval);
+ break;
+ case ACTION_UNLINK:
+ rval = unlink(STR(0));
+ break;
+ case ACTION_MKDIR:
+ rval = mkdir(STR(0), NUM(1));
+ break;
+ case ACTION_RMDIR:
+ rval = rmdir(STR(0));
+ break;
+ case ACTION_LINK:
+ rval = link(STR(0), STR(1));
+ break;
+ case ACTION_SYMLINK:
+ rval = symlink(STR(0), STR(1));
+ break;
+ case ACTION_RENAME:
+ rval = rename(STR(0), STR(1));
+ break;
+ case ACTION_MKFIFO:
+ rval = mkfifo(STR(0), NUM(1));
+ break;
+ case ACTION_CHMOD:
+ rval = chmod(STR(0), NUM(1));
+ break;
+#ifdef HAS_LCHMOD
+ case ACTION_LCHMOD:
+ rval = lchmod(STR(0), NUM(1));
+ break;
+#endif
+ case ACTION_CHOWN:
+ rval = chown(STR(0), NUM(1), NUM(2));
+ break;
+ case ACTION_LCHOWN:
+ rval = lchown(STR(0), NUM(1), NUM(2));
+ break;
+#ifdef HAS_CHFLAGS
+ case ACTION_CHFLAGS:
+ rval = chflags(STR(0), str2flags(chflags_flags, STR(1)));
+ break;
+#endif
+#ifdef HAS_LCHFLAGS
+ case ACTION_LCHFLAGS:
+ rval = lchflags(STR(0), str2flags(chflags_flags, STR(1)));
+ break;
+#endif
+ case ACTION_TRUNCATE:
+ rval = truncate64(STR(0), NUM(1));
+ break;
+ case ACTION_STAT:
+ rval = stat64(STR(0), &sb);
+ if (rval == 0) {
+ show_stats(&sb, STR(1));
+ return (i);
+ }
+ break;
+ case ACTION_LSTAT:
+ rval = lstat64(STR(0), &sb);
+ if (rval == 0) {
+ show_stats(&sb, STR(1));
+ return (i);
+ }
+ break;
+ default:
+ fprintf(stderr, "unsupported syscall\n");
+ exit(1);
+ }
+#undef STR
+#undef NUM
+ if (rval < 0) {
+ const char *serrno;
+
+ serrno = err2str(errno);
+ fprintf(stderr, "%s returned %d\n", scall->sd_name, rval);
+ printf("%s\n", serrno);
+ exit(1);
+ }
+ printf("0\n");
+ return (i);
+}
+
+static void
+set_gids(char *gids)
+{
+ gid_t *gidset;
+ long ngroups;
+ char *g, *endp;
+ unsigned i;
+
+ ngroups = sysconf(_SC_NGROUPS_MAX);
+ assert(ngroups > 0);
+ gidset = malloc(sizeof(*gidset) * ngroups);
+ assert(gidset != NULL);
+ for (i = 0, g = strtok(gids, ","); g != NULL; g = strtok(NULL, ","), i++) {
+ if (i >= ngroups) {
+ fprintf(stderr, "too many gids\n");
+ exit(1);
+ }
+ gidset[i] = strtol(g, &endp, 0);
+ if (*endp != '\0' && !isspace((unsigned char)*endp)) {
+ fprintf(stderr, "invalid gid '%s' - number expected\n",
+ g);
+ exit(1);
+ }
+ }
+ if (setgroups(i, gidset) < 0) {
+ fprintf(stderr, "cannot change groups: %s\n", strerror(errno));
+ exit(1);
+ }
+ free(gidset);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct syscall_desc *scall;
+ unsigned int n;
+ char *gids, *endp;
+ int uid, umsk, ch;
+
+ uid = -1;
+ gids = NULL;
+ umsk = 0;
+
+ while ((ch = getopt(argc, argv, "g:u:U:")) != -1) {
+ switch(ch) {
+ case 'g':
+ gids = optarg;
+ break;
+ case 'u':
+ uid = (int)strtol(optarg, &endp, 0);
+ if (*endp != '\0' && !isspace((unsigned char)*endp)) {
+ fprintf(stderr, "invalid uid '%s' - number "
+ "expected\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'U':
+ umsk = (int)strtol(optarg, &endp, 0);
+ if (*endp != '\0' && !isspace((unsigned char)*endp)) {
+ fprintf(stderr, "invalid umask '%s' - number "
+ "expected\n", optarg);
+ exit(1);
+ }
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ fprintf(stderr, "too few arguments\n");
+ usage();
+ }
+
+ if (gids != NULL) {
+ fprintf(stderr, "changing groups to %s\n", gids);
+ set_gids(gids);
+ }
+ if (uid != -1) {
+ fprintf(stderr, "changing uid to %d\n", uid);
+ if (setuid(uid) < 0) {
+ fprintf(stderr, "cannot change uid: %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ }
+
+ /* Change umask to requested value or to 0, if not requested. */
+ umask(umsk);
+
+ for (;;) {
+ scall = find_syscall(argv[0]);
+ if (scall == NULL) {
+ fprintf(stderr, "syscall '%s' not supported\n", argv[0]);
+ exit(1);
+ }
+ argc++;
+ argv++;
+ n = call_syscall(scall, argv);
+ argc += n;
+ argv += n;
+ if (argv[0] == NULL)
+ break;
+ argc++;
+ argv++;
+ }
+
+ exit(0);
+}
+
+static const char *
+err2str(int error)
+{
+ static char errnum[8];
+
+ switch (error) {
+#ifdef EPERM
+ case EPERM:
+ return ("EPERM");
+#endif
+#ifdef ENOENT
+ case ENOENT:
+ return ("ENOENT");
+#endif
+#ifdef ESRCH
+ case ESRCH:
+ return ("ESRCH");
+#endif
+#ifdef EINTR
+ case EINTR:
+ return ("EINTR");
+#endif
+#ifdef EIO
+ case EIO:
+ return ("EIO");
+#endif
+#ifdef ENXIO
+ case ENXIO:
+ return ("ENXIO");
+#endif
+#ifdef E2BIG
+ case E2BIG:
+ return ("E2BIG");
+#endif
+#ifdef ENOEXEC
+ case ENOEXEC:
+ return ("ENOEXEC");
+#endif
+#ifdef EBADF
+ case EBADF:
+ return ("EBADF");
+#endif
+#ifdef ECHILD
+ case ECHILD:
+ return ("ECHILD");
+#endif
+#ifdef EDEADLK
+ case EDEADLK:
+ return ("EDEADLK");
+#endif
+#ifdef ENOMEM
+ case ENOMEM:
+ return ("ENOMEM");
+#endif
+#ifdef EACCES
+ case EACCES:
+ return ("EACCES");
+#endif
+#ifdef EFAULT
+ case EFAULT:
+ return ("EFAULT");
+#endif
+#ifdef ENOTBLK
+ case ENOTBLK:
+ return ("ENOTBLK");
+#endif
+#ifdef EBUSY
+ case EBUSY:
+ return ("EBUSY");
+#endif
+#ifdef EEXIST
+ case EEXIST:
+ return ("EEXIST");
+#endif
+#ifdef EXDEV
+ case EXDEV:
+ return ("EXDEV");
+#endif
+#ifdef ENODEV
+ case ENODEV:
+ return ("ENODEV");
+#endif
+#ifdef ENOTDIR
+ case ENOTDIR:
+ return ("ENOTDIR");
+#endif
+#ifdef EISDIR
+ case EISDIR:
+ return ("EISDIR");
+#endif
+#ifdef EINVAL
+ case EINVAL:
+ return ("EINVAL");
+#endif
+#ifdef ENFILE
+ case ENFILE:
+ return ("ENFILE");
+#endif
+#ifdef EMFILE
+ case EMFILE:
+ return ("EMFILE");
+#endif
+#ifdef ENOTTY
+ case ENOTTY:
+ return ("ENOTTY");
+#endif
+#ifdef ETXTBSY
+ case ETXTBSY:
+ return ("ETXTBSY");
+#endif
+#ifdef EFBIG
+ case EFBIG:
+ return ("EFBIG");
+#endif
+#ifdef ENOSPC
+ case ENOSPC:
+ return ("ENOSPC");
+#endif
+#ifdef ESPIPE
+ case ESPIPE:
+ return ("ESPIPE");
+#endif
+#ifdef EROFS
+ case EROFS:
+ return ("EROFS");
+#endif
+#ifdef EMLINK
+ case EMLINK:
+ return ("EMLINK");
+#endif
+#ifdef EPIPE
+ case EPIPE:
+ return ("EPIPE");
+#endif
+#ifdef EDOM
+ case EDOM:
+ return ("EDOM");
+#endif
+#ifdef ERANGE
+ case ERANGE:
+ return ("ERANGE");
+#endif
+#ifdef EAGAIN
+ case EAGAIN:
+ return ("EAGAIN");
+#endif
+#ifdef EINPROGRESS
+ case EINPROGRESS:
+ return ("EINPROGRESS");
+#endif
+#ifdef EALREADY
+ case EALREADY:
+ return ("EALREADY");
+#endif
+#ifdef ENOTSOCK
+ case ENOTSOCK:
+ return ("ENOTSOCK");
+#endif
+#ifdef EDESTADDRREQ
+ case EDESTADDRREQ:
+ return ("EDESTADDRREQ");
+#endif
+#ifdef EMSGSIZE
+ case EMSGSIZE:
+ return ("EMSGSIZE");
+#endif
+#ifdef EPROTOTYPE
+ case EPROTOTYPE:
+ return ("EPROTOTYPE");
+#endif
+#ifdef ENOPROTOOPT
+ case ENOPROTOOPT:
+ return ("ENOPROTOOPT");
+#endif
+#ifdef EPROTONOSUPPORT
+ case EPROTONOSUPPORT:
+ return ("EPROTONOSUPPORT");
+#endif
+#ifdef ESOCKTNOSUPPORT
+ case ESOCKTNOSUPPORT:
+ return ("ESOCKTNOSUPPORT");
+#endif
+#ifdef EOPNOTSUPP
+ case EOPNOTSUPP:
+ return ("EOPNOTSUPP");
+#endif
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT:
+ return ("EPFNOSUPPORT");
+#endif
+#ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT:
+ return ("EAFNOSUPPORT");
+#endif
+#ifdef EADDRINUSE
+ case EADDRINUSE:
+ return ("EADDRINUSE");
+#endif
+#ifdef EADDRNOTAVAIL
+ case EADDRNOTAVAIL:
+ return ("EADDRNOTAVAIL");
+#endif
+#ifdef ENETDOWN
+ case ENETDOWN:
+ return ("ENETDOWN");
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH:
+ return ("ENETUNREACH");
+#endif
+#ifdef ENETRESET
+ case ENETRESET:
+ return ("ENETRESET");
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED:
+ return ("ECONNABORTED");
+#endif
+#ifdef ECONNRESET
+ case ECONNRESET:
+ return ("ECONNRESET");
+#endif
+#ifdef ENOBUFS
+ case ENOBUFS:
+ return ("ENOBUFS");
+#endif
+#ifdef EISCONN
+ case EISCONN:
+ return ("EISCONN");
+#endif
+#ifdef ENOTCONN
+ case ENOTCONN:
+ return ("ENOTCONN");
+#endif
+#ifdef ESHUTDOWN
+ case ESHUTDOWN:
+ return ("ESHUTDOWN");
+#endif
+#ifdef ETOOMANYREFS
+ case ETOOMANYREFS:
+ return ("ETOOMANYREFS");
+#endif
+#ifdef ETIMEDOUT
+ case ETIMEDOUT:
+ return ("ETIMEDOUT");
+#endif
+#ifdef ECONNREFUSED
+ case ECONNREFUSED:
+ return ("ECONNREFUSED");
+#endif
+#ifdef ELOOP
+ case ELOOP:
+ return ("ELOOP");
+#endif
+#ifdef ENAMETOOLONG
+ case ENAMETOOLONG:
+ return ("ENAMETOOLONG");
+#endif
+#ifdef EHOSTDOWN
+ case EHOSTDOWN:
+ return ("EHOSTDOWN");
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH:
+ return ("EHOSTUNREACH");
+#endif
+#ifdef ENOTEMPTY
+ case ENOTEMPTY:
+ return ("ENOTEMPTY");
+#endif
+#ifdef EPROCLIM
+ case EPROCLIM:
+ return ("EPROCLIM");
+#endif
+#ifdef EUSERS
+ case EUSERS:
+ return ("EUSERS");
+#endif
+#ifdef EDQUOT
+ case EDQUOT:
+ return ("EDQUOT");
+#endif
+#ifdef ESTALE
+ case ESTALE:
+ return ("ESTALE");
+#endif
+#ifdef EREMOTE
+ case EREMOTE:
+ return ("EREMOTE");
+#endif
+#ifdef EBADRPC
+ case EBADRPC:
+ return ("EBADRPC");
+#endif
+#ifdef ERPCMISMATCH
+ case ERPCMISMATCH:
+ return ("ERPCMISMATCH");
+#endif
+#ifdef EPROGUNAVAIL
+ case EPROGUNAVAIL:
+ return ("EPROGUNAVAIL");
+#endif
+#ifdef EPROGMISMATCH
+ case EPROGMISMATCH:
+ return ("EPROGMISMATCH");
+#endif
+#ifdef EPROCUNAVAIL
+ case EPROCUNAVAIL:
+ return ("EPROCUNAVAIL");
+#endif
+#ifdef ENOLCK
+ case ENOLCK:
+ return ("ENOLCK");
+#endif
+#ifdef ENOSYS
+ case ENOSYS:
+ return ("ENOSYS");
+#endif
+#ifdef EFTYPE
+ case EFTYPE:
+ return ("EFTYPE");
+#endif
+#ifdef EAUTH
+ case EAUTH:
+ return ("EAUTH");
+#endif
+#ifdef ENEEDAUTH
+ case ENEEDAUTH:
+ return ("ENEEDAUTH");
+#endif
+#ifdef EIDRM
+ case EIDRM:
+ return ("EIDRM");
+#endif
+#ifdef ENOMSG
+ case ENOMSG:
+ return ("ENOMSG");
+#endif
+#ifdef EOVERFLOW
+ case EOVERFLOW:
+ return ("EOVERFLOW");
+#endif
+#ifdef ECANCELED
+ case ECANCELED:
+ return ("ECANCELED");
+#endif
+#ifdef EILSEQ
+ case EILSEQ:
+ return ("EILSEQ");
+#endif
+#ifdef ENOATTR
+ case ENOATTR:
+ return ("ENOATTR");
+#endif
+#ifdef EDOOFUS
+ case EDOOFUS:
+ return ("EDOOFUS");
+#endif
+#ifdef EBADMSG
+ case EBADMSG:
+ return ("EBADMSG");
+#endif
+#ifdef EMULTIHOP
+ case EMULTIHOP:
+ return ("EMULTIHOP");
+#endif
+#ifdef ENOLINK
+ case ENOLINK:
+ return ("ENOLINK");
+#endif
+#ifdef EPROTO
+ case EPROTO:
+ return ("EPROTO");
+#endif
+ default:
+ snprintf(errnum, sizeof(errnum), "%d", error);
+ return (errnum);
+ }
+}
diff --git a/tools/regression/fstest/tests/chflags/00.t b/tools/regression/fstest/tests/chflags/00.t
new file mode 100644
index 0000000..af144b0
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/00.t
@@ -0,0 +1,178 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags changes flags"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..191"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n2} 0755
+cdir=`pwd`
+cd ${n2}
+
+expect 0 create ${n0} 0644
+expect none stat ${n0} flags
+expect 0 chflags ${n0} UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE,SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK
+expect UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE,SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK stat ${n0} flags
+expect 0 chflags ${n0} UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE
+expect UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE stat ${n0} flags
+expect 0 chflags ${n0} SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK
+expect SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK stat ${n0} flags
+expect 0 chflags ${n0} none
+expect none stat ${n0} flags
+expect 0 unlink ${n0}
+
+expect 0 mkdir ${n0} 0644
+expect none stat ${n0} flags
+expect 0 chflags ${n0} UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE,SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK
+expect UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE,SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK stat ${n0} flags
+expect 0 chflags ${n0} UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE
+expect UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE stat ${n0} flags
+expect 0 chflags ${n0} SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK
+expect SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK stat ${n0} flags
+expect 0 chflags ${n0} none
+expect none stat ${n0} flags
+expect 0 rmdir ${n0}
+
+expect 0 mkfifo ${n0} 0644
+expect none stat ${n0} flags
+expect 0 chflags ${n0} UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE,SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK
+expect UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE,SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK stat ${n0} flags
+expect 0 chflags ${n0} UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE
+expect UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE stat ${n0} flags
+expect 0 chflags ${n0} SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK
+expect SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK stat ${n0} flags
+expect 0 chflags ${n0} none
+expect none stat ${n0} flags
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 symlink ${n0} ${n1}
+expect none stat ${n1} flags
+expect none lstat ${n1} flags
+expect 0 chflags ${n1} UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE,SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK
+expect UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE,SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK stat ${n1} flags
+expect none lstat ${n1} flags
+expect 0 chflags ${n1} UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE
+expect UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE stat ${n1} flags
+expect none lstat ${n1} flags
+expect 0 chflags ${n1} SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK
+expect SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK stat ${n1} flags
+expect none lstat ${n1} flags
+expect 0 chflags ${n1} none
+expect none stat ${n1} flags
+expect none lstat ${n1} flags
+expect 0 unlink ${n1}
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 symlink ${n0} ${n1}
+expect none stat ${n1} flags
+expect none lstat ${n1} flags
+expect 0 lchflags ${n1} UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE,SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK
+expect UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE,SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK lstat ${n1} flags
+expect none stat ${n1} flags
+expect 0 lchflags ${n1} UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE
+expect UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE lstat ${n1} flags
+expect none stat ${n1} flags
+expect 0 lchflags ${n1} SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK
+expect SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK lstat ${n1} flags
+expect none stat ${n1} flags
+expect 0 lchflags ${n1} none
+expect none lstat ${n1} flags
+expect none stat ${n1} flags
+expect 0 unlink ${n1}
+expect 0 unlink ${n0}
+
+# successful chflags(2) updates ctime.
+expect 0 create ${n0} 0644
+for flag in UF_NODUMP UF_IMMUTABLE UF_APPEND UF_NOUNLINK UF_OPAQUE SF_ARCHIVED SF_IMMUTABLE SF_APPEND SF_NOUNLINK none; do
+ ctime1=`${fstest} stat ${n0} ctime`
+ sleep 1
+ expect 0 chflags ${n0} ${flag}
+ ctime2=`${fstest} stat ${n0} ctime`
+ test_check $ctime1 -lt $ctime2
+done
+expect 0 unlink ${n0}
+
+expect 0 mkdir ${n0} 0755
+for flag in UF_NODUMP UF_IMMUTABLE UF_APPEND UF_NOUNLINK UF_OPAQUE SF_ARCHIVED SF_IMMUTABLE SF_APPEND SF_NOUNLINK none; do
+ ctime1=`${fstest} stat ${n0} ctime`
+ sleep 1
+ expect 0 chflags ${n0} ${flag}
+ ctime2=`${fstest} stat ${n0} ctime`
+ test_check $ctime1 -lt $ctime2
+done
+expect 0 rmdir ${n0}
+
+expect 0 mkfifo ${n0} 0644
+for flag in UF_NODUMP UF_IMMUTABLE UF_APPEND UF_NOUNLINK UF_OPAQUE SF_ARCHIVED SF_IMMUTABLE SF_APPEND SF_NOUNLINK none; do
+ ctime1=`${fstest} stat ${n0} ctime`
+ sleep 1
+ expect 0 chflags ${n0} ${flag}
+ ctime2=`${fstest} stat ${n0} ctime`
+ test_check $ctime1 -lt $ctime2
+done
+expect 0 unlink ${n0}
+
+expect 0 symlink ${n1} ${n0}
+for flag in UF_NODUMP UF_IMMUTABLE UF_APPEND UF_NOUNLINK UF_OPAQUE SF_ARCHIVED SF_IMMUTABLE SF_APPEND SF_NOUNLINK none; do
+ ctime1=`${fstest} lstat ${n0} ctime`
+ sleep 1
+ expect 0 lchflags ${n0} ${flag}
+ ctime2=`${fstest} lstat ${n0} ctime`
+ test_check $ctime1 -lt $ctime2
+done
+expect 0 unlink ${n0}
+
+# unsuccessful chflags(2) does not update ctime.
+expect 0 create ${n0} 0644
+for flag in UF_IMMUTABLE SF_IMMUTABLE none; do
+ ctime1=`${fstest} stat ${n0} ctime`
+ sleep 1
+ expect EPERM -u 65534 chflags ${n0} ${flag}
+ ctime2=`${fstest} stat ${n0} ctime`
+ test_check $ctime1 -eq $ctime2
+done
+expect 0 unlink ${n0}
+
+expect 0 mkdir ${n0} 0755
+for flag in UF_IMMUTABLE SF_IMMUTABLE none; do
+ ctime1=`${fstest} stat ${n0} ctime`
+ sleep 1
+ expect EPERM -u 65534 chflags ${n0} ${flag}
+ ctime2=`${fstest} stat ${n0} ctime`
+ test_check $ctime1 -eq $ctime2
+done
+expect 0 rmdir ${n0}
+
+expect 0 mkfifo ${n0} 0644
+for flag in UF_IMMUTABLE SF_IMMUTABLE none; do
+ ctime1=`${fstest} stat ${n0} ctime`
+ sleep 1
+ expect EPERM -u 65534 chflags ${n0} ${flag}
+ ctime2=`${fstest} stat ${n0} ctime`
+ test_check $ctime1 -eq $ctime2
+done
+expect 0 unlink ${n0}
+
+expect 0 symlink ${n1} ${n0}
+for flag in UF_IMMUTABLE SF_IMMUTABLE none; do
+ ctime1=`${fstest} lstat ${n0} ctime`
+ sleep 1
+ expect EPERM -u 65534 lchflags ${n0} ${flag}
+ ctime2=`${fstest} lstat ${n0} ctime`
+ test_check $ctime1 -eq $ctime2
+done
+expect 0 unlink ${n0}
+
+cd ${cdir}
+expect 0 rmdir ${n2}
diff --git a/tools/regression/fstest/tests/chflags/01.t b/tools/regression/fstest/tests/chflags/01.t
new file mode 100644
index 0000000..efdee5c
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/01.t
@@ -0,0 +1,20 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags returns ENOTDIR if a component of the path prefix is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..5"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+expect ENOTDIR chflags ${n0}/${n1}/test UF_IMMUTABLE
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chflags/02.t b/tools/regression/fstest/tests/chflags/02.t
new file mode 100644
index 0000000..7579061
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/02.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags returns ENAMETOOLONG if a component of a pathname exceeded 255 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..6"
+
+expect 0 create ${name255} 0644
+expect 0 chflags ${name255} UF_IMMUTABLE
+expect UF_IMMUTABLE stat ${name255} flags
+expect 0 chflags ${name255} none
+expect 0 unlink ${name255}
+expect ENAMETOOLONG chflags ${name256} UF_IMMUTABLE
diff --git a/tools/regression/fstest/tests/chflags/03.t b/tools/regression/fstest/tests/chflags/03.t
new file mode 100644
index 0000000..06a0c04
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/03.t
@@ -0,0 +1,25 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags returns ENAMETOOLONG if an entire path name exceeded 1023 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..13"
+
+expect 0 mkdir ${name255} 0755
+expect 0 mkdir ${name255}/${name255} 0755
+expect 0 mkdir ${name255}/${name255}/${name255} 0755
+expect 0 mkdir ${path1021} 0755
+expect 0 create ${path1023} 0644
+expect 0 chflags ${path1023} UF_IMMUTABLE
+expect 0 chflags ${path1023} none
+expect 0 unlink ${path1023}
+expect ENAMETOOLONG chflags ${path1024} UF_IMMUTABLE
+expect 0 rmdir ${path1021}
+expect 0 rmdir ${name255}/${name255}/${name255}
+expect 0 rmdir ${name255}/${name255}
+expect 0 rmdir ${name255}
diff --git a/tools/regression/fstest/tests/chflags/04.t b/tools/regression/fstest/tests/chflags/04.t
new file mode 100644
index 0000000..105732c
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/04.t
@@ -0,0 +1,19 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags returns ENOENT if the named file does not exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..4"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect ENOENT chflags ${n0}/${n1}/test UF_IMMUTABLE
+expect ENOENT chflags ${n0}/${n1} UF_IMMUTABLE
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chflags/05.t b/tools/regression/fstest/tests/chflags/05.t
new file mode 100644
index 0000000..a534ff5
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/05.t
@@ -0,0 +1,35 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags returns EACCES when search permission is denied for a component of the path prefix"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..16"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n1}/${n2} 0644
+expect 0 -u 65534 -g 65534 chflags ${n1}/${n2} UF_IMMUTABLE
+expect UF_IMMUTABLE -u 65534 -g 65534 stat ${n1}/${n2} flags
+expect 0 -u 65534 -g 65534 chflags ${n1}/${n2} none
+expect 0 chmod ${n1} 0644
+expect EACCES -u 65534 -g 65534 chflags ${n1}/${n2} UF_IMMUTABLE
+expect 0 chmod ${n1} 0755
+expect 0 -u 65534 -g 65534 chflags ${n1}/${n2} UF_IMMUTABLE
+expect UF_IMMUTABLE -u 65534 -g 65534 stat ${n1}/${n2} flags
+expect 0 -u 65534 -g 65534 chflags ${n1}/${n2} none
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chflags/06.t b/tools/regression/fstest/tests/chflags/06.t
new file mode 100644
index 0000000..cebfcdd
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/06.t
@@ -0,0 +1,21 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags returns ELOOP if too many symbolic links were encountered in translating the pathname"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 symlink ${n0} ${n1}
+expect 0 symlink ${n1} ${n0}
+expect ELOOP chflags ${n0}/test UF_IMMUTABLE
+expect ELOOP chflags ${n1}/test UF_IMMUTABLE
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
diff --git a/tools/regression/fstest/tests/chflags/07.t b/tools/regression/fstest/tests/chflags/07.t
new file mode 100644
index 0000000..ef7c19c
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/07.t
@@ -0,0 +1,54 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags returns EPERM when the effective user ID does not match the owner of the file and the effective user ID is not the super-user"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..30"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+
+expect 0 create ${n1} 0644
+expect EPERM -u 65534 -g 65534 chflags ${n1} UF_IMMUTABLE
+expect none stat ${n1} flags
+expect 0 chown ${n1} 65534 65534
+expect EPERM -u 65533 -g 65533 chflags ${n1} UF_IMMUTABLE
+expect none stat ${n1} flags
+expect 0 unlink ${n1}
+
+expect 0 mkdir ${n1} 0755
+expect EPERM -u 65534 -g 65534 chflags ${n1} UF_IMMUTABLE
+expect none stat ${n1} flags
+expect 0 chown ${n1} 65534 65534
+expect EPERM -u 65533 -g 65533 chflags ${n1} UF_IMMUTABLE
+expect none stat ${n1} flags
+expect 0 rmdir ${n1}
+
+expect 0 mkfifo ${n1} 0644
+expect EPERM -u 65534 -g 65534 chflags ${n1} UF_IMMUTABLE
+expect none stat ${n1} flags
+expect 0 chown ${n1} 65534 65534
+expect EPERM -u 65533 -g 65533 chflags ${n1} UF_IMMUTABLE
+expect none stat ${n1} flags
+expect 0 unlink ${n1}
+
+expect 0 symlink ${n2} ${n1}
+expect EPERM -u 65534 -g 65534 lchflags ${n1} UF_IMMUTABLE
+expect none lstat ${n1} flags
+expect 0 lchown ${n1} 65534 65534
+expect EPERM -u 65533 -g 65533 lchflags ${n1} UF_IMMUTABLE
+expect none lstat ${n1} flags
+expect 0 unlink ${n1}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chflags/08.t b/tools/regression/fstest/tests/chflags/08.t
new file mode 100644
index 0000000..9fa97b7
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/08.t
@@ -0,0 +1,70 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags returns EPERM when one of SF_IMMUTABLE, SF_APPEND, or SF_NOUNLINK is set and the user is not the super-user"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..78"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+
+expect 0 create ${n1} 0644
+expect 0 chown ${n1} 65534 65534
+for flag in SF_IMMUTABLE SF_APPEND SF_NOUNLINK; do
+ expect 0 chflags ${n1} ${flag}
+ expect EPERM -u 65533 -g 65533 chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+ expect EPERM -u 65534 -g 65534 chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+done
+expect 0 chflags ${n1} none
+expect 0 unlink ${n1}
+
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+for flag in SF_IMMUTABLE SF_APPEND SF_NOUNLINK; do
+ expect 0 chflags ${n1} ${flag}
+ expect EPERM -u 65533 -g 65533 chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+ expect EPERM -u 65534 -g 65534 chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+done
+expect 0 chflags ${n1} none
+expect 0 rmdir ${n1}
+
+expect 0 mkfifo ${n1} 0644
+expect 0 chown ${n1} 65534 65534
+for flag in SF_IMMUTABLE SF_APPEND SF_NOUNLINK; do
+ expect 0 chflags ${n1} ${flag}
+ expect EPERM -u 65533 -g 65533 chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+ expect EPERM -u 65534 -g 65534 chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+done
+expect 0 chflags ${n1} none
+expect 0 unlink ${n1}
+
+expect 0 symlink ${n2} ${n1}
+expect 0 lchown ${n1} 65534 65534
+for flag in SF_IMMUTABLE SF_APPEND SF_NOUNLINK; do
+ expect 0 lchflags ${n1} ${flag}
+ expect EPERM -u 65533 -g 65533 lchflags ${n1} UF_IMMUTABLE
+ expect ${flag} lstat ${n1} flags
+ expect EPERM -u 65534 -g 65534 lchflags ${n1} UF_IMMUTABLE
+ expect ${flag} lstat ${n1} flags
+done
+expect 0 lchflags ${n1} none
+expect 0 unlink ${n1}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chflags/09.t b/tools/regression/fstest/tests/chflags/09.t
new file mode 100644
index 0000000..7b6a2cb
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/09.t
@@ -0,0 +1,82 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags returns EPERM when one of SF_IMMUTABLE, SF_APPEND, or SF_NOUNLINK is set and securelevel is greater than 0"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..102"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+old=`sysctl -n security.jail.chflags_allowed`
+sysctl security.jail.chflags_allowed=1 >/dev/null
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+
+expect 0 create ${n1} 0644
+expect 0 chown ${n1} 65534 65534
+for flag in SF_IMMUTABLE SF_APPEND SF_NOUNLINK; do
+ expect 0 chflags ${n1} ${flag}
+ jexpect 1 `pwd` EPERM chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+ jexpect 1 `pwd` EPERM -u 65533 -g 65533 chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+ jexpect 1 `pwd` EPERM -u 65534 -g 65534 chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+done
+expect 0 chflags ${n1} none
+expect 0 unlink ${n1}
+
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+for flag in SF_IMMUTABLE SF_APPEND SF_NOUNLINK; do
+ expect 0 chflags ${n1} ${flag}
+ jexpect 1 `pwd` EPERM chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+ jexpect 1 `pwd` EPERM -u 65533 -g 65533 chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+ jexpect 1 `pwd` EPERM -u 65534 -g 65534 chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+done
+expect 0 chflags ${n1} none
+expect 0 rmdir ${n1}
+
+expect 0 mkfifo ${n1} 0644
+expect 0 chown ${n1} 65534 65534
+for flag in SF_IMMUTABLE SF_APPEND SF_NOUNLINK; do
+ expect 0 chflags ${n1} ${flag}
+ jexpect 1 `pwd` EPERM chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+ jexpect 1 `pwd` EPERM -u 65533 -g 65533 chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+ jexpect 1 `pwd` EPERM -u 65534 -g 65534 chflags ${n1} UF_IMMUTABLE
+ expect ${flag} stat ${n1} flags
+done
+expect 0 chflags ${n1} none
+expect 0 unlink ${n1}
+
+expect 0 symlink ${n2} ${n1}
+expect 0 lchown ${n1} 65534 65534
+for flag in SF_IMMUTABLE SF_APPEND SF_NOUNLINK; do
+ expect 0 lchflags ${n1} ${flag}
+ jexpect 1 `pwd` EPERM lchflags ${n1} UF_IMMUTABLE
+ expect ${flag} lstat ${n1} flags
+ jexpect 1 `pwd` EPERM -u 65533 -g 65533 lchflags ${n1} UF_IMMUTABLE
+ expect ${flag} lstat ${n1} flags
+ jexpect 1 `pwd` EPERM -u 65534 -g 65534 lchflags ${n1} UF_IMMUTABLE
+ expect ${flag} lstat ${n1} flags
+done
+expect 0 lchflags ${n1} none
+expect 0 unlink ${n1}
+
+sysctl security.jail.chflags_allowed=${old} >/dev/null
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chflags/10.t b/tools/regression/fstest/tests/chflags/10.t
new file mode 100644
index 0000000..57b33f4
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/10.t
@@ -0,0 +1,62 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags returns EPERM if non-super-user tries to set one of SF_IMMUTABLE, SF_APPEND, or SF_NOUNLINK"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..62"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+
+expect 0 create ${n1} 0644
+expect 0 chown ${n1} 65534 65534
+for flag in SF_IMMUTABLE SF_APPEND SF_NOUNLINK; do
+ expect EPERM -u 65533 -g 65533 chflags ${n1} ${flag}
+ expect none stat ${n1} flags
+ expect EPERM -u 65534 -g 65534 chflags ${n1} ${flag}
+ expect none stat ${n1} flags
+done
+expect 0 unlink ${n1}
+
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+for flag in SF_IMMUTABLE SF_APPEND SF_NOUNLINK; do
+ expect EPERM -u 65533 -g 65533 chflags ${n1} ${flag}
+ expect none stat ${n1} flags
+ expect EPERM -u 65534 -g 65534 chflags ${n1} ${flag}
+ expect none stat ${n1} flags
+done
+expect 0 rmdir ${n1}
+
+expect 0 mkfifo ${n1} 0644
+expect 0 chown ${n1} 65534 65534
+for flag in SF_IMMUTABLE SF_APPEND SF_NOUNLINK; do
+ expect EPERM -u 65533 -g 65533 chflags ${n1} ${flag}
+ expect none stat ${n1} flags
+ expect EPERM -u 65534 -g 65534 chflags ${n1} ${flag}
+ expect none stat ${n1} flags
+done
+expect 0 unlink ${n1}
+
+expect 0 symlink ${n2} ${n1}
+expect 0 lchown ${n1} 65534 65534
+for flag in SF_IMMUTABLE SF_APPEND SF_NOUNLINK; do
+ expect EPERM -u 65533 -g 65533 lchflags ${n1} ${flag}
+ expect none lstat ${n1} flags
+ expect EPERM -u 65534 -g 65534 lchflags ${n1} ${flag}
+ expect none lstat ${n1} flags
+done
+expect 0 unlink ${n1}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chflags/11.t b/tools/regression/fstest/tests/chflags/11.t
new file mode 100644
index 0000000..6c3887f
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/11.t
@@ -0,0 +1,70 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags returns EPERM if a user tries to set or remove the SF_SNAPSHOT flag"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..46"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+
+expect 0 create ${n1} 0644
+expect EPERM -u 65534 -g 65534 chflags ${n1} SF_SNAPSHOT
+expect none stat ${n1} flags
+expect EPERM chflags ${n1} SF_SNAPSHOT
+expect none stat ${n1} flags
+expect 0 chown ${n1} 65534 65534
+expect EPERM -u 65534 -g 65534 chflags ${n1} SF_SNAPSHOT
+expect none stat ${n1} flags
+expect EPERM chflags ${n1} SF_SNAPSHOT
+expect none stat ${n1} flags
+expect 0 unlink ${n1}
+
+expect 0 mkdir ${n1} 0644
+expect EPERM -u 65534 -g 65534 chflags ${n1} SF_SNAPSHOT
+expect none stat ${n1} flags
+expect EPERM chflags ${n1} SF_SNAPSHOT
+expect none stat ${n1} flags
+expect 0 chown ${n1} 65534 65534
+expect EPERM -u 65534 -g 65534 chflags ${n1} SF_SNAPSHOT
+expect none stat ${n1} flags
+expect EPERM chflags ${n1} SF_SNAPSHOT
+expect none stat ${n1} flags
+expect 0 rmdir ${n1}
+
+expect 0 mkfifo ${n1} 0644
+expect EPERM -u 65534 -g 65534 chflags ${n1} SF_SNAPSHOT
+expect none stat ${n1} flags
+expect EPERM chflags ${n1} SF_SNAPSHOT
+expect none stat ${n1} flags
+expect 0 chown ${n1} 65534 65534
+expect EPERM -u 65534 -g 65534 chflags ${n1} SF_SNAPSHOT
+expect none stat ${n1} flags
+expect EPERM chflags ${n1} SF_SNAPSHOT
+expect none stat ${n1} flags
+expect 0 unlink ${n1}
+
+expect 0 symlink ${n2} ${n1}
+expect EPERM -u 65534 -g 65534 lchflags ${n1} SF_SNAPSHOT
+expect none lstat ${n1} flags
+expect EPERM lchflags ${n1} SF_SNAPSHOT
+expect none lstat ${n1} flags
+expect 0 lchown ${n1} 65534 65534
+expect EPERM -u 65534 -g 65534 lchflags ${n1} SF_SNAPSHOT
+expect none lstat ${n1} flags
+expect EPERM lchflags ${n1} SF_SNAPSHOT
+expect none lstat ${n1} flags
+expect 0 unlink ${n1}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chflags/12.t b/tools/regression/fstest/tests/chflags/12.t
new file mode 100644
index 0000000..7b03436
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/12.t
@@ -0,0 +1,43 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags returns EROFS if the named file resides on a read-only file system"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..14"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 create ${n0}/${n1} 0644
+ expect 0 chflags ${n0}/${n1} UF_IMMUTABLE
+ expect UF_IMMUTABLE stat ${n0}/${n1} flags
+ expect 0 chflags ${n0}/${n1} none
+ expect none stat ${n0}/${n1} flags
+ mount -ur /dev/md${n}
+ expect EROFS chflags ${n0}/${n1} UF_IMMUTABLE
+ expect none stat ${n0}/${n1} flags
+ mount -uw /dev/md${n}
+ expect 0 chflags ${n0}/${n1} UF_IMMUTABLE
+ expect UF_IMMUTABLE stat ${n0}/${n1} flags
+ expect 0 chflags ${n0}/${n1} none
+ expect none stat ${n0}/${n1} flags
+ expect 0 unlink ${n0}/${n1}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/chflags/13.t b/tools/regression/fstest/tests/chflags/13.t
new file mode 100644
index 0000000..edab3a9
--- /dev/null
+++ b/tools/regression/fstest/tests/chflags/13.t
@@ -0,0 +1,14 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chflags returns EFAULT if the path argument points outside the process's allocated address space"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..2"
+
+expect EFAULT chflags NULL UF_IMMUTABLE
+expect EFAULT chflags DEADCODE UF_IMMUTABLE
diff --git a/tools/regression/fstest/tests/chmod/00.t b/tools/regression/fstest/tests/chmod/00.t
new file mode 100644
index 0000000..086f1ec
--- /dev/null
+++ b/tools/regression/fstest/tests/chmod/00.t
@@ -0,0 +1,161 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chmod changes permission"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+if supported lchmod; then
+ echo "1..77"
+else
+ echo "1..58"
+fi
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n2} 0755
+cdir=`pwd`
+cd ${n2}
+
+expect 0 create ${n0} 0644
+expect 0644 stat ${n0} mode
+expect 0 chmod ${n0} 0111
+expect 0111 stat ${n0} mode
+expect 0 unlink ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect 0755 stat ${n0} mode
+expect 0 chmod ${n0} 0753
+expect 0753 stat ${n0} mode
+expect 0 rmdir ${n0}
+
+expect 0 mkfifo ${n0} 0644
+expect 0644 stat ${n0} mode
+expect 0 chmod ${n0} 0310
+expect 0310 stat ${n0} mode
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 symlink ${n0} ${n1}
+expect 0644 stat ${n1} mode
+expect 0 chmod ${n1} 0321
+expect 0321 stat ${n1} mode
+expect 0321 lstat ${n0} mode
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
+
+if supported lchmod; then
+ expect 0 create ${n0} 0644
+ expect 0 symlink ${n0} ${n1}
+ expect 0644 stat ${n1} mode
+ expect 0 lchmod ${n1} 0321
+ expect 0321 lstat ${n1} mode
+ expect 0 lchmod ${n1} 0531
+ expect 0531 lstat ${n1} mode
+ expect 0644 stat ${n0} mode
+ expect 0644 stat ${n1} mode
+ expect 0 unlink ${n0}
+ expect 0 unlink ${n1}
+fi
+
+# successful chmod(2) updates ctime.
+expect 0 create ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 chmod ${n0} 0111
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n0}
+
+expect 0 mkdir ${n0} 0755
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 chmod ${n0} 0753
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 rmdir ${n0}
+
+expect 0 mkfifo ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 chmod ${n0} 0310
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n0}
+
+if supported lchmod; then
+ expect 0 symlink ${n1} ${n0}
+ ctime1=`${fstest} lstat ${n0} ctime`
+ sleep 1
+ expect 0 lchmod ${n0} 0321
+ ctime2=`${fstest} lstat ${n0} ctime`
+ test_check $ctime1 -lt $ctime2
+ expect 0 unlink ${n0}
+fi
+
+# unsuccessful chmod(2) does not update ctime.
+expect 0 create ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect EPERM -u 65534 chmod ${n0} 0111
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+
+expect 0 mkdir ${n0} 0755
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect EPERM -u 65534 chmod ${n0} 0753
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 rmdir ${n0}
+
+expect 0 mkfifo ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect EPERM -u 65534 chmod ${n0} 0310
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+
+if supported lchmod; then
+ expect 0 symlink ${n1} ${n0}
+ ctime1=`${fstest} lstat ${n0} ctime`
+ sleep 1
+ expect EPERM -u 65534 lchmod ${n0} 0321
+ ctime2=`${fstest} lstat ${n0} ctime`
+ test_check $ctime1 -eq $ctime2
+ expect 0 unlink ${n0}
+fi
+
+# POSIX: If the calling process does not have appropriate privileges, and if
+# the group ID of the file does not match the effective group ID or one of the
+# supplementary group IDs and if the file is a regular file, bit S_ISGID
+# (set-group-ID on execution) in the file's mode shall be cleared upon
+# successful return from chmod().
+
+expect 0 create ${n0} 0755
+expect 0 chown ${n0} 65535 65535
+expect 0 -u 65535 -g 65535 chmod ${n0} 02755
+expect 02755 stat ${n0} mode
+expect 0 -u 65535 -g 65535 chmod ${n0} 0755
+expect 0755 stat ${n0} mode
+
+# Unfortunately FreeBSD doesn't clear set-gid bit, but returns EPERM instead.
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ expect EPERM -u 65535 -g 65534 chmod ${n0} 02755
+ expect 0755 stat ${n0} mode
+ ;;
+*)
+ expect 0 -u 65535 -g 65534 chmod ${n0} 02755
+ expect 0755 stat ${n0} mode
+ ;;
+esac
+expect 0 unlink ${n0}
+
+cd ${cdir}
+expect 0 rmdir ${n2}
diff --git a/tools/regression/fstest/tests/chmod/01.t b/tools/regression/fstest/tests/chmod/01.t
new file mode 100644
index 0000000..469daa4
--- /dev/null
+++ b/tools/regression/fstest/tests/chmod/01.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chmod returns ENOTDIR if a component of the path prefix is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..5"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+expect ENOTDIR chmod ${n0}/${n1}/test 0644
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chmod/02.t b/tools/regression/fstest/tests/chmod/02.t
new file mode 100644
index 0000000..c6343a6
--- /dev/null
+++ b/tools/regression/fstest/tests/chmod/02.t
@@ -0,0 +1,15 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chmod returns ENAMETOOLONG if a component of a pathname exceeded 255 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..5"
+
+expect 0 create ${name255} 0644
+expect 0 chmod ${name255} 0620
+expect 0620 stat ${name255} mode
+expect 0 unlink ${name255}
+expect ENAMETOOLONG chmod ${name256} 0620
diff --git a/tools/regression/fstest/tests/chmod/03.t b/tools/regression/fstest/tests/chmod/03.t
new file mode 100644
index 0000000..7b424d0
--- /dev/null
+++ b/tools/regression/fstest/tests/chmod/03.t
@@ -0,0 +1,22 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chmod returns ENAMETOOLONG if an entire path name exceeded 1023 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+expect 0 mkdir ${name255} 0755
+expect 0 mkdir ${name255}/${name255} 0755
+expect 0 mkdir ${name255}/${name255}/${name255} 0755
+expect 0 mkdir ${path1021} 0755
+expect 0 create ${path1023} 0644
+expect 0 chmod ${path1023} 0642
+expect 0 unlink ${path1023}
+expect ENAMETOOLONG chmod ${path1024} 0642
+expect 0 rmdir ${path1021}
+expect 0 rmdir ${name255}/${name255}/${name255}
+expect 0 rmdir ${name255}/${name255}
+expect 0 rmdir ${name255}
diff --git a/tools/regression/fstest/tests/chmod/04.t b/tools/regression/fstest/tests/chmod/04.t
new file mode 100644
index 0000000..a8987c2
--- /dev/null
+++ b/tools/regression/fstest/tests/chmod/04.t
@@ -0,0 +1,17 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chmod returns ENOENT if the named file does not exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..4"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect ENOENT chmod ${n0}/${n1}/test 0644
+expect ENOENT chmod ${n0}/${n1} 0644
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chmod/05.t b/tools/regression/fstest/tests/chmod/05.t
new file mode 100644
index 0000000..31fe859
--- /dev/null
+++ b/tools/regression/fstest/tests/chmod/05.t
@@ -0,0 +1,31 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chmod returns EACCES when search permission is denied for a component of the path prefix"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..14"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n1}/${n2} 0644
+expect 0 -u 65534 -g 65534 chmod ${n1}/${n2} 0642
+expect 0642 -u 65534 -g 65534 stat ${n1}/${n2} mode
+expect 0 chmod ${n1} 0644
+expect EACCES -u 65534 -g 65534 chmod ${n1}/${n2} 0620
+expect 0 chmod ${n1} 0755
+expect 0 -u 65534 -g 65534 chmod ${n1}/${n2} 0420
+expect 0420 -u 65534 -g 65534 stat ${n1}/${n2} mode
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chmod/06.t b/tools/regression/fstest/tests/chmod/06.t
new file mode 100644
index 0000000..fc5f362
--- /dev/null
+++ b/tools/regression/fstest/tests/chmod/06.t
@@ -0,0 +1,19 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chmod returns ELOOP if too many symbolic links were encountered in translating the pathname"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 symlink ${n0} ${n1}
+expect 0 symlink ${n1} ${n0}
+expect ELOOP chmod ${n0}/test 0644
+expect ELOOP chmod ${n1}/test 0644
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
diff --git a/tools/regression/fstest/tests/chmod/07.t b/tools/regression/fstest/tests/chmod/07.t
new file mode 100644
index 0000000..dfa1b27
--- /dev/null
+++ b/tools/regression/fstest/tests/chmod/07.t
@@ -0,0 +1,31 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chmod returns EPERM if the operation would change the ownership, but the effective user ID is not the super-user"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..14"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n1}/${n2} 0644
+expect 0 -u 65534 -g 65534 chmod ${n1}/${n2} 0642
+expect 0642 stat ${n1}/${n2} mode
+expect EPERM -u 65533 -g 65533 chmod ${n1}/${n2} 0641
+expect 0642 stat ${n1}/${n2} mode
+expect 0 chown ${n1}/${n2} 0 0
+expect EPERM -u 65534 -g 65534 chmod ${n1}/${n2} 0641
+expect 0642 stat ${n1}/${n2} mode
+expect 0 unlink ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chmod/08.t b/tools/regression/fstest/tests/chmod/08.t
new file mode 100644
index 0000000..110bace
--- /dev/null
+++ b/tools/regression/fstest/tests/chmod/08.t
@@ -0,0 +1,59 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chmod returns EPERM if the named file has its immutable or append-only flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..40"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM chmod ${n0} 0600
+expect 0644 stat ${n0} mode
+expect 0 chflags ${n0} none
+expect 0 chmod ${n0} 0600
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM chmod ${n0} 0600
+expect 0644 stat ${n0} mode
+expect 0 chflags ${n0} none
+expect 0 chmod ${n0} 0600
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_APPEND
+expect EPERM chmod ${n0} 0600
+expect 0644 stat ${n0} mode
+expect 0 chflags ${n0} none
+expect 0 chmod ${n0} 0600
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_APPEND
+expect EPERM chmod ${n0} 0600
+expect 0644 stat ${n0} mode
+expect 0 chflags ${n0} none
+expect 0 chmod ${n0} 0600
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_NOUNLINK
+expect 0 chmod ${n0} 0600
+expect 0600 stat ${n0} mode
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_NOUNLINK
+expect 0 chmod ${n0} 0600
+expect 0600 stat ${n0} mode
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/chmod/09.t b/tools/regression/fstest/tests/chmod/09.t
new file mode 100644
index 0000000..edf1f3a
--- /dev/null
+++ b/tools/regression/fstest/tests/chmod/09.t
@@ -0,0 +1,37 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chmod returns EROFS if the named file resides on a read-only file system"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..10"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 create ${n0}/${n1} 0644
+ expect 0 chmod ${n0}/${n1} 0640
+ expect 0640 stat ${n0}/${n1} mode
+ mount -ur /dev/md${n}
+ expect EROFS chmod ${n0}/${n1} 0600
+ expect 0640 stat ${n0}/${n1} mode
+ mount -uw /dev/md${n}
+ expect 0 chmod ${n0}/${n1} 0600
+ expect 0600 stat ${n0}/${n1} mode
+ expect 0 unlink ${n0}/${n1}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/chmod/10.t b/tools/regression/fstest/tests/chmod/10.t
new file mode 100644
index 0000000..867a653
--- /dev/null
+++ b/tools/regression/fstest/tests/chmod/10.t
@@ -0,0 +1,12 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chmod returns EFAULT if the path argument points outside the process's allocated address space"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..2"
+
+expect EFAULT chmod NULL 0644
+expect EFAULT chmod DEADCODE 0644
diff --git a/tools/regression/fstest/tests/chmod/11.t b/tools/regression/fstest/tests/chmod/11.t
new file mode 100644
index 0000000..f7bc056
--- /dev/null
+++ b/tools/regression/fstest/tests/chmod/11.t
@@ -0,0 +1,53 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chmod returns EFTYPE if the effective user ID is not the super-user, the mode includes the sticky bit (S_ISVTX), and path does not refer to a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..20"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+
+expect 0 mkdir ${n1} 0755
+expect 0 chmod ${n1} 01755
+expect 01755 stat ${n1} mode
+expect 0 rmdir ${n1}
+
+expect 0 create ${n1} 0644
+expect 0 chmod ${n1} 01644
+expect 01644 stat ${n1} mode
+expect 0 unlink ${n1}
+
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 chmod ${n1} 01755
+expect 01755 stat ${n1} mode
+expect 0 rmdir ${n1}
+
+expect 0 create ${n1} 0644
+expect 0 chown ${n1} 65534 65534
+case "${os}" in
+FreeBSD)
+ expect EFTYPE -u 65534 -g 65534 chmod ${n1} 01644
+ expect 0644 stat ${n1} mode
+ ;;
+SunOS)
+ expect 0 -u 65534 -g 65534 chmod ${n1} 01644
+ expect 0644 stat ${n1} mode
+ ;;
+Linux)
+ expect 0 -u 65534 -g 65534 chmod ${n1} 01644
+ expect 01644 stat ${n1} mode
+ ;;
+esac
+expect 0 unlink ${n1}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chown/00.t b/tools/regression/fstest/tests/chown/00.t
new file mode 100644
index 0000000..154129a
--- /dev/null
+++ b/tools/regression/fstest/tests/chown/00.t
@@ -0,0 +1,304 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chown changes ownership"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+if supported lchmod; then
+ echo "1..186"
+else
+ echo "1..171"
+fi
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n2} 0755
+cdir=`pwd`
+cd ${n2}
+
+# super-user can always modify ownership
+# 2
+expect 0 create ${n0} 0644
+expect 0 chown ${n0} 123 456
+expect 123,456 lstat ${n0} uid,gid
+expect 0 chown ${n0} 0 0
+expect 0,0 lstat ${n0} uid,gid
+expect 0 unlink ${n0}
+# 8
+expect 0 mkfifo ${n0} 0644
+expect 0 chown ${n0} 123 456
+expect 123,456 lstat ${n0} uid,gid
+expect 0 chown ${n0} 0 0
+expect 0,0 lstat ${n0} uid,gid
+expect 0 unlink ${n0}
+# 14
+expect 0 mkdir ${n0} 0755
+expect 0 chown ${n0} 123 456
+expect 123,456 lstat ${n0} uid,gid
+expect 0 chown ${n0} 0 0
+expect 0,0 lstat ${n0} uid,gid
+expect 0 rmdir ${n0}
+# 20
+expect 0 create ${n0} 0644
+expect 0 symlink ${n0} ${n1}
+expect 0 chown ${n1} 123 456
+expect 123,456 stat ${n1} uid,gid
+expect 123,456 stat ${n0} uid,gid
+expect 0 lchown ${n1} 135 579
+expect 135,579 lstat ${n1} uid,gid
+expect 123,456 stat ${n1} uid,gid
+expect 123,456 stat ${n0} uid,gid
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
+
+# non-super-user can modify file group if he is owner of a file and
+# gid he is setting is in his groups list.
+# 31
+expect 0 create ${n0} 0644
+expect 0 chown ${n0} 65534 65533
+expect 65534,65533 lstat ${n0} uid,gid
+expect 0 -u 65534 -g 65532,65531 chown ${n0} -1 65532
+expect 65534,65532 lstat ${n0} uid,gid
+expect 0 -u 65534 -g 65532,65531 chown ${n0} 65534 65531
+expect 65534,65531 lstat ${n0} uid,gid
+expect 0 unlink ${n0}
+
+# chown(2) return 0 if user is not owner of a file, but chown(2) is called
+# with both uid and gid equal to -1.
+# 39
+expect 0 create ${n0} 0644
+expect 0 chown ${n0} 65534 65533
+expect 0 -u 65532 -g 65531 chown ${n0} -1 -1
+expect 0 unlink ${n0}
+
+# when super-user calls chown(2), set-uid and set-gid bits are not removed.
+# 43
+expect 0 create ${n0} 0644
+expect 0 chown ${n0} 65534 65533
+expect 0 chmod ${n0} 06555
+expect 06555 lstat ${n0} mode
+expect 0 chown ${n0} 65532 65531
+expect 06555 lstat ${n0} mode
+expect 0 unlink ${n0}
+# 50
+expect 0 create ${n0} 0644
+expect 0 chown ${n0} 0 0
+expect 0 chmod ${n0} 06555
+expect 06555 lstat ${n0} mode
+expect 0 chown ${n0} 65534 65533
+expect 06555 lstat ${n0} mode
+expect 0 unlink ${n0}
+# 57
+expect 0 create ${n0} 0644
+expect 0 chown ${n0} 65534 65533
+expect 0 chmod ${n0} 06555
+expect 06555 lstat ${n0} mode
+expect 0 chown ${n0} 0 0
+expect 06555 lstat ${n0} mode
+expect 0 unlink ${n0}
+
+# when non-super-user calls chown(2) successfully, set-uid and set-gid bits are
+# removed, except when both uid and gid are equal to -1.
+# 64
+expect 0 create ${n0} 0644
+expect 0 chown ${n0} 65534 65533
+expect 0 chmod ${n0} 06555
+expect 06555 lstat ${n0} mode
+expect 0 -u 65534 -g 65533,65532 chown ${n0} 65534 65532
+expect 0555,65534,65532 lstat ${n0} mode,uid,gid
+expect 0 chmod ${n0} 06555
+expect 06555 lstat ${n0} mode
+expect 0 -u 65534 -g 65533,65532 chown ${n0} -1 65533
+expect 0555,65534,65533 lstat ${n0} mode,uid,gid
+expect 0 chmod ${n0} 06555
+expect 06555 lstat ${n0} mode
+expect 0 -u 65534 -g 65533,65532 chown ${n0} -1 -1
+expect 06555,65534,65533 lstat ${n0} mode,uid,gid
+expect 0 unlink ${n0}
+# 79
+expect 0 mkdir ${n0} 0755
+expect 0 chown ${n0} 65534 65533
+expect 0 chmod ${n0} 06555
+expect 06555 lstat ${n0} mode
+expect 0 -u 65534 -g 65533,65532 chown ${n0} 65534 65532
+expect 0555,65534,65532 lstat ${n0} mode,uid,gid
+expect 0 chmod ${n0} 06555
+expect 06555 lstat ${n0} mode
+expect 0 -u 65534 -g 65533,65532 chown ${n0} -1 65533
+expect 0555,65534,65533 lstat ${n0} mode,uid,gid
+expect 0 chmod ${n0} 06555
+expect 06555 lstat ${n0} mode
+expect 0 -u 65534 -g 65533,65532 chown ${n0} -1 -1
+expect 06555,65534,65533 lstat ${n0} mode,uid,gid
+expect 0 rmdir ${n0}
+# 94
+if supported lchmod; then
+ expect 0 symlink ${n1} ${n0}
+ expect 0 lchown ${n0} 65534 65533
+ expect 0 lchmod ${n0} 06555
+ expect 06555 lstat ${n0} mode
+ expect 0 -u 65534 -g 65533,65532 lchown ${n0} 65534 65532
+ expect 0555,65534,65532 lstat ${n0} mode,uid,gid
+ expect 0 lchmod ${n0} 06555
+ expect 06555 lstat ${n0} mode
+ expect 0 -u 65534 -g 65533,65532 lchown ${n0} -1 65533
+ expect 0555,65534,65533 lstat ${n0} mode,uid,gid
+ expect 0 lchmod ${n0} 06555
+ expect 06555 lstat ${n0} mode
+ expect 0 -u 65534 -g 65533,65532 lchown ${n0} -1 -1
+ expect 06555,65534,65533 lstat ${n0} mode,uid,gid
+ expect 0 unlink ${n0}
+fi
+
+# successfull chown(2) call (except uid and gid equal to -1) updates ctime.
+# 109
+expect 0 create ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 chown ${n0} 65534 65533
+expect 65534,65533 lstat ${n0} uid,gid
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n0}
+# 114
+expect 0 mkdir ${n0} 0755
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 chown ${n0} 65534 65533
+expect 65534,65533 lstat ${n0} uid,gid
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 rmdir ${n0}
+# 119
+expect 0 mkfifo ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 chown ${n0} 65534 65533
+expect 65534,65533 lstat ${n0} uid,gid
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n0}
+# 124
+expect 0 symlink ${n1} ${n0}
+ctime1=`${fstest} lstat ${n0} ctime`
+sleep 1
+expect 0 lchown ${n0} 65534 65533
+expect 65534,65533 lstat ${n0} uid,gid
+ctime2=`${fstest} lstat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n0}
+# 129
+expect 0 create ${n0} 0644
+expect 0 chown ${n0} 65534 65533
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 -u 65534 -g 65532 chown ${n0} 65534 65532
+expect 65534,65532 lstat ${n0} uid,gid
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n0}
+# 135
+expect 0 mkdir ${n0} 0755
+expect 0 chown ${n0} 65534 65533
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 -u 65534 -g 65532 chown ${n0} 65534 65532
+expect 65534,65532 lstat ${n0} uid,gid
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 rmdir ${n0}
+# 141
+expect 0 mkfifo ${n0} 0644
+expect 0 chown ${n0} 65534 65533
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 chown ${n0} 65534 65533
+expect 0 -u 65534 -g 65532 chown ${n0} 65534 65532
+expect 65534,65532 lstat ${n0} uid,gid
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n0}
+# 148
+expect 0 symlink ${n1} ${n0}
+expect 0 lchown ${n0} 65534 65533
+ctime1=`${fstest} lstat ${n0} ctime`
+sleep 1
+expect 0 -u 65534 -g 65532 lchown ${n0} 65534 65532
+expect 65534,65532 lstat ${n0} uid,gid
+ctime2=`${fstest} lstat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n0}
+# 154
+expect 0 create ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 chown ${n0} -1 -1
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+# 158
+expect 0 mkdir ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 chown ${n0} -1 -1
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 rmdir ${n0}
+# 162
+expect 0 mkfifo ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 chown ${n0} -1 -1
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+# 166
+expect 0 symlink ${n1} ${n0}
+ctime1=`${fstest} lstat ${n0} ctime`
+sleep 1
+expect 0 lchown ${n0} -1 -1
+ctime2=`${fstest} lstat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+
+# unsuccessful chown(2) does not update ctime.
+# 170
+expect 0 create ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect EPERM -u 65534 chown ${n0} 65534 -1
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+# 174
+expect 0 mkdir ${n0} 0755
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect EPERM -u 65534 -g 65534 chown ${n0} -1 65534
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 rmdir ${n0}
+# 178
+expect 0 mkfifo ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect EPERM -u 65534 -g 65534 chown ${n0} 65534 65534
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+# 182
+expect 0 symlink ${n1} ${n0}
+ctime1=`${fstest} lstat ${n0} ctime`
+sleep 1
+expect EPERM -u 65534 -g 65534 lchown ${n0} 65534 65534
+ctime2=`${fstest} lstat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+
+# 186
+cd ${cdir}
+expect 0 rmdir ${n2}
diff --git a/tools/regression/fstest/tests/chown/01.t b/tools/regression/fstest/tests/chown/01.t
new file mode 100644
index 0000000..9559e6e
--- /dev/null
+++ b/tools/regression/fstest/tests/chown/01.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chown returns ENOTDIR if a component of the path prefix is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..5"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+expect ENOTDIR chown ${n0}/${n1}/test 65534 65534
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chown/02.t b/tools/regression/fstest/tests/chown/02.t
new file mode 100644
index 0000000..12e6b2e
--- /dev/null
+++ b/tools/regression/fstest/tests/chown/02.t
@@ -0,0 +1,15 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chown returns ENAMETOOLONG if a component of a pathname exceeded 255 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..5"
+
+expect 0 create ${name255} 0644
+expect 0 chown ${name255} 65534 65534
+expect 65534,65534 stat ${name255} uid,gid
+expect 0 unlink ${name255}
+expect ENAMETOOLONG chown ${name256} 65533 65533
diff --git a/tools/regression/fstest/tests/chown/03.t b/tools/regression/fstest/tests/chown/03.t
new file mode 100644
index 0000000..bb3f74b
--- /dev/null
+++ b/tools/regression/fstest/tests/chown/03.t
@@ -0,0 +1,22 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chown returns ENAMETOOLONG if an entire path name exceeded 1023 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+expect 0 mkdir ${name255} 0755
+expect 0 mkdir ${name255}/${name255} 0755
+expect 0 mkdir ${name255}/${name255}/${name255} 0755
+expect 0 mkdir ${path1021} 0755
+expect 0 create ${path1023} 0644
+expect 0 chown ${path1023} 65534 65534
+expect 0 unlink ${path1023}
+expect ENAMETOOLONG chown ${path1024} 65533 65533
+expect 0 rmdir ${path1021}
+expect 0 rmdir ${name255}/${name255}/${name255}
+expect 0 rmdir ${name255}/${name255}
+expect 0 rmdir ${name255}
diff --git a/tools/regression/fstest/tests/chown/04.t b/tools/regression/fstest/tests/chown/04.t
new file mode 100644
index 0000000..8575de7
--- /dev/null
+++ b/tools/regression/fstest/tests/chown/04.t
@@ -0,0 +1,17 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chown returns ENOENT if the named file does not exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..4"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect ENOENT chown ${n0}/${n1}/test 65534 65534
+expect ENOENT chown ${n0}/${n1} 65534 65534
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chown/05.t b/tools/regression/fstest/tests/chown/05.t
new file mode 100644
index 0000000..844ffca
--- /dev/null
+++ b/tools/regression/fstest/tests/chown/05.t
@@ -0,0 +1,32 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chown returns EACCES when search permission is denied for a component of the path prefix"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..15"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n1}/${n2} 0644
+expect 0 -u 65534 -g 65533,65534 chown ${n1}/${n2} -1 65533
+expect 65534,65533 -u 65534 -g 65534 stat ${n1}/${n2} uid,gid
+expect 0 chmod ${n1} 0644
+expect EACCES -u 65534 -g 65533,65534 chown ${n1}/${n2} -1 65534
+expect 0 chmod ${n1} 0755
+expect 65534,65533 -u 65534 -g 65534 stat ${n1}/${n2} uid,gid
+expect 0 -u 65534 -g 65533,65534 chown ${n1}/${n2} -1 65534
+expect 65534,65534 -u 65534 -g 65534 stat ${n1}/${n2} uid,gid
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chown/06.t b/tools/regression/fstest/tests/chown/06.t
new file mode 100644
index 0000000..8e6d2cc
--- /dev/null
+++ b/tools/regression/fstest/tests/chown/06.t
@@ -0,0 +1,19 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chown returns ELOOP if too many symbolic links were encountered in translating the pathname"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 symlink ${n0} ${n1}
+expect 0 symlink ${n1} ${n0}
+expect ELOOP chown ${n0}/test 65534 65534
+expect ELOOP chown ${n1}/test 65534 65534
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
diff --git a/tools/regression/fstest/tests/chown/07.t b/tools/regression/fstest/tests/chown/07.t
new file mode 100644
index 0000000..a9789eb
--- /dev/null
+++ b/tools/regression/fstest/tests/chown/07.t
@@ -0,0 +1,28 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chown returns EPERM if the operation would change the ownership, but the effective user ID is not the super-user and the process is not an owner of the file"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..11"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n1}/${n2} 0644
+expect EPERM -u 65534 -g 65534 chown ${n1}/${n2} 65533 65533
+expect EPERM -u 65533 -g 65533 chown ${n1}/${n2} 65534 65534
+expect EPERM -u 65533 -g 65533 chown ${n1}/${n2} 65533 65533
+expect EPERM -u 65534 -g 65534 chown ${n1}/${n2} -1 65533
+expect 0 unlink ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/chown/08.t b/tools/regression/fstest/tests/chown/08.t
new file mode 100644
index 0000000..9fed455
--- /dev/null
+++ b/tools/regression/fstest/tests/chown/08.t
@@ -0,0 +1,53 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chown returns EPERM if the named file has its immutable or append-only flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..34"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM chown ${n0} 65534 65534
+expect 0 chflags ${n0} none
+expect 0 chown ${n0} 65534 65534
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM chown ${n0} 65534 65534
+expect 0 chflags ${n0} none
+expect 0 chown ${n0} 65534 65534
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_APPEND
+expect EPERM chown ${n0} 65534 65534
+expect 0 chflags ${n0} none
+expect 0 chown ${n0} 65534 65534
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_APPEND
+expect EPERM chown ${n0} 65534 65534
+expect 0 chflags ${n0} none
+expect 0 chown ${n0} 65534 65534
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_NOUNLINK
+expect 0 chown ${n0} 65534 65534
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_NOUNLINK
+expect 0 chown ${n0} 65534 65534
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/chown/09.t b/tools/regression/fstest/tests/chown/09.t
new file mode 100644
index 0000000..9751f97
--- /dev/null
+++ b/tools/regression/fstest/tests/chown/09.t
@@ -0,0 +1,37 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chown returns EROFS if the named file resides on a read-only file system"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:{fs}" in
+FreeBSD:UFS)
+ echo "1..10"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 create ${n0}/${n1} 0644
+ expect 0 chown ${n0}/${n1} 65534 65534
+ expect 65534,65534 stat ${n0}/${n1} uid,gid
+ mount -ur /dev/md${n}
+ expect EROFS chown ${n0}/${n1} 65533 65533
+ expect 65534,65534 stat ${n0}/${n1} uid,gid
+ mount -uw /dev/md${n}
+ expect 0 chown ${n0}/${n1} 65533 65533
+ expect 65533,65533 stat ${n0}/${n1} uid,gid
+ expect 0 unlink ${n0}/${n1}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/chown/10.t b/tools/regression/fstest/tests/chown/10.t
new file mode 100644
index 0000000..1ef6f85
--- /dev/null
+++ b/tools/regression/fstest/tests/chown/10.t
@@ -0,0 +1,12 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="chown returns EFAULT if the path argument points outside the process's allocated address space"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..2"
+
+expect EFAULT chown NULL 65534 65534
+expect EFAULT chown DEADCODE 65534 65534
diff --git a/tools/regression/fstest/tests/conf b/tools/regression/fstest/tests/conf
new file mode 100644
index 0000000..54183e4
--- /dev/null
+++ b/tools/regression/fstest/tests/conf
@@ -0,0 +1,8 @@
+# $FreeBSD$
+# fstest configuration file
+
+# Known operating systems: FreeBSD, SunOS, Linux
+os=`uname`
+
+# Known file systems: UFS, ZFS, other
+fs="UFS"
diff --git a/tools/regression/fstest/tests/link/00.t b/tools/regression/fstest/tests/link/00.t
new file mode 100644
index 0000000..e5ac67d
--- /dev/null
+++ b/tools/regression/fstest/tests/link/00.t
@@ -0,0 +1,151 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link creates hardlinks"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..82"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+n3=`namegen`
+
+expect 0 mkdir ${n3} 0755
+cdir=`pwd`
+cd ${n3}
+
+expect 0 create ${n0} 0644
+expect regular,0644,1 lstat ${n0} type,mode,nlink
+
+expect 0 link ${n0} ${n1}
+expect regular,0644,2 lstat ${n0} type,mode,nlink
+expect regular,0644,2 lstat ${n1} type,mode,nlink
+
+expect 0 link ${n1} ${n2}
+expect regular,0644,3 lstat ${n0} type,mode,nlink
+expect regular,0644,3 lstat ${n1} type,mode,nlink
+expect regular,0644,3 lstat ${n2} type,mode,nlink
+
+expect 0 chmod ${n1} 0201
+expect 0 chown ${n1} 65534 65533
+
+expect regular,0201,3,65534,65533 lstat ${n0} type,mode,nlink,uid,gid
+expect regular,0201,3,65534,65533 lstat ${n1} type,mode,nlink,uid,gid
+expect regular,0201,3,65534,65533 lstat ${n2} type,mode,nlink,uid,gid
+
+expect 0 unlink ${n0}
+expect ENOENT lstat ${n0} type,mode,nlink,uid,gid
+expect regular,0201,2,65534,65533 lstat ${n1} type,mode,nlink,uid,gid
+expect regular,0201,2,65534,65533 lstat ${n2} type,mode,nlink,uid,gid
+
+expect 0 unlink ${n2}
+expect ENOENT lstat ${n0} type,mode,nlink,uid,gid
+expect regular,0201,1,65534,65533 lstat ${n1} type,mode,nlink,uid,gid
+expect ENOENT lstat ${n2} type,mode,nlink,uid,gid
+
+expect 0 unlink ${n1}
+expect ENOENT lstat ${n0} type,mode,nlink,uid,gid
+expect ENOENT lstat ${n1} type,mode,nlink,uid,gid
+expect ENOENT lstat ${n2} type,mode,nlink,uid,gid
+
+expect 0 mkfifo ${n0} 0644
+expect fifo,0644,1 lstat ${n0} type,mode,nlink
+
+expect 0 link ${n0} ${n1}
+expect fifo,0644,2 lstat ${n0} type,mode,nlink
+expect fifo,0644,2 lstat ${n1} type,mode,nlink
+
+expect 0 link ${n1} ${n2}
+expect fifo,0644,3 lstat ${n0} type,mode,nlink
+expect fifo,0644,3 lstat ${n1} type,mode,nlink
+expect fifo,0644,3 lstat ${n2} type,mode,nlink
+
+expect 0 chmod ${n1} 0201
+expect 0 chown ${n1} 65534 65533
+
+expect fifo,0201,3,65534,65533 lstat ${n0} type,mode,nlink,uid,gid
+expect fifo,0201,3,65534,65533 lstat ${n1} type,mode,nlink,uid,gid
+expect fifo,0201,3,65534,65533 lstat ${n2} type,mode,nlink,uid,gid
+
+expect 0 unlink ${n0}
+expect ENOENT lstat ${n0} type,mode,nlink,uid,gid
+expect fifo,0201,2,65534,65533 lstat ${n1} type,mode,nlink,uid,gid
+expect fifo,0201,2,65534,65533 lstat ${n2} type,mode,nlink,uid,gid
+
+expect 0 unlink ${n2}
+expect ENOENT lstat ${n0} type,mode,nlink,uid,gid
+expect fifo,0201,1,65534,65533 lstat ${n1} type,mode,nlink,uid,gid
+expect ENOENT lstat ${n2} type,mode,nlink,uid,gid
+
+expect 0 unlink ${n1}
+expect ENOENT lstat ${n0} type,mode,nlink,uid,gid
+expect ENOENT lstat ${n1} type,mode,nlink,uid,gid
+expect ENOENT lstat ${n2} type,mode,nlink,uid,gid
+
+# successful link(2) updates ctime.
+expect 0 create ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+dctime1=`${fstest} stat . ctime`
+dmtime1=`${fstest} stat . mtime`
+sleep 1
+expect 0 link ${n0} ${n1}
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+dctime2=`${fstest} stat . ctime`
+test_check $dctime1 -lt $dctime2
+dmtime2=`${fstest} stat . mtime`
+test_check $dctime1 -lt $dmtime2
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
+
+expect 0 mkfifo ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+dctime1=`${fstest} stat . ctime`
+dmtime1=`${fstest} stat . mtime`
+sleep 1
+expect 0 link ${n0} ${n1}
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+dctime2=`${fstest} stat . ctime`
+test_check $dctime1 -lt $dctime2
+dmtime2=`${fstest} stat . mtime`
+test_check $dctime1 -lt $dmtime2
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
+
+# unsuccessful link(2) does not update ctime.
+expect 0 create ${n0} 0644
+expect 0 chown ${n0} 65534 -1
+ctime1=`${fstest} stat ${n0} ctime`
+dctime1=`${fstest} stat . ctime`
+dmtime1=`${fstest} stat . mtime`
+sleep 1
+expect EACCES -u 65534 link ${n0} ${n1}
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+dctime2=`${fstest} stat . ctime`
+test_check $dctime1 -eq $dctime2
+dmtime2=`${fstest} stat . mtime`
+test_check $dctime1 -eq $dmtime2
+expect 0 unlink ${n0}
+
+expect 0 mkfifo ${n0} 0644
+expect 0 chown ${n0} 65534 -1
+ctime1=`${fstest} stat ${n0} ctime`
+dctime1=`${fstest} stat . ctime`
+dmtime1=`${fstest} stat . mtime`
+sleep 1
+expect EACCES -u 65534 link ${n0} ${n1}
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+dctime2=`${fstest} stat . ctime`
+test_check $dctime1 -eq $dctime2
+dmtime2=`${fstest} stat . mtime`
+test_check $dctime1 -eq $dmtime2
+expect 0 unlink ${n0}
+
+cd ${cdir}
+expect 0 rmdir ${n3}
diff --git a/tools/regression/fstest/tests/link/01.t b/tools/regression/fstest/tests/link/01.t
new file mode 100644
index 0000000..9a740ed
--- /dev/null
+++ b/tools/regression/fstest/tests/link/01.t
@@ -0,0 +1,22 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns ENOTDIR if a component of either path prefix is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..8"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+expect ENOTDIR link ${n0}/${n1}/test ${n0}/${n2}
+expect 0 create ${n0}/${n2} 0644
+expect ENOTDIR link ${n0}/${n2} ${n0}/${n1}/test
+expect 0 unlink ${n0}/${n1}
+expect 0 unlink ${n0}/${n2}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/link/02.t b/tools/regression/fstest/tests/link/02.t
new file mode 100644
index 0000000..436b627
--- /dev/null
+++ b/tools/regression/fstest/tests/link/02.t
@@ -0,0 +1,23 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns ENAMETOOLONG if a component of either pathname exceeded 255 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..10"
+
+n0=`namegen`
+
+expect 0 create ${name255} 0644
+expect 0 link ${name255} ${n0}
+expect 0 unlink ${name255}
+expect 0 link ${n0} ${name255}
+expect 0 unlink ${n0}
+expect 0 unlink ${name255}
+
+expect 0 create ${n0} 0644
+expect ENAMETOOLONG link ${n0} ${name256}
+expect 0 unlink ${n0}
+expect ENAMETOOLONG link ${name256} ${n0}
diff --git a/tools/regression/fstest/tests/link/03.t b/tools/regression/fstest/tests/link/03.t
new file mode 100644
index 0000000..8fcb77f
--- /dev/null
+++ b/tools/regression/fstest/tests/link/03.t
@@ -0,0 +1,28 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns ENAMETOOLONG if an entire length of either path name exceeded 1023 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..16"
+
+n0=`namegen`
+
+expect 0 mkdir ${name255} 0755
+expect 0 mkdir ${name255}/${name255} 0755
+expect 0 mkdir ${name255}/${name255}/${name255} 0755
+expect 0 mkdir ${path1021} 0755
+expect 0 create ${path1023} 0644
+expect 0 link ${path1023} ${n0}
+expect 0 unlink ${path1023}
+expect 0 link ${n0} ${path1023}
+expect 0 unlink ${path1023}
+expect ENAMETOOLONG link ${n0} ${path1024}
+expect 0 unlink ${n0}
+expect ENAMETOOLONG link ${path1024} ${n0}
+expect 0 rmdir ${path1021}
+expect 0 rmdir ${name255}/${name255}/${name255}
+expect 0 rmdir ${name255}/${name255}
+expect 0 rmdir ${name255}
diff --git a/tools/regression/fstest/tests/link/04.t b/tools/regression/fstest/tests/link/04.t
new file mode 100644
index 0000000..d27beef
--- /dev/null
+++ b/tools/regression/fstest/tests/link/04.t
@@ -0,0 +1,20 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns ENOENT if a component of either path prefix does not exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect ENOENT link ${n0}/${n1}/test ${n2}
+expect 0 create ${n2} 0644
+expect ENOENT link ${n2} ${n0}/${n1}/test
+expect 0 unlink ${n2}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/link/05.t b/tools/regression/fstest/tests/link/05.t
new file mode 100644
index 0000000..c1da717
--- /dev/null
+++ b/tools/regression/fstest/tests/link/05.t
@@ -0,0 +1,41 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns EMLINK if the link count of the file named by name1 would exceed 32767"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..5"
+
+ n0=`namegen`
+ n1=`namegen`
+ n2=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs -i 1 /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 create ${n0}/${n1} 0644
+ i=1
+ while :; do
+ link ${n0}/${n1} ${n0}/${i} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ break
+ fi
+ i=`expr $i + 1`
+ done
+ test_check $i -eq 32767
+
+ expect EMLINK link ${n0}/${n1} ${n0}/${n2}
+
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/link/06.t b/tools/regression/fstest/tests/link/06.t
new file mode 100644
index 0000000..3ce0919
--- /dev/null
+++ b/tools/regression/fstest/tests/link/06.t
@@ -0,0 +1,43 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns EACCES when a component of either path prefix denies search permission"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..18"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+n3=`namegen`
+n4=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 mkdir ${n2} 0755
+expect 0 chown ${n2} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n1}/${n3} 0644
+
+expect 0 -u 65534 -g 65534 link ${n1}/${n3} ${n2}/${n4}
+expect 0 -u 65534 -g 65534 unlink ${n2}/${n4}
+
+expect 0 chmod ${n1} 0644
+expect EACCES -u 65534 -g 65534 link ${n1}/${n3} ${n1}/${n4}
+expect EACCES -u 65534 -g 65534 link ${n1}/${n3} ${n2}/${n4}
+
+expect 0 chmod ${n1} 0755
+expect 0 chmod ${n2} 0644
+expect EACCES -u 65534 -g 65534 link ${n1}/${n3} ${n2}/${n4}
+
+expect 0 unlink ${n1}/${n3}
+expect 0 rmdir ${n1}
+expect 0 rmdir ${n2}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/link/07.t b/tools/regression/fstest/tests/link/07.t
new file mode 100644
index 0000000..f9d35e7
--- /dev/null
+++ b/tools/regression/fstest/tests/link/07.t
@@ -0,0 +1,41 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns EACCES when the requested link requires writing in a directory with a mode that denies write permission"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..17"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+n3=`namegen`
+n4=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 mkdir ${n2} 0755
+expect 0 chown ${n2} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n1}/${n3} 0644
+
+expect 0 -u 65534 -g 65534 link ${n1}/${n3} ${n2}/${n4}
+expect 0 -u 65534 -g 65534 unlink ${n2}/${n4}
+
+expect 0 chmod ${n2} 0555
+expect EACCES -u 65534 -g 65534 link ${n1}/${n3} ${n2}/${n4}
+expect 0 chmod ${n1} 0555
+expect EACCES -u 65534 -g 65534 link ${n1}/${n3} ${n1}/${n4}
+expect 0 chmod ${n1} 0755
+
+expect 0 unlink ${n1}/${n3}
+expect 0 rmdir ${n1}
+expect 0 rmdir ${n2}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/link/08.t b/tools/regression/fstest/tests/link/08.t
new file mode 100644
index 0000000..f9d9445
--- /dev/null
+++ b/tools/regression/fstest/tests/link/08.t
@@ -0,0 +1,24 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns ELOOP if too many symbolic links were encountered in translating one of the pathnames"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..10"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 symlink ${n0} ${n1}
+expect 0 symlink ${n1} ${n0}
+expect ELOOP link ${n0}/test ${n2}
+expect ELOOP link ${n1}/test ${n2}
+expect 0 create ${n2} 0644
+expect ELOOP link ${n2} ${n0}/test
+expect ELOOP link ${n2} ${n1}/test
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
+expect 0 unlink ${n2}
diff --git a/tools/regression/fstest/tests/link/09.t b/tools/regression/fstest/tests/link/09.t
new file mode 100644
index 0000000..224395f
--- /dev/null
+++ b/tools/regression/fstest/tests/link/09.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns ENOENT if the source file does not exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..5"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 create ${n0} 0644
+expect 0 link ${n0} ${n1}
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
+expect ENOENT link ${n0} ${n1}
diff --git a/tools/regression/fstest/tests/link/10.t b/tools/regression/fstest/tests/link/10.t
new file mode 100644
index 0000000..beb141c
--- /dev/null
+++ b/tools/regression/fstest/tests/link/10.t
@@ -0,0 +1,32 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns EEXIST if the destination file does exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..14"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 create ${n0} 0644
+
+expect 0 create ${n1} 0644
+expect EEXIST link ${n0} ${n1}
+expect 0 unlink ${n1}
+
+expect 0 mkdir ${n1} 0755
+expect EEXIST link ${n0} ${n1}
+expect 0 rmdir ${n1}
+
+expect 0 symlink test ${n1}
+expect EEXIST link ${n0} ${n1}
+expect 0 unlink ${n1}
+
+expect 0 mkfifo ${n1} 0644
+expect EEXIST link ${n0} ${n1}
+expect 0 unlink ${n1}
+
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/link/11.t b/tools/regression/fstest/tests/link/11.t
new file mode 100644
index 0000000..cf31c9e
--- /dev/null
+++ b/tools/regression/fstest/tests/link/11.t
@@ -0,0 +1,41 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns EPERM if the source file is a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+case "${os}:${fs}" in
+SunOS:UFS)
+ echo "1..10"
+
+ expect 0 mkdir ${n0} 0755
+ expect 0 link ${n0} ${n1}
+ expect 0 unlink ${n1}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ echo "1..9"
+
+ expect 0 mkdir ${n0} 0755
+ expect EPERM link ${n0} ${n1}
+ expect 0 rmdir ${n0}
+ ;;
+esac
+
+expect 0 mkdir ${n0} 0755
+expect 0 chown ${n0} 65534 65534
+cdir=`pwd`
+cd ${n0}
+
+expect 0 -u 65534 -g 65534 mkdir ${n1} 0755
+expect EPERM -u 65534 -g 65534 link ${n1} ${n2}
+expect 0 -u 65534 -g 65534 rmdir ${n1}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/link/12.t b/tools/regression/fstest/tests/link/12.t
new file mode 100644
index 0000000..1f1efdc
--- /dev/null
+++ b/tools/regression/fstest/tests/link/12.t
@@ -0,0 +1,55 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns EPERM if the source file has its immutable or append-only flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..32"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 create ${n0} 0644
+
+expect 0 link ${n0} ${n1}
+expect 0 unlink ${n1}
+
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM link ${n0} ${n1}
+expect 0 chflags ${n0} none
+expect 0 link ${n0} ${n1}
+expect 0 unlink ${n1}
+
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM link ${n0} ${n1}
+expect 0 chflags ${n0} none
+expect 0 link ${n0} ${n1}
+expect 0 unlink ${n1}
+
+expect 0 chflags ${n0} SF_APPEND
+expect EPERM link ${n0} ${n1}
+expect 0 chflags ${n0} none
+expect 0 link ${n0} ${n1}
+expect 0 unlink ${n1}
+
+expect 0 chflags ${n0} UF_APPEND
+expect EPERM link ${n0} ${n1}
+expect 0 chflags ${n0} none
+expect 0 link ${n0} ${n1}
+expect 0 unlink ${n1}
+
+expect 0 chflags ${n0} SF_NOUNLINK
+expect 0 link ${n0} ${n1}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n1}
+
+expect 0 chflags ${n0} UF_NOUNLINK
+expect 0 link ${n0} ${n1}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n1}
+
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/link/13.t b/tools/regression/fstest/tests/link/13.t
new file mode 100644
index 0000000..f6a00ea
--- /dev/null
+++ b/tools/regression/fstest/tests/link/13.t
@@ -0,0 +1,56 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns EPERM if the parent directory of the destination file has its immutable flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..32"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+
+expect 0 create ${n0}/${n1} 0644
+expect 0 link ${n0}/${n1} ${n0}/${n2}
+expect 0 unlink ${n0}/${n2}
+
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM link ${n0}/${n1} ${n0}/${n2}
+expect 0 chflags ${n0} none
+expect 0 link ${n0}/${n1} ${n0}/${n2}
+expect 0 unlink ${n0}/${n2}
+
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM link ${n0}/${n1} ${n0}/${n2}
+expect 0 chflags ${n0} none
+expect 0 link ${n0}/${n1} ${n0}/${n2}
+expect 0 unlink ${n0}/${n2}
+
+expect 0 chflags ${n0} SF_APPEND
+expect 0 link ${n0}/${n1} ${n0}/${n2}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n2}
+
+expect 0 chflags ${n0} UF_APPEND
+expect 0 link ${n0}/${n1} ${n0}/${n2}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n2}
+
+expect 0 chflags ${n0} SF_NOUNLINK
+expect 0 link ${n0}/${n1} ${n0}/${n2}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n2}
+
+expect 0 chflags ${n0} UF_NOUNLINK
+expect 0 link ${n0}/${n1} ${n0}/${n2}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n2}
+
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/link/14.t b/tools/regression/fstest/tests/link/14.t
new file mode 100644
index 0000000..2b0dca3
--- /dev/null
+++ b/tools/regression/fstest/tests/link/14.t
@@ -0,0 +1,34 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns EXDEV if the source and the destination files are on different file systems"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}" in
+FreeBSD)
+ echo "1..8"
+
+ n0=`namegen`
+ n1=`namegen`
+ n2=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 create ${n0}/${n1} 0644
+ expect EXDEV link ${n0}/${n1} ${n2}
+ expect 0 unlink ${n0}/${n1}
+ expect 0 create ${n1} 0644
+ expect EXDEV link ${n1} ${n0}/${n2}
+ expect 0 unlink ${n1}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/link/15.t b/tools/regression/fstest/tests/link/15.t
new file mode 100644
index 0000000..42c6ccf
--- /dev/null
+++ b/tools/regression/fstest/tests/link/15.t
@@ -0,0 +1,38 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns ENOSPC if the directory in which the entry for the new link is being placed cannot be extended because there is no space left on the file system containing the directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..4"
+
+ n0=`namegen`
+ n1=`namegen`
+ n2=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 256k`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 create ${n0}/${n1} 0644
+ i=0
+ while :; do
+ link ${n0}/${n1} ${n0}/${i} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ break
+ fi
+ i=`expr $i + 1`
+ done
+ expect ENOSPC link ${n0}/${n1} ${n0}/${n2}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/link/16.t b/tools/regression/fstest/tests/link/16.t
new file mode 100644
index 0000000..0adb225
--- /dev/null
+++ b/tools/regression/fstest/tests/link/16.t
@@ -0,0 +1,39 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns EROFS if the requested link requires writing in a directory on a read-only file system"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}" in
+FreeBSD)
+ echo "1..9"
+
+ n0=`namegen`
+ n1=`namegen`
+ n2=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 create ${n0}/${n1} 0644
+
+ expect 0 link ${n0}/${n1} ${n0}/${n2}
+ expect 0 unlink ${n0}/${n2}
+ mount -ur /dev/md${n}
+ expect EROFS link ${n0}/${n1} ${n0}/${n2}
+ mount -uw /dev/md${n}
+ expect 0 link ${n0}/${n1} ${n0}/${n2}
+ expect 0 unlink ${n0}/${n2}
+
+ expect 0 unlink ${n0}/${n1}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/link/17.t b/tools/regression/fstest/tests/link/17.t
new file mode 100644
index 0000000..cb56128
--- /dev/null
+++ b/tools/regression/fstest/tests/link/17.t
@@ -0,0 +1,20 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="link returns EFAULT if one of the pathnames specified is outside the process's allocated address space"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..8"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+expect EFAULT link ${n0} NULL
+expect EFAULT link ${n0} DEADCODE
+expect 0 unlink ${n0}
+expect EFAULT link NULL ${n0}
+expect EFAULT link DEADCODE ${n0}
+expect EFAULT link NULL DEADCODE
+expect EFAULT link DEADCODE NULL
diff --git a/tools/regression/fstest/tests/misc.sh b/tools/regression/fstest/tests/misc.sh
new file mode 100644
index 0000000..0ca8065
--- /dev/null
+++ b/tools/regression/fstest/tests/misc.sh
@@ -0,0 +1,96 @@
+# $FreeBSD$
+
+ntest=1
+
+name253="_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_12"
+name255="${name253}34"
+name256="${name255}5"
+path1021="${name255}/${name255}/${name255}/${name253}"
+path1023="${path1021}/x"
+path1024="${path1023}x"
+
+echo ${dir} | egrep '^/' >/dev/null 2>&1
+if [ $? -eq 0 ]; then
+ maindir="${dir}/../.."
+else
+ maindir="`pwd`/${dir}/../.."
+fi
+fstest="${maindir}/fstest"
+. ${maindir}/tests/conf
+
+expect()
+{
+ e="${1}"
+ shift
+ r=`${fstest} $* 2>/dev/null | tail -1`
+ echo "${r}" | egrep '^'${e}'$' >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ echo "ok ${ntest}"
+ else
+ echo "not ok ${ntest}"
+ fi
+ ntest=`expr $ntest + 1`
+}
+
+jexpect()
+{
+ s="${1}"
+ d="${2}"
+ e="${3}"
+ shift 3
+ r=`jail -s ${s} / fstest 127.0.0.1 /bin/sh -c "cd ${d} && ${fstest} $* 2>/dev/null" | tail -1`
+ echo "${r}" | egrep '^'${e}'$' >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ echo "ok ${ntest}"
+ else
+ echo "not ok ${ntest}"
+ fi
+ ntest=`expr $ntest + 1`
+}
+
+test_check()
+{
+ if [ $* ]; then
+ echo "ok ${ntest}"
+ else
+ echo "not ok ${ntest}"
+ fi
+ ntest=`expr $ntest + 1`
+}
+
+namegen()
+{
+ echo "fstest_`dd if=/dev/random bs=1k count=1 2>/dev/null | openssl md5`"
+}
+
+quick_exit()
+{
+ echo "1..1"
+ echo "ok 1"
+ exit 0
+}
+
+supported()
+{
+ case "${1}" in
+ chflags)
+ if [ ${os} != "FreeBSD" -o ${fs} != "UFS" ]; then
+ return 1
+ fi
+ ;;
+ lchmod)
+ if [ ${os} != "FreeBSD" ]; then
+ return 1
+ fi
+ ;;
+ esac
+ return 0
+}
+
+require()
+{
+ if supported ${1}; then
+ return
+ fi
+ quick_exit
+}
diff --git a/tools/regression/fstest/tests/mkdir/00.t b/tools/regression/fstest/tests/mkdir/00.t
new file mode 100644
index 0000000..6ba01c6
--- /dev/null
+++ b/tools/regression/fstest/tests/mkdir/00.t
@@ -0,0 +1,63 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkdir creates directories"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..36"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n1} 0755
+cdir=`pwd`
+cd ${n1}
+
+expect 0 mkdir ${n0} 0755
+expect dir,0755 lstat ${n0} type,mode
+expect 0 rmdir ${n0}
+expect 0 mkdir ${n0} 0151
+expect dir,0151 lstat ${n0} type,mode
+expect 0 rmdir ${n0}
+expect 0 -U 077 mkdir ${n0} 0151
+expect dir,0100 lstat ${n0} type,mode
+expect 0 rmdir ${n0}
+expect 0 -U 070 mkdir ${n0} 0345
+expect dir,0305 lstat ${n0} type,mode
+expect 0 rmdir ${n0}
+expect 0 -U 0501 mkdir ${n0} 0345
+expect dir,0244 lstat ${n0} type,mode
+expect 0 rmdir ${n0}
+
+expect 0 chown . 65535 65535
+expect 0 -u 65535 -g 65535 mkdir ${n0} 0755
+expect 65535,65535 lstat ${n0} uid,gid
+expect 0 rmdir ${n0}
+expect 0 -u 65535 -g 65534 mkdir ${n0} 0755
+expect 65535,65535 lstat ${n0} uid,gid
+expect 0 rmdir ${n0}
+expect 0 chmod . 0777
+expect 0 -u 65534 -g 65533 mkdir ${n0} 0755
+expect 65534,65535 lstat ${n0} uid,gid
+expect 0 rmdir ${n0}
+
+expect 0 chown . 0 0
+time=`${fstest} stat . ctime`
+sleep 1
+expect 0 mkdir ${n0} 0755
+atime=`${fstest} stat ${n0} atime`
+test_check $time -lt $atime
+mtime=`${fstest} stat ${n0} mtime`
+test_check $time -lt $mtime
+ctime=`${fstest} stat ${n0} ctime`
+test_check $time -lt $ctime
+mtime=`${fstest} stat . mtime`
+test_check $time -lt $mtime
+ctime=`${fstest} stat . ctime`
+test_check $time -lt $ctime
+expect 0 rmdir ${n0}
+
+cd ${cdir}
+expect 0 rmdir ${n1}
diff --git a/tools/regression/fstest/tests/mkdir/01.t b/tools/regression/fstest/tests/mkdir/01.t
new file mode 100644
index 0000000..43717e6
--- /dev/null
+++ b/tools/regression/fstest/tests/mkdir/01.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkdir returns ENOTDIR if a component of the path prefix is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..5"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+expect ENOTDIR mkdir ${n0}/${n1}/test 0755
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/mkdir/02.t b/tools/regression/fstest/tests/mkdir/02.t
new file mode 100644
index 0000000..8a4c47a
--- /dev/null
+++ b/tools/regression/fstest/tests/mkdir/02.t
@@ -0,0 +1,13 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkdir returns ENAMETOOLONG if a component of a pathname exceeded 255 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..3"
+
+expect 0 mkdir ${name255} 0755
+expect 0 rmdir ${name255}
+expect ENAMETOOLONG mkdir ${name256} 0755
diff --git a/tools/regression/fstest/tests/mkdir/03.t b/tools/regression/fstest/tests/mkdir/03.t
new file mode 100644
index 0000000..36213af
--- /dev/null
+++ b/tools/regression/fstest/tests/mkdir/03.t
@@ -0,0 +1,21 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkdir returns ENAMETOOLONG if an entire path name exceeded 1023 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..11"
+
+expect 0 mkdir ${name255} 0755
+expect 0 mkdir ${name255}/${name255} 0755
+expect 0 mkdir ${name255}/${name255}/${name255} 0755
+expect 0 mkdir ${path1021} 0755
+expect 0 mkdir ${path1023} 0755
+expect 0 rmdir ${path1023}
+expect ENAMETOOLONG mkdir ${path1024} 0755
+expect 0 rmdir ${path1021}
+expect 0 rmdir ${name255}/${name255}/${name255}
+expect 0 rmdir ${name255}/${name255}
+expect 0 rmdir ${name255}
diff --git a/tools/regression/fstest/tests/mkdir/04.t b/tools/regression/fstest/tests/mkdir/04.t
new file mode 100644
index 0000000..cd65819
--- /dev/null
+++ b/tools/regression/fstest/tests/mkdir/04.t
@@ -0,0 +1,16 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkdir returns ENOENT if a component of the path prefix does not exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..3"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect ENOENT mkdir ${n0}/${n1}/test 0755
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/mkdir/05.t b/tools/regression/fstest/tests/mkdir/05.t
new file mode 100644
index 0000000..7e97d9b
--- /dev/null
+++ b/tools/regression/fstest/tests/mkdir/05.t
@@ -0,0 +1,29 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkdir returns EACCES when search permission is denied for a component of the path prefix"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 mkdir ${n1}/${n2} 0755
+expect 0 -u 65534 -g 65534 rmdir ${n1}/${n2}
+expect 0 chmod ${n1} 0644
+expect EACCES -u 65534 -g 65534 mkdir ${n1}/${n2} 0755
+expect 0 chmod ${n1} 0755
+expect 0 -u 65534 -g 65534 mkdir ${n1}/${n2} 0755
+expect 0 -u 65534 -g 65534 rmdir ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/mkdir/06.t b/tools/regression/fstest/tests/mkdir/06.t
new file mode 100644
index 0000000..79aa539
--- /dev/null
+++ b/tools/regression/fstest/tests/mkdir/06.t
@@ -0,0 +1,29 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkdir returns EACCES when write permission is denied on the parent directory of the directory to be created"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 mkdir ${n1}/${n2} 0755
+expect 0 -u 65534 -g 65534 rmdir ${n1}/${n2}
+expect 0 chmod ${n1} 0555
+expect EACCES -u 65534 -g 65534 mkdir ${n1}/${n2} 0755
+expect 0 chmod ${n1} 0755
+expect 0 -u 65534 -g 65534 mkdir ${n1}/${n2} 0755
+expect 0 -u 65534 -g 65534 rmdir ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/mkdir/07.t b/tools/regression/fstest/tests/mkdir/07.t
new file mode 100644
index 0000000..dbb00df
--- /dev/null
+++ b/tools/regression/fstest/tests/mkdir/07.t
@@ -0,0 +1,19 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkdir returns ELOOP if too many symbolic links were encountered in translating the pathname"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 symlink ${n0} ${n1}
+expect 0 symlink ${n1} ${n0}
+expect ELOOP mkdir ${n0}/test 0755
+expect ELOOP mkdir ${n1}/test 0755
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
diff --git a/tools/regression/fstest/tests/mkdir/08.t b/tools/regression/fstest/tests/mkdir/08.t
new file mode 100644
index 0000000..f87c7bc
--- /dev/null
+++ b/tools/regression/fstest/tests/mkdir/08.t
@@ -0,0 +1,53 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkdir returns EPERM if the parent directory of the directory to be created has its immutable flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..30"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+
+expect 0 mkdir ${n0}/${n1} 0755
+expect 0 rmdir ${n0}/${n1}
+
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM mkdir ${n0}/${n1} 0755
+expect 0 chflags ${n0} none
+expect 0 mkdir ${n0}/${n1} 0755
+expect 0 rmdir ${n0}/${n1}
+
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM mkdir ${n0}/${n1} 0755
+expect 0 chflags ${n0} none
+expect 0 mkdir ${n0}/${n1} 0755
+expect 0 rmdir ${n0}/${n1}
+
+expect 0 chflags ${n0} SF_APPEND
+expect 0 mkdir ${n0}/${n1} 0755
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}/${n1}
+
+expect 0 chflags ${n0} UF_APPEND
+expect 0 mkdir ${n0}/${n1} 0755
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}/${n1}
+
+expect 0 chflags ${n0} SF_NOUNLINK
+expect 0 mkdir ${n0}/${n1} 0755
+expect 0 rmdir ${n0}/${n1}
+expect 0 chflags ${n0} none
+
+expect 0 chflags ${n0} UF_NOUNLINK
+expect 0 mkdir ${n0}/${n1} 0755
+expect 0 rmdir ${n0}/${n1}
+expect 0 chflags ${n0} none
+
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/mkdir/09.t b/tools/regression/fstest/tests/mkdir/09.t
new file mode 100644
index 0000000..c36d030
--- /dev/null
+++ b/tools/regression/fstest/tests/mkdir/09.t
@@ -0,0 +1,34 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkdir returns EROFS if the named file resides on a read-only file system"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..7"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 mkdir ${n0}/${n1} 0755
+ expect 0 rmdir ${n0}/${n1}
+ mount -ur /dev/md${n}
+ expect EROFS mkdir ${n0}/${n1} 0755
+ mount -uw /dev/md${n}
+ expect 0 mkdir ${n0}/${n1} 0755
+ expect 0 rmdir ${n0}/${n1}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/mkdir/10.t b/tools/regression/fstest/tests/mkdir/10.t
new file mode 100644
index 0000000..217bded
--- /dev/null
+++ b/tools/regression/fstest/tests/mkdir/10.t
@@ -0,0 +1,27 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkdir returns EEXIST if the named file exists"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+n0=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect EEXIST mkdir ${n0} 0755
+expect 0 rmdir ${n0}
+
+expect 0 create ${n0} 0644
+expect EEXIST mkdir ${n0} 0755
+expect 0 unlink ${n0}
+
+expect 0 symlink test ${n0}
+expect EEXIST mkdir ${n0} 0755
+expect 0 unlink ${n0}
+
+expect 0 mkfifo ${n0} 0644
+expect EEXIST mkdir ${n0} 0755
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/mkdir/11.t b/tools/regression/fstest/tests/mkdir/11.t
new file mode 100644
index 0000000..8b9758b
--- /dev/null
+++ b/tools/regression/fstest/tests/mkdir/11.t
@@ -0,0 +1,36 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkdir returns ENOSPC if there are no free inodes on the file system on which the directory is being created"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..3"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 256k`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ i=0
+ while :; do
+ mkdir ${n0}/${i} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ break
+ fi
+ i=`expr $i + 1`
+ done
+ expect ENOSPC mkdir ${n0}/${n1} 0755
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/mkdir/12.t b/tools/regression/fstest/tests/mkdir/12.t
new file mode 100644
index 0000000..af322c4
--- /dev/null
+++ b/tools/regression/fstest/tests/mkdir/12.t
@@ -0,0 +1,12 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkdir returns EFAULT if the path argument points outside the process's allocated address space"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..2"
+
+expect EFAULT mkdir NULL 0755
+expect EFAULT mkdir DEADCODE 0755
diff --git a/tools/regression/fstest/tests/mkfifo/00.t b/tools/regression/fstest/tests/mkfifo/00.t
new file mode 100644
index 0000000..15f8409
--- /dev/null
+++ b/tools/regression/fstest/tests/mkfifo/00.t
@@ -0,0 +1,63 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkfifo creates fifo files"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..36"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n1} 0755
+cdir=`pwd`
+cd ${n1}
+
+expect 0 mkfifo ${n0} 0755
+expect fifo,0755 lstat ${n0} type,mode
+expect 0 unlink ${n0}
+expect 0 mkfifo ${n0} 0151
+expect fifo,0151 lstat ${n0} type,mode
+expect 0 unlink ${n0}
+expect 0 -U 077 mkfifo ${n0} 0151
+expect fifo,0100 lstat ${n0} type,mode
+expect 0 unlink ${n0}
+expect 0 -U 070 mkfifo ${n0} 0345
+expect fifo,0305 lstat ${n0} type,mode
+expect 0 unlink ${n0}
+expect 0 -U 0501 mkfifo ${n0} 0345
+expect fifo,0244 lstat ${n0} type,mode
+expect 0 unlink ${n0}
+
+expect 0 chown . 65535 65535
+expect 0 -u 65535 -g 65535 mkfifo ${n0} 0755
+expect 65535,65535 lstat ${n0} uid,gid
+expect 0 unlink ${n0}
+expect 0 -u 65535 -g 65534 mkfifo ${n0} 0755
+expect 65535,65535 lstat ${n0} uid,gid
+expect 0 unlink ${n0}
+expect 0 chmod . 0777
+expect 0 -u 65534 -g 65533 mkfifo ${n0} 0755
+expect 65534,65535 lstat ${n0} uid,gid
+expect 0 unlink ${n0}
+
+expect 0 chown . 0 0
+time=`${fstest} stat . ctime`
+sleep 1
+expect 0 mkfifo ${n0} 0755
+atime=`${fstest} stat ${n0} atime`
+test_check $time -lt $atime
+mtime=`${fstest} stat ${n0} mtime`
+test_check $time -lt $mtime
+ctime=`${fstest} stat ${n0} ctime`
+test_check $time -lt $ctime
+mtime=`${fstest} stat . mtime`
+test_check $time -lt $mtime
+ctime=`${fstest} stat . ctime`
+test_check $time -lt $ctime
+expect 0 unlink ${n0}
+
+cd ${cdir}
+expect 0 rmdir ${n1}
diff --git a/tools/regression/fstest/tests/mkfifo/01.t b/tools/regression/fstest/tests/mkfifo/01.t
new file mode 100644
index 0000000..69bfff5
--- /dev/null
+++ b/tools/regression/fstest/tests/mkfifo/01.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkfifo returns ENOTDIR if a component of the path prefix is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..5"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+expect ENOTDIR mkfifo ${n0}/${n1}/test 0644
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/mkfifo/02.t b/tools/regression/fstest/tests/mkfifo/02.t
new file mode 100644
index 0000000..1f3a64e
--- /dev/null
+++ b/tools/regression/fstest/tests/mkfifo/02.t
@@ -0,0 +1,13 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkfifo returns ENAMETOOLONG if a component of a pathname exceeded 255 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..3"
+
+expect 0 mkfifo ${name255} 0644
+expect 0 unlink ${name255}
+expect ENAMETOOLONG mkfifo ${name256} 0644
diff --git a/tools/regression/fstest/tests/mkfifo/03.t b/tools/regression/fstest/tests/mkfifo/03.t
new file mode 100644
index 0000000..aa48201
--- /dev/null
+++ b/tools/regression/fstest/tests/mkfifo/03.t
@@ -0,0 +1,21 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkfifo returns ENAMETOOLONG if an entire path name exceeded 1023 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..11"
+
+expect 0 mkdir ${name255} 0755
+expect 0 mkdir ${name255}/${name255} 0755
+expect 0 mkdir ${name255}/${name255}/${name255} 0755
+expect 0 mkdir ${path1021} 0755
+expect 0 mkfifo ${path1023} 0644
+expect 0 unlink ${path1023}
+expect ENAMETOOLONG mkfifo ${path1024} 0644
+expect 0 rmdir ${path1021}
+expect 0 rmdir ${name255}/${name255}/${name255}
+expect 0 rmdir ${name255}/${name255}
+expect 0 rmdir ${name255}
diff --git a/tools/regression/fstest/tests/mkfifo/04.t b/tools/regression/fstest/tests/mkfifo/04.t
new file mode 100644
index 0000000..d9ad951
--- /dev/null
+++ b/tools/regression/fstest/tests/mkfifo/04.t
@@ -0,0 +1,16 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkfifo returns ENOENT if a component of the path prefix does not exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..3"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect ENOENT mkfifo ${n0}/${n1}/test 0644
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/mkfifo/05.t b/tools/regression/fstest/tests/mkfifo/05.t
new file mode 100644
index 0000000..d93d568
--- /dev/null
+++ b/tools/regression/fstest/tests/mkfifo/05.t
@@ -0,0 +1,29 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkfifo returns EACCES when search permission is denied for a component of the path prefix"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 mkfifo ${n1}/${n2} 0644
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+expect 0 chmod ${n1} 0644
+expect EACCES -u 65534 -g 65534 mkfifo ${n1}/${n2} 0644
+expect 0 chmod ${n1} 0755
+expect 0 -u 65534 -g 65534 mkfifo ${n1}/${n2} 0644
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/mkfifo/06.t b/tools/regression/fstest/tests/mkfifo/06.t
new file mode 100644
index 0000000..47f199b
--- /dev/null
+++ b/tools/regression/fstest/tests/mkfifo/06.t
@@ -0,0 +1,29 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkfifo returns EACCES when write permission is denied on the parent directory of the file to be created"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 mkfifo ${n1}/${n2} 0644
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+expect 0 chmod ${n1} 0555
+expect EACCES -u 65534 -g 65534 mkfifo ${n1}/${n2} 0644
+expect 0 chmod ${n1} 0755
+expect 0 -u 65534 -g 65534 mkfifo ${n1}/${n2} 0644
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/mkfifo/07.t b/tools/regression/fstest/tests/mkfifo/07.t
new file mode 100644
index 0000000..44271b6
--- /dev/null
+++ b/tools/regression/fstest/tests/mkfifo/07.t
@@ -0,0 +1,19 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkfifo returns ELOOP if too many symbolic links were encountered in translating the pathname"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 symlink ${n0} ${n1}
+expect 0 symlink ${n1} ${n0}
+expect ELOOP mkfifo ${n0}/test 0644
+expect ELOOP mkfifo ${n1}/test 0644
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
diff --git a/tools/regression/fstest/tests/mkfifo/08.t b/tools/regression/fstest/tests/mkfifo/08.t
new file mode 100644
index 0000000..a4b0002
--- /dev/null
+++ b/tools/regression/fstest/tests/mkfifo/08.t
@@ -0,0 +1,34 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkfifo returns EROFS if the named file resides on a read-only file system"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..7"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 mkfifo ${n0}/${n1} 0644
+ expect 0 unlink ${n0}/${n1}
+ mount -ur /dev/md${n}
+ expect EROFS mkfifo ${n0}/${n1} 0644
+ mount -uw /dev/md${n}
+ expect 0 mkfifo ${n0}/${n1} 0644
+ expect 0 unlink ${n0}/${n1}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/mkfifo/09.t b/tools/regression/fstest/tests/mkfifo/09.t
new file mode 100644
index 0000000..102e12b
--- /dev/null
+++ b/tools/regression/fstest/tests/mkfifo/09.t
@@ -0,0 +1,27 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkfifo returns EEXIST if the named file exists"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+n0=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect EEXIST mkfifo ${n0} 0644
+expect 0 rmdir ${n0}
+
+expect 0 create ${n0} 0644
+expect EEXIST mkfifo ${n0} 0644
+expect 0 unlink ${n0}
+
+expect 0 symlink test ${n0}
+expect EEXIST mkfifo ${n0} 0644
+expect 0 unlink ${n0}
+
+expect 0 mkfifo ${n0} 0644
+expect EEXIST mkfifo ${n0} 0644
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/mkfifo/10.t b/tools/regression/fstest/tests/mkfifo/10.t
new file mode 100644
index 0000000..beeacab
--- /dev/null
+++ b/tools/regression/fstest/tests/mkfifo/10.t
@@ -0,0 +1,53 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkfifo returns EPERM if the parent directory of the file to be created has its immutable flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..30"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+
+expect 0 mkfifo ${n0}/${n1} 0644
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM mkfifo ${n0}/${n1} 0644
+expect 0 chflags ${n0} none
+expect 0 mkfifo ${n0}/${n1} 0644
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM mkfifo ${n0}/${n1} 0644
+expect 0 chflags ${n0} none
+expect 0 mkfifo ${n0}/${n1} 0644
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} SF_APPEND
+expect 0 mkfifo ${n0}/${n1} 0644
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} UF_APPEND
+expect 0 mkfifo ${n0}/${n1} 0644
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} SF_NOUNLINK
+expect 0 mkfifo ${n0}/${n1} 0644
+expect 0 unlink ${n0}/${n1}
+expect 0 chflags ${n0} none
+
+expect 0 chflags ${n0} UF_NOUNLINK
+expect 0 mkfifo ${n0}/${n1} 0644
+expect 0 unlink ${n0}/${n1}
+expect 0 chflags ${n0} none
+
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/mkfifo/11.t b/tools/regression/fstest/tests/mkfifo/11.t
new file mode 100644
index 0000000..f9937fa
--- /dev/null
+++ b/tools/regression/fstest/tests/mkfifo/11.t
@@ -0,0 +1,36 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkfifo returns ENOSPC if there are no free inodes on the file system on which the file is being created"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..3"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 256k`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ i=0
+ while :; do
+ mkfifo ${n0}/${i} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ break
+ fi
+ i=`expr $i + 1`
+ done
+ expect ENOSPC mkfifo ${n0}/${n1} 0644
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/mkfifo/12.t b/tools/regression/fstest/tests/mkfifo/12.t
new file mode 100644
index 0000000..40c1455
--- /dev/null
+++ b/tools/regression/fstest/tests/mkfifo/12.t
@@ -0,0 +1,12 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="mkfifo returns EFAULT if the path argument points outside the process's allocated address space"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..2"
+
+expect EFAULT mkfifo NULL 0644
+expect EFAULT mkfifo DEADCODE 0644
diff --git a/tools/regression/fstest/tests/open/00.t b/tools/regression/fstest/tests/open/00.t
new file mode 100644
index 0000000..48bc27a
--- /dev/null
+++ b/tools/regression/fstest/tests/open/00.t
@@ -0,0 +1,87 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open opens (and eventually creates) a file"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..45"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n1} 0755
+cdir=`pwd`
+cd ${n1}
+
+expect 0 open ${n0} O_CREAT,O_WRONLY 0755
+expect regular,0755 lstat ${n0} type,mode
+expect 0 unlink ${n0}
+expect 0 open ${n0} O_CREAT,O_WRONLY 0151
+expect regular,0151 lstat ${n0} type,mode
+expect 0 unlink ${n0}
+expect 0 -U 077 open ${n0} O_CREAT,O_WRONLY 0151
+expect regular,0100 lstat ${n0} type,mode
+expect 0 unlink ${n0}
+expect 0 -U 070 open ${n0} O_CREAT,O_WRONLY 0345
+expect regular,0305 lstat ${n0} type,mode
+expect 0 unlink ${n0}
+expect 0 -U 0501 open ${n0} O_CREAT,O_WRONLY 0345
+expect regular,0244 lstat ${n0} type,mode
+expect 0 unlink ${n0}
+
+expect 0 chown . 65535 65535
+expect 0 -u 65535 -g 65535 open ${n0} O_CREAT,O_WRONLY 0644
+expect 65535,65535 lstat ${n0} uid,gid
+expect 0 unlink ${n0}
+expect 0 -u 65535 -g 65534 open ${n0} O_CREAT,O_WRONLY 0644
+expect 65535,65535 lstat ${n0} uid,gid
+expect 0 unlink ${n0}
+expect 0 chmod . 0777
+expect 0 -u 65534 -g 65533 open ${n0} O_CREAT,O_WRONLY 0644
+expect 65534,65535 lstat ${n0} uid,gid
+expect 0 unlink ${n0}
+
+# Update parent directory ctime/mtime if file didn't exist.
+expect 0 chown . 0 0
+time=`${fstest} stat . ctime`
+sleep 1
+expect 0 open ${n0} O_CREAT,O_WRONLY 0644
+atime=`${fstest} stat ${n0} atime`
+test_check $time -lt $atime
+mtime=`${fstest} stat ${n0} mtime`
+test_check $time -lt $mtime
+ctime=`${fstest} stat ${n0} ctime`
+test_check $time -lt $ctime
+mtime=`${fstest} stat . mtime`
+test_check $time -lt $mtime
+ctime=`${fstest} stat . ctime`
+test_check $time -lt $ctime
+expect 0 unlink ${n0}
+
+# Don't update parent directory ctime/mtime if file existed.
+expect 0 create ${n0} 0644
+dmtime=`${fstest} stat . mtime`
+dctime=`${fstest} stat . ctime`
+sleep 1
+expect 0 open ${n0} O_CREAT,O_RDONLY 0644
+mtime=`${fstest} stat . mtime`
+test_check $dmtime -eq $mtime
+ctime=`${fstest} stat . ctime`
+test_check $dctime -eq $ctime
+expect 0 unlink ${n0}
+
+echo test > ${n0}
+mtime1=`${fstest} stat ${n0} mtime`
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 open ${n0} O_WRONLY,O_TRUNC
+mtime2=`${fstest} stat ${n0} mtime`
+test_check $mtime1 -lt $mtime2
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n0}
+
+cd ${cdir}
+expect 0 rmdir ${n1}
diff --git a/tools/regression/fstest/tests/open/01.t b/tools/regression/fstest/tests/open/01.t
new file mode 100644
index 0000000..39446ba
--- /dev/null
+++ b/tools/regression/fstest/tests/open/01.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns ENOTDIR if a component of the path prefix is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..5"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+expect ENOTDIR open ${n0}/${n1}/test O_CREAT 0644
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/open/02.t b/tools/regression/fstest/tests/open/02.t
new file mode 100644
index 0000000..ebd47e3
--- /dev/null
+++ b/tools/regression/fstest/tests/open/02.t
@@ -0,0 +1,14 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns ENAMETOOLONG if a component of a pathname exceeded 255 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..4"
+
+expect 0 open ${name255} O_CREAT 0620
+expect 0620 stat ${name255} mode
+expect 0 unlink ${name255}
+expect ENAMETOOLONG open ${name256} O_CREAT 0620
diff --git a/tools/regression/fstest/tests/open/03.t b/tools/regression/fstest/tests/open/03.t
new file mode 100644
index 0000000..ad78e5b
--- /dev/null
+++ b/tools/regression/fstest/tests/open/03.t
@@ -0,0 +1,22 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns ENAMETOOLONG if an entire path name exceeded 1023 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+expect 0 mkdir ${name255} 0755
+expect 0 mkdir ${name255}/${name255} 0755
+expect 0 mkdir ${name255}/${name255}/${name255} 0755
+expect 0 mkdir ${path1021} 0755
+expect 0 open ${path1023} O_CREAT 0642
+expect 0642 stat ${path1023} mode
+expect 0 unlink ${path1023}
+expect ENAMETOOLONG open ${path1024} O_CREAT 0642
+expect 0 rmdir ${path1021}
+expect 0 rmdir ${name255}/${name255}/${name255}
+expect 0 rmdir ${name255}/${name255}
+expect 0 rmdir ${name255}
diff --git a/tools/regression/fstest/tests/open/04.t b/tools/regression/fstest/tests/open/04.t
new file mode 100644
index 0000000..1ce99cb
--- /dev/null
+++ b/tools/regression/fstest/tests/open/04.t
@@ -0,0 +1,17 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns ENOENT if a component of the path name that must exist does not exist or O_CREAT is not set and the named file does not exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..4"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect ENOENT open ${n0}/${n1}/test O_CREAT 0644
+expect ENOENT open ${n0}/${n1} O_RDONLY
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/open/05.t b/tools/regression/fstest/tests/open/05.t
new file mode 100644
index 0000000..25ad7da
--- /dev/null
+++ b/tools/regression/fstest/tests/open/05.t
@@ -0,0 +1,29 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EACCES when search permission is denied for a component of the path prefix"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n1}/${n2} 0644
+expect 0 -u 65534 -g 65534 open ${n1}/${n2} O_RDONLY
+expect 0 chmod ${n1} 0644
+expect EACCES -u 65534 -g 65534 open ${n1}/${n2} O_RDONLY
+expect 0 chmod ${n1} 0755
+expect 0 -u 65534 -g 65534 open ${n1}/${n2} O_RDONLY
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/open/06.t b/tools/regression/fstest/tests/open/06.t
new file mode 100644
index 0000000..e72d191
--- /dev/null
+++ b/tools/regression/fstest/tests/open/06.t
@@ -0,0 +1,89 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EACCES when the required permissions (for reading and/or writing) are denied for the given flags"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..65"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 chown ${n0} 65534 65534
+cdir=`pwd`
+cd ${n0}
+
+expect 0 -u 65534 -g 65534 create ${n1} 0644
+
+expect 0 -u 65534 -g 65534 chmod ${n1} 0600
+expect 0 -u 65534 -g 65534 open ${n1} O_RDONLY
+expect 0 -u 65534 -g 65534 open ${n1} O_WRONLY
+expect 0 -u 65534 -g 65534 open ${n1} O_RDWR
+expect 0 -u 65534 -g 65534 chmod ${n1} 0060
+expect 0 -u 65533 -g 65534 open ${n1} O_RDONLY
+expect 0 -u 65533 -g 65534 open ${n1} O_WRONLY
+expect 0 -u 65533 -g 65534 open ${n1} O_RDWR
+expect 0 -u 65534 -g 65534 chmod ${n1} 0006
+expect 0 -u 65533 -g 65533 open ${n1} O_RDONLY
+expect 0 -u 65533 -g 65533 open ${n1} O_WRONLY
+expect 0 -u 65533 -g 65533 open ${n1} O_RDWR
+
+expect 0 -u 65534 -g 65534 chmod ${n1} 0477
+expect 0 -u 65534 -g 65534 open ${n1} O_RDONLY
+expect EACCES -u 65534 -g 65534 open ${n1} O_WRONLY
+expect EACCES -u 65534 -g 65534 open ${n1} O_RDWR
+expect 0 -u 65534 -g 65534 chmod ${n1} 0747
+expect 0 -u 65533 -g 65534 open ${n1} O_RDONLY
+expect EACCES -u 65533 -g 65534 open ${n1} O_WRONLY
+expect EACCES -u 65533 -g 65534 open ${n1} O_RDWR
+expect 0 -u 65534 -g 65534 chmod ${n1} 0774
+expect 0 -u 65533 -g 65533 open ${n1} O_RDONLY
+expect EACCES -u 65533 -g 65533 open ${n1} O_WRONLY
+expect EACCES -u 65533 -g 65533 open ${n1} O_RDWR
+
+expect 0 -u 65534 -g 65534 chmod ${n1} 0277
+expect EACCES -u 65534 -g 65534 open ${n1} O_RDONLY
+expect 0 -u 65534 -g 65534 open ${n1} O_WRONLY
+expect EACCES -u 65534 -g 65534 open ${n1} O_RDWR
+expect 0 -u 65534 -g 65534 chmod ${n1} 0727
+expect EACCES -u 65533 -g 65534 open ${n1} O_RDONLY
+expect 0 -u 65533 -g 65534 open ${n1} O_WRONLY
+expect EACCES -u 65533 -g 65534 open ${n1} O_RDWR
+expect 0 -u 65534 -g 65534 chmod ${n1} 0772
+expect EACCES -u 65533 -g 65533 open ${n1} O_RDONLY
+expect 0 -u 65533 -g 65533 open ${n1} O_WRONLY
+expect EACCES -u 65533 -g 65533 open ${n1} O_RDWR
+
+expect 0 -u 65534 -g 65534 chmod ${n1} 0177
+expect EACCES -u 65534 -g 65534 open ${n1} O_RDONLY
+expect EACCES -u 65534 -g 65534 open ${n1} O_WRONLY
+expect EACCES -u 65534 -g 65534 open ${n1} O_RDWR
+expect 0 -u 65534 -g 65534 chmod ${n1} 0717
+expect EACCES -u 65533 -g 65534 open ${n1} O_RDONLY
+expect EACCES -u 65533 -g 65534 open ${n1} O_WRONLY
+expect EACCES -u 65533 -g 65534 open ${n1} O_RDWR
+expect 0 -u 65534 -g 65534 chmod ${n1} 0771
+expect EACCES -u 65533 -g 65533 open ${n1} O_RDONLY
+expect EACCES -u 65533 -g 65533 open ${n1} O_WRONLY
+expect EACCES -u 65533 -g 65533 open ${n1} O_RDWR
+
+expect 0 -u 65534 -g 65534 chmod ${n1} 0077
+expect EACCES -u 65534 -g 65534 open ${n1} O_RDONLY
+expect EACCES -u 65534 -g 65534 open ${n1} O_WRONLY
+expect EACCES -u 65534 -g 65534 open ${n1} O_RDWR
+expect 0 -u 65534 -g 65534 chmod ${n1} 0707
+expect EACCES -u 65533 -g 65534 open ${n1} O_RDONLY
+expect EACCES -u 65533 -g 65534 open ${n1} O_WRONLY
+expect EACCES -u 65533 -g 65534 open ${n1} O_RDWR
+expect 0 -u 65534 -g 65534 chmod ${n1} 0770
+expect EACCES -u 65533 -g 65533 open ${n1} O_RDONLY
+expect EACCES -u 65533 -g 65533 open ${n1} O_WRONLY
+expect EACCES -u 65533 -g 65533 open ${n1} O_RDWR
+
+expect 0 -u 65534 -g 65534 unlink ${n1}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/open/07.t b/tools/regression/fstest/tests/open/07.t
new file mode 100644
index 0000000..a41d193
--- /dev/null
+++ b/tools/regression/fstest/tests/open/07.t
@@ -0,0 +1,45 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EACCES when O_TRUNC is specified and write permission is denied"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..23"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 chown ${n0} 65534 65534
+cdir=`pwd`
+cd ${n0}
+
+expect 0 -u 65534 -g 65534 create ${n1} 0644
+
+expect 0 -u 65534 -g 65534 chmod ${n1} 0477
+expect EACCES -u 65534 -g 65534 open ${n1} O_RDONLY,O_TRUNC
+expect 0 -u 65534 -g 65534 chmod ${n1} 0747
+expect EACCES -u 65533 -g 65534 open ${n1} O_RDONLY,O_TRUNC
+expect 0 -u 65534 -g 65534 chmod ${n1} 0774
+expect EACCES -u 65533 -g 65533 open ${n1} O_RDONLY,O_TRUNC
+
+expect 0 -u 65534 -g 65534 chmod ${n1} 0177
+expect EACCES -u 65534 -g 65534 open ${n1} O_RDONLY,O_TRUNC
+expect 0 -u 65534 -g 65534 chmod ${n1} 0717
+expect EACCES -u 65533 -g 65534 open ${n1} O_RDONLY,O_TRUNC
+expect 0 -u 65534 -g 65534 chmod ${n1} 0771
+expect EACCES -u 65533 -g 65533 open ${n1} O_RDONLY,O_TRUNC
+
+expect 0 -u 65534 -g 65534 chmod ${n1} 0077
+expect EACCES -u 65534 -g 65534 open ${n1} O_RDONLY,O_TRUNC
+expect 0 -u 65534 -g 65534 chmod ${n1} 0707
+expect EACCES -u 65533 -g 65534 open ${n1} O_RDONLY,O_TRUNC
+expect 0 -u 65534 -g 65534 chmod ${n1} 0770
+expect EACCES -u 65533 -g 65533 open ${n1} O_RDONLY,O_TRUNC
+
+expect 0 -u 65534 -g 65534 unlink ${n1}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/open/08.t b/tools/regression/fstest/tests/open/08.t
new file mode 100644
index 0000000..22ea29b
--- /dev/null
+++ b/tools/regression/fstest/tests/open/08.t
@@ -0,0 +1,19 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EACCES when O_CREAT is specified, the file does not exist, and the directory in which it is to be created does not permit writing"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..3"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect EACCES -u 65534 -g 65534 open ${n1} O_RDONLY,O_CREAT 0644
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/open/09.t b/tools/regression/fstest/tests/open/09.t
new file mode 100644
index 0000000..4614a40
--- /dev/null
+++ b/tools/regression/fstest/tests/open/09.t
@@ -0,0 +1,53 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="O_CREAT is specified, the file does not exist, and the directory in which it is to be created has its immutable flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..30"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+
+expect 0 open ${n0}/${n1} O_RDONLY,O_CREAT 0644
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM open ${n0}/${n1} O_RDONLY,O_CREAT 0644
+expect 0 chflags ${n0} none
+expect 0 open ${n0}/${n1} O_RDONLY,O_CREAT 0644
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM open ${n0}/${n1} O_RDONLY,O_CREAT 0644
+expect 0 chflags ${n0} none
+expect 0 open ${n0}/${n1} O_RDONLY,O_CREAT 0644
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} SF_APPEND
+expect 0 open ${n0}/${n1} O_RDONLY,O_CREAT 0644
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} UF_APPEND
+expect 0 open ${n0}/${n1} O_RDONLY,O_CREAT 0644
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} SF_NOUNLINK
+expect 0 open ${n0}/${n1} O_RDONLY,O_CREAT 0644
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} UF_NOUNLINK
+expect 0 symlink test ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/open/10.t b/tools/regression/fstest/tests/open/10.t
new file mode 100644
index 0000000..d56ceb1
--- /dev/null
+++ b/tools/regression/fstest/tests/open/10.t
@@ -0,0 +1,45 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EPERM when the named file has its immutable flag set and the file is to be modified"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..28"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM open ${n0} O_WRONLY
+expect EPERM open ${n0} O_RDWR
+expect EPERM open ${n0} O_RDONLY,O_TRUNC
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM open ${n0} O_WRONLY
+expect EPERM open ${n0} O_RDWR
+expect EPERM open ${n0} O_RDONLY,O_TRUNC
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_NOUNLINK
+expect 0 open ${n0} O_WRONLY
+expect 0 open ${n0} O_RDWR
+expect 0 open ${n0} O_RDONLY,O_TRUNC
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_NOUNLINK
+expect 0 open ${n0} O_WRONLY
+expect 0 open ${n0} O_RDWR
+expect 0 open ${n0} O_RDONLY,O_TRUNC
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/open/11.t b/tools/regression/fstest/tests/open/11.t
new file mode 100644
index 0000000..feb0ffe
--- /dev/null
+++ b/tools/regression/fstest/tests/open/11.t
@@ -0,0 +1,39 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EPERM when the named file has its append-only flag set, the file is to be modified, and O_TRUNC is specified or O_APPEND is not specified"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..24"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_APPEND
+expect 0 open ${n0} O_WRONLY,O_APPEND
+expect 0 open ${n0} O_RDWR,O_APPEND
+expect EPERM open ${n0} O_WRONLY
+expect EPERM open ${n0} O_RDWR
+expect EPERM open ${n0} O_RDONLY,O_TRUNC
+expect EPERM open ${n0} O_RDONLY,O_APPEND,O_TRUNC
+expect EPERM open ${n0} O_WRONLY,O_APPEND,O_TRUNC
+expect EPERM open ${n0} O_RDWR,O_APPEND,O_TRUNC
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_APPEND
+expect 0 open ${n0} O_WRONLY,O_APPEND
+expect 0 open ${n0} O_RDWR,O_APPEND
+expect EPERM open ${n0} O_WRONLY
+expect EPERM open ${n0} O_RDWR
+expect EPERM open ${n0} O_RDONLY,O_TRUNC
+expect EPERM open ${n0} O_RDONLY,O_APPEND,O_TRUNC
+expect EPERM open ${n0} O_WRONLY,O_APPEND,O_TRUNC
+expect EPERM open ${n0} O_RDWR,O_APPEND,O_TRUNC
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/open/12.t b/tools/regression/fstest/tests/open/12.t
new file mode 100644
index 0000000..2726dc1
--- /dev/null
+++ b/tools/regression/fstest/tests/open/12.t
@@ -0,0 +1,19 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns ELOOP if too many symbolic links were encountered in translating the pathname"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 symlink ${n0} ${n1}
+expect 0 symlink ${n1} ${n0}
+expect ELOOP open ${n0}/test O_RDONLY
+expect ELOOP open ${n1}/test O_RDONLY
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
diff --git a/tools/regression/fstest/tests/open/13.t b/tools/regression/fstest/tests/open/13.t
new file mode 100644
index 0000000..4d05a61
--- /dev/null
+++ b/tools/regression/fstest/tests/open/13.t
@@ -0,0 +1,24 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EISDIR when he named file is a directory, and the arguments specify it is to be modified"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..8"
+
+n0=`namegen`
+
+expect 0 mkdir ${n0} 0755
+
+expect 0 open ${n0} O_RDONLY
+expect EISDIR open ${n0} O_WRONLY
+expect EISDIR open ${n0} O_RDWR
+expect EISDIR open ${n0} O_RDONLY,O_TRUNC
+expect EISDIR open ${n0} O_WRONLY,O_TRUNC
+expect EISDIR open ${n0} O_RDWR,O_TRUNC
+
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/open/14.t b/tools/regression/fstest/tests/open/14.t
new file mode 100644
index 0000000..771f451
--- /dev/null
+++ b/tools/regression/fstest/tests/open/14.t
@@ -0,0 +1,37 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EROFS if the named file resides on a read-only file system, and the file is to be modified"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..10"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 create ${n0}/${n1} 0644
+ expect 0 open ${n0}/${n1} O_WRONLY
+ expect 0 open ${n0}/${n1} O_RDWR
+ expect 0 open ${n0}/${n1} O_RDONLY,O_TRUNC
+ mount -ur /dev/md${n}
+ expect EROFS open ${n0}/${n1} O_WRONLY
+ expect EROFS open ${n0}/${n1} O_RDWR
+ expect EROFS open ${n0}/${n1} O_RDONLY,O_TRUNC
+ mount -uw /dev/md${n}
+ expect 0 unlink ${n0}/${n1}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/open/15.t b/tools/regression/fstest/tests/open/15.t
new file mode 100644
index 0000000..76b57d3
--- /dev/null
+++ b/tools/regression/fstest/tests/open/15.t
@@ -0,0 +1,32 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EROFS when O_CREAT is specified and the named file would reside on a read-only file system"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..5"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 open ${n0}/${n1} O_RDONLY,O_CREAT 0644
+ expect 0 unlink ${n0}/${n1}
+ mount -ur /dev/md${n}
+ expect EROFS open ${n0}/${n1} O_RDONLY,O_CREAT 0644
+ mount -uw /dev/md${n}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/open/16.t b/tools/regression/fstest/tests/open/16.t
new file mode 100644
index 0000000..7b4194e
--- /dev/null
+++ b/tools/regression/fstest/tests/open/16.t
@@ -0,0 +1,19 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EMLINK when O_NOFOLLOW was specified and the target is a symbolic link"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 symlink ${n0} ${n1}
+expect EMLINK open ${n1} O_RDONLY,O_CREAT,O_NOFOLLOW 0644
+expect EMLINK open ${n1} O_RDONLY,O_NOFOLLOW
+expect EMLINK open ${n1} O_WRONLY,O_NOFOLLOW
+expect EMLINK open ${n1} O_RDWR,O_NOFOLLOW
+expect 0 unlink ${n1}
diff --git a/tools/regression/fstest/tests/open/17.t b/tools/regression/fstest/tests/open/17.t
new file mode 100644
index 0000000..2224daf
--- /dev/null
+++ b/tools/regression/fstest/tests/open/17.t
@@ -0,0 +1,15 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns ENXIO when O_NONBLOCK is set, the named file is a fifo, O_WRONLY is set, and no process has the file open for reading"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..3"
+
+n0=`namegen`
+
+expect 0 mkfifo ${n0} 0644
+expect ENXIO open ${n0} O_WRONLY,O_NONBLOCK
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/open/18.t b/tools/regression/fstest/tests/open/18.t
new file mode 100644
index 0000000..e14fc4b
--- /dev/null
+++ b/tools/regression/fstest/tests/open/18.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EWOULDBLOCK when O_NONBLOCK and one of O_SHLOCK or O_EXLOCK is specified and the file is locked"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+expect 0 open ${n0} O_RDONLY,O_SHLOCK : open ${n0} O_RDONLY,O_SHLOCK,O_NONBLOCK
+expect "EWOULDBLOCK|EAGAIN" open ${n0} O_RDONLY,O_EXLOCK : open ${n0} O_RDONLY,O_EXLOCK,O_NONBLOCK
+expect "EWOULDBLOCK|EAGAIN" open ${n0} O_RDONLY,O_SHLOCK : open ${n0} O_RDONLY,O_EXLOCK,O_NONBLOCK
+expect "EWOULDBLOCK|EAGAIN" open ${n0} O_RDONLY,O_EXLOCK : open ${n0} O_RDONLY,O_SHLOCK,O_NONBLOCK
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/open/19.t b/tools/regression/fstest/tests/open/19.t
new file mode 100644
index 0000000..aa2d909
--- /dev/null
+++ b/tools/regression/fstest/tests/open/19.t
@@ -0,0 +1,37 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns ENOSPC when O_CREAT is specified, the file does not exist, and there are no free inodes on the file system on which the file is being created"
+
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..3"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 256k`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ i=0
+ while :; do
+ touch ${n0}/${i} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ break
+ fi
+ i=`expr $i + 1`
+ done
+ expect ENOSPC open ${n0}/${i} O_RDONLY,O_CREAT 0644
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/open/20.t b/tools/regression/fstest/tests/open/20.t
new file mode 100644
index 0000000..fc926f4
--- /dev/null
+++ b/tools/regression/fstest/tests/open/20.t
@@ -0,0 +1,25 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns ETXTBSY when the file is a pure procedure (shared text) file that is being executed and the open() system call requests write access"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}" in
+FreeBSD)
+ echo "1..4"
+
+ n0=`namegen`
+
+ cp -pf `which sleep` ${n0}
+ ./${n0} 3 &
+ expect ETXTBSY open ${n0} O_WRONLY
+ expect ETXTBSY open ${n0} O_RDWR
+ expect ETXTBSY open ${n0} O_RDONLY,O_TRUNC
+ expect 0 unlink ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/open/21.t b/tools/regression/fstest/tests/open/21.t
new file mode 100644
index 0000000..c43d7fd
--- /dev/null
+++ b/tools/regression/fstest/tests/open/21.t
@@ -0,0 +1,12 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EFAULT if the path argument points outside the process's allocated address space"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..2"
+
+expect EFAULT open NULL O_RDONLY
+expect EFAULT open DEADCODE O_RDONLY
diff --git a/tools/regression/fstest/tests/open/22.t b/tools/regression/fstest/tests/open/22.t
new file mode 100644
index 0000000..5e3d228
--- /dev/null
+++ b/tools/regression/fstest/tests/open/22.t
@@ -0,0 +1,27 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EEXIST when O_CREAT and O_EXCL were specified and the file exists"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+expect EEXIST open ${n0} O_CREAT,O_EXCL 0644
+expect 0 unlink ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect EEXIST open ${n0} O_CREAT,O_EXCL 0644
+expect 0 rmdir ${n0}
+
+expect 0 mkfifo ${n0} 0644
+expect EEXIST open ${n0} O_CREAT,O_EXCL 0644
+expect 0 unlink ${n0}
+
+expect 0 symlink test ${n0}
+expect EEXIST open ${n0} O_CREAT,O_EXCL 0644
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/open/23.t b/tools/regression/fstest/tests/open/23.t
new file mode 100644
index 0000000..ea6335f
--- /dev/null
+++ b/tools/regression/fstest/tests/open/23.t
@@ -0,0 +1,16 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="open returns EINVAL when an attempt was made to open a descriptor with an illegal combination of O_RDONLY, O_WRONLY, and O_RDWR"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..4"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+expect EINVAL open ${n0} O_WRONLY,O_RDWR
+expect EINVAL open ${n0} O_RDONLY,O_WRONLY,O_RDWR
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/rename/00.t b/tools/regression/fstest/tests/rename/00.t
new file mode 100644
index 0000000..db1feab
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/00.t
@@ -0,0 +1,141 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename changes file name"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..79"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+n3=`namegen`
+
+expect 0 mkdir ${n3} 0755
+cdir=`pwd`
+cd ${n3}
+
+expect 0 create ${n0} 0644
+expect regular,0644,1 lstat ${n0} type,mode,nlink
+inode=`${fstest} lstat ${n0} inode`
+expect 0 rename ${n0} ${n1}
+expect ENOENT lstat ${n0} type,mode,nlink
+expect regular,${inode},0644,1 lstat ${n1} type,inode,mode,nlink
+expect 0 link ${n1} ${n0}
+expect regular,${inode},0644,2 lstat ${n0} type,inode,mode,nlink
+expect regular,${inode},0644,2 lstat ${n1} type,inode,mode,nlink
+expect 0 rename ${n1} ${n2}
+expect regular,${inode},0644,2 lstat ${n0} type,inode,mode,nlink
+expect ENOENT lstat ${n1} type,mode,nlink
+expect regular,${inode},0644,2 lstat ${n2} type,inode,mode,nlink
+expect 0 unlink ${n0}
+expect 0 unlink ${n2}
+
+expect 0 mkdir ${n0} 0755
+expect dir,0755 lstat ${n0} type,mode
+inode=`${fstest} lstat ${n0} inode`
+expect 0 rename ${n0} ${n1}
+expect ENOENT lstat ${n0} type,mode
+expect dir,${inode},0755 lstat ${n1} type,inode,mode
+expect 0 rmdir ${n1}
+
+expect 0 mkfifo ${n0} 0644
+expect fifo,0644,1 lstat ${n0} type,mode,nlink
+inode=`${fstest} lstat ${n0} inode`
+expect 0 rename ${n0} ${n1}
+expect ENOENT lstat ${n0} type,mode,nlink
+expect fifo,${inode},0644,1 lstat ${n1} type,inode,mode,nlink
+expect 0 link ${n1} ${n0}
+expect fifo,${inode},0644,2 lstat ${n0} type,inode,mode,nlink
+expect fifo,${inode},0644,2 lstat ${n1} type,inode,mode,nlink
+expect 0 rename ${n1} ${n2}
+expect fifo,${inode},0644,2 lstat ${n0} type,inode,mode,nlink
+expect ENOENT lstat ${n1} type,mode,nlink
+expect fifo,${inode},0644,2 lstat ${n2} type,inode,mode,nlink
+expect 0 unlink ${n0}
+expect 0 unlink ${n2}
+
+expect 0 create ${n0} 0644
+rinode=`${fstest} lstat ${n0} inode`
+expect regular,0644 lstat ${n0} type,mode
+expect 0 symlink ${n0} ${n1}
+sinode=`${fstest} lstat ${n1} inode`
+expect regular,${rinode},0644 stat ${n1} type,inode,mode
+expect symlink,${sinode} lstat ${n1} type,inode
+expect 0 rename ${n1} ${n2}
+expect regular,${rinode},0644 stat ${n0} type,inode,mode
+expect ENOENT lstat ${n1} type,mode
+expect symlink,${sinode} lstat ${n2} type,inode
+expect 0 unlink ${n0}
+expect 0 unlink ${n2}
+
+# successful rename(2) updates ctime.
+expect 0 create ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 rename ${n0} ${n1}
+ctime2=`${fstest} stat ${n1} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n1}
+
+expect 0 mkdir ${n0} 0755
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 rename ${n0} ${n1}
+ctime2=`${fstest} stat ${n1} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 rmdir ${n1}
+
+expect 0 mkfifo ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 rename ${n0} ${n1}
+ctime2=`${fstest} stat ${n1} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n1}
+
+expect 0 symlink ${n2} ${n0}
+ctime1=`${fstest} lstat ${n0} ctime`
+sleep 1
+expect 0 rename ${n0} ${n1}
+ctime2=`${fstest} lstat ${n1} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n1}
+
+# unsuccessful link(2) does not update ctime.
+expect 0 create ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect EACCES -u 65534 rename ${n0} ${n1}
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+
+expect 0 mkdir ${n0} 0755
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect EACCES -u 65534 rename ${n0} ${n1}
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 rmdir ${n0}
+
+expect 0 mkfifo ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect EACCES -u 65534 rename ${n0} ${n1}
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+
+expect 0 symlink ${n2} ${n0}
+ctime1=`${fstest} lstat ${n0} ctime`
+sleep 1
+expect EACCES -u 65534 rename ${n0} ${n1}
+ctime2=`${fstest} lstat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+
+cd ${cdir}
+expect 0 rmdir ${n3}
diff --git a/tools/regression/fstest/tests/rename/01.t b/tools/regression/fstest/tests/rename/01.t
new file mode 100644
index 0000000..7749b90
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/01.t
@@ -0,0 +1,21 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns ENAMETOOLONG if a component of either pathname exceeded 255 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..8"
+
+n0=`namegen`
+
+expect 0 create ${name255} 0644
+expect 0 rename ${name255} ${n0}
+expect 0 rename ${n0} ${name255}
+expect 0 unlink ${name255}
+
+expect 0 create ${n0} 0644
+expect ENAMETOOLONG rename ${n0} ${name256}
+expect 0 unlink ${n0}
+expect ENAMETOOLONG rename ${name256} ${n0}
diff --git a/tools/regression/fstest/tests/rename/02.t b/tools/regression/fstest/tests/rename/02.t
new file mode 100644
index 0000000..cbe2622
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/02.t
@@ -0,0 +1,26 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns ENAMETOOLONG if an entire length of either path name exceeded 1023 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..14"
+
+n0=`namegen`
+
+expect 0 mkdir ${name255} 0755
+expect 0 mkdir ${name255}/${name255} 0755
+expect 0 mkdir ${name255}/${name255}/${name255} 0755
+expect 0 mkdir ${path1021} 0755
+expect 0 create ${n0} 0644
+expect 0 rename ${n0} ${path1023}
+expect 0 rename ${path1023} ${n0}
+expect ENAMETOOLONG rename ${n0} ${path1024}
+expect 0 unlink ${n0}
+expect ENAMETOOLONG rename ${path1024} ${n0}
+expect 0 rmdir ${path1021}
+expect 0 rmdir ${name255}/${name255}/${name255}
+expect 0 rmdir ${name255}/${name255}
+expect 0 rmdir ${name255}
diff --git a/tools/regression/fstest/tests/rename/03.t b/tools/regression/fstest/tests/rename/03.t
new file mode 100644
index 0000000..8404dbe
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/03.t
@@ -0,0 +1,20 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns ENOENT if a component of the 'from' path does not exist, or a path prefix of 'to' does not exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect ENOENT rename ${n0}/${n1}/test ${n2}
+expect 0 create ${n2} 0644
+expect ENOENT rename ${n2} ${n0}/${n1}/test
+expect 0 unlink ${n2}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rename/04.t b/tools/regression/fstest/tests/rename/04.t
new file mode 100644
index 0000000..af3801f
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/04.t
@@ -0,0 +1,43 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EACCES when a component of either path prefix denies search permission"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..18"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+n3=`namegen`
+n4=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 mkdir ${n2} 0755
+expect 0 chown ${n2} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n1}/${n3} 0644
+
+expect 0 -u 65534 -g 65534 rename ${n1}/${n3} ${n2}/${n4}
+expect 0 -u 65534 -g 65534 rename ${n2}/${n4} ${n1}/${n3}
+
+expect 0 chmod ${n1} 0644
+expect EACCES -u 65534 -g 65534 rename ${n1}/${n3} ${n1}/${n4}
+expect EACCES -u 65534 -g 65534 rename ${n1}/${n3} ${n2}/${n4}
+
+expect 0 chmod ${n1} 0755
+expect 0 chmod ${n2} 0644
+expect EACCES -u 65534 -g 65534 rename ${n1}/${n3} ${n2}/${n4}
+
+expect 0 unlink ${n1}/${n3}
+expect 0 rmdir ${n1}
+expect 0 rmdir ${n2}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rename/05.t b/tools/regression/fstest/tests/rename/05.t
new file mode 100644
index 0000000..39aa28f
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/05.t
@@ -0,0 +1,41 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EACCES when the requested link requires writing in a directory with a mode that denies write permission"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..17"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+n3=`namegen`
+n4=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 mkdir ${n2} 0755
+expect 0 chown ${n2} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n1}/${n3} 0644
+
+expect 0 -u 65534 -g 65534 rename ${n1}/${n3} ${n2}/${n4}
+expect 0 -u 65534 -g 65534 rename ${n2}/${n4} ${n1}/${n3}
+
+expect 0 chmod ${n2} 0555
+expect EACCES -u 65534 -g 65534 rename ${n1}/${n3} ${n2}/${n4}
+expect 0 chmod ${n1} 0555
+expect EACCES -u 65534 -g 65534 rename ${n1}/${n3} ${n1}/${n4}
+expect 0 chmod ${n1} 0755
+
+expect 0 unlink ${n1}/${n3}
+expect 0 rmdir ${n1}
+expect 0 rmdir ${n2}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rename/06.t b/tools/regression/fstest/tests/rename/06.t
new file mode 100644
index 0000000..880c604
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/06.t
@@ -0,0 +1,50 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EPERM if the file pointed at by the 'from' argument has its immutable, undeletable or append-only flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..84"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 create ${n0} 0644
+for flag in SF_IMMUTABLE UF_IMMUTABLE SF_APPEND UF_APPEND SF_NOUNLINK UF_NOUNLINK; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect EPERM rename ${n0} ${n1}
+done
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 mkdir ${n0} 0755
+for flag in SF_IMMUTABLE UF_IMMUTABLE SF_APPEND UF_APPEND SF_NOUNLINK UF_NOUNLINK; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect EPERM rename ${n0} ${n1}
+done
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}
+
+expect 0 mkfifo ${n0} 0644
+for flag in SF_IMMUTABLE UF_IMMUTABLE SF_APPEND UF_APPEND SF_NOUNLINK UF_NOUNLINK; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect EPERM rename ${n0} ${n1}
+done
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 symlink ${n1} ${n0}
+for flag in SF_IMMUTABLE UF_IMMUTABLE SF_APPEND UF_APPEND SF_NOUNLINK UF_NOUNLINK; do
+ expect 0 lchflags ${n0} ${flag}
+ expect ${flag} lstat ${n0} flags
+ expect EPERM rename ${n0} ${n1}
+done
+expect 0 lchflags ${n0} none
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/rename/07.t b/tools/regression/fstest/tests/rename/07.t
new file mode 100644
index 0000000..40d0476
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/07.t
@@ -0,0 +1,95 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EPERM if the parent directory of the file pointed at by the 'from' argument has its immutable or append-only flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..106"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+
+expect 0 create ${n0}/${n1} 0644
+for flag in SF_IMMUTABLE UF_IMMUTABLE SF_APPEND UF_APPEND; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect EPERM rename ${n0}/${n1} ${n2}
+done
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 mkdir ${n0}/${n1} 0755
+for flag in SF_IMMUTABLE UF_IMMUTABLE SF_APPEND UF_APPEND; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect EPERM rename ${n0}/${n1} ${n2}
+done
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}/${n1}
+
+expect 0 mkfifo ${n0}/${n1} 0644
+for flag in SF_IMMUTABLE UF_IMMUTABLE SF_APPEND UF_APPEND; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect EPERM rename ${n0}/${n1} ${n2}
+done
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 symlink ${n2} ${n0}/${n1}
+for flag in SF_IMMUTABLE UF_IMMUTABLE SF_APPEND UF_APPEND; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect EPERM rename ${n0}/${n1} ${n2}
+done
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 create ${n0}/${n1} 0644
+for flag in SF_NOUNLINK UF_NOUNLINK; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect 0 rename ${n0}/${n1} ${n2}
+ expect 0 rename ${n2} ${n0}/${n1}
+done
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 mkdir ${n0}/${n1} 0755
+for flag in SF_NOUNLINK UF_NOUNLINK; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect 0 rename ${n0}/${n1} ${n2}
+ expect 0 rename ${n2} ${n0}/${n1}
+done
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}/${n1}
+
+expect 0 mkfifo ${n0}/${n1} 0644
+for flag in SF_NOUNLINK UF_NOUNLINK; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect 0 rename ${n0}/${n1} ${n2}
+ expect 0 rename ${n2} ${n0}/${n1}
+done
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 symlink ${n2} ${n0}/${n1}
+for flag in SF_NOUNLINK UF_NOUNLINK; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect 0 rename ${n0}/${n1} ${n2}
+ expect 0 rename ${n2} ${n0}/${n1}
+done
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rename/08.t b/tools/regression/fstest/tests/rename/08.t
new file mode 100644
index 0000000..962eea1
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/08.t
@@ -0,0 +1,95 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EPERM if the parent directory of the file pointed at by the 'to' argument has its immutable flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..126"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+
+expect 0 create ${n1} 0644
+for flag in SF_IMMUTABLE UF_IMMUTABLE; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect EPERM rename ${n1} ${n0}/${n2}
+done
+expect 0 chflags ${n0} none
+expect 0 unlink ${n1}
+
+expect 0 mkdir ${n1} 0755
+for flag in SF_IMMUTABLE UF_IMMUTABLE; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect EPERM rename ${n1} ${n0}/${n2}
+done
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n1}
+
+expect 0 mkfifo ${n1} 0644
+for flag in SF_IMMUTABLE UF_IMMUTABLE; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect EPERM rename ${n1} ${n0}/${n2}
+done
+expect 0 chflags ${n0} none
+expect 0 unlink ${n1}
+
+expect 0 symlink ${n2} ${n1}
+for flag in SF_IMMUTABLE UF_IMMUTABLE; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect EPERM rename ${n1} ${n0}/${n2}
+done
+expect 0 chflags ${n0} none
+expect 0 unlink ${n1}
+
+expect 0 create ${n1} 0644
+for flag in SF_APPEND UF_APPEND SF_NOUNLINK UF_NOUNLINK; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect 0 rename ${n1} ${n0}/${n2}
+ expect 0 chflags ${n0} none
+ expect 0 rename ${n0}/${n2} ${n1}
+done
+expect 0 unlink ${n1}
+
+expect 0 mkdir ${n1} 0755
+for flag in SF_APPEND UF_APPEND SF_NOUNLINK UF_NOUNLINK; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect 0 rename ${n1} ${n0}/${n2}
+ expect 0 chflags ${n0} none
+ expect 0 rename ${n0}/${n2} ${n1}
+done
+expect 0 rmdir ${n1}
+
+expect 0 mkfifo ${n1} 0644
+for flag in SF_APPEND UF_APPEND SF_NOUNLINK UF_NOUNLINK; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect 0 rename ${n1} ${n0}/${n2}
+ expect 0 chflags ${n0} none
+ expect 0 rename ${n0}/${n2} ${n1}
+done
+expect 0 unlink ${n1}
+
+expect 0 symlink ${n2} ${n1}
+for flag in SF_APPEND UF_APPEND SF_NOUNLINK UF_NOUNLINK; do
+ expect 0 chflags ${n0} ${flag}
+ expect ${flag} stat ${n0} flags
+ expect 0 rename ${n1} ${n0}/${n2}
+ expect 0 chflags ${n0} none
+ expect 0 rename ${n0}/${n2} ${n1}
+done
+expect 0 unlink ${n1}
+
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rename/09.t b/tools/regression/fstest/tests/rename/09.t
new file mode 100644
index 0000000..41270f1
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/09.t
@@ -0,0 +1,94 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EACCES or EPERM if the directory containing 'from' is marked sticky, and neither the containing directory nor 'from' are owned by the effective user ID"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..56"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+n3=`namegen`
+n4=`namegen`
+
+expect 0 mkdir ${n4} 0755
+cdir=`pwd`
+cd ${n4}
+
+expect 0 mkdir ${n0} 0755
+expect 0 chown ${n0} 65534 65534
+expect 0 chmod ${n0} 01777
+
+expect 0 mkdir ${n1} 0755
+
+# User owns both: the sticky directory and the file to be renamed.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n0}/${n2} 0644
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect 0 unlink ${n1}/${n3}
+# User owns the file to be renamed, but doesn't own the sticky directory.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65533 -g 65533 create ${n0}/${n2} 0644
+expect 0 -u 65533 -g 65533 rename ${n0}/${n2} ${n1}/${n3}
+expect 0 unlink ${n1}/${n3}
+# User owns the sticky directory, but doesn't own the file to be renamed.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65533 -g 65533 create ${n0}/${n2} 0644
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect 0 unlink ${n1}/${n3}
+# User doesn't own the sticky directory nor the file to be renamed.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65534 -g 65534 create ${n0}/${n2} 0644
+expect "EACCES|EPERM" -u 65533 -g 65533 rename ${n0}/${n2} ${n1}/${n3}
+expect 0 unlink ${n0}/${n2}
+
+# User owns both: the sticky directory and the fifo to be renamed.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 mkfifo ${n0}/${n2} 0644
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect 0 unlink ${n1}/${n3}
+# User owns the fifo to be renamed, but doesn't own the sticky directory.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65533 -g 65533 mkfifo ${n0}/${n2} 0644
+expect 0 -u 65533 -g 65533 rename ${n0}/${n2} ${n1}/${n3}
+expect 0 unlink ${n1}/${n3}
+# User owns the sticky directory, but doesn't own the fifo to be renamed.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65533 -g 65533 mkfifo ${n0}/${n2} 0644
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect 0 unlink ${n1}/${n3}
+# User doesn't own the sticky directory nor the fifo to be renamed.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65534 -g 65534 mkfifo ${n0}/${n2} 0644
+expect "EACCES|EPERM" -u 65533 -g 65533 rename ${n0}/${n2} ${n1}/${n3}
+expect 0 unlink ${n0}/${n2}
+
+# User owns both: the sticky directory and the symlink to be renamed.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 symlink test ${n0}/${n2}
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect 0 unlink ${n1}/${n3}
+# User owns the symlink to be renamed, but doesn't own the sticky directory.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65533 -g 65533 symlink test ${n0}/${n2}
+expect 0 -u 65533 -g 65533 rename ${n0}/${n2} ${n1}/${n3}
+expect 0 unlink ${n1}/${n3}
+# User owns the sticky directory, but doesn't own the symlink to be renamed.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65533 -g 65533 symlink test ${n0}/${n2}
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect 0 unlink ${n1}/${n3}
+# User doesn't own the sticky directory nor the symlink to be renamed.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65534 -g 65534 symlink test ${n0}/${n2}
+expect "EACCES|EPERM" -u 65533 -g 65533 rename ${n0}/${n2} ${n1}/${n3}
+expect 0 unlink ${n0}/${n2}
+
+expect 0 rmdir ${n1}
+expect 0 rmdir ${n0}
+
+cd ${cdir}
+expect 0 rmdir ${n4}
diff --git a/tools/regression/fstest/tests/rename/10.t b/tools/regression/fstest/tests/rename/10.t
new file mode 100644
index 0000000..6d5e831
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/10.t
@@ -0,0 +1,243 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EACCES or EPERM if the file pointed at by the 'to' argument exists, the directory containing 'to' is marked sticky, and neither the containing directory nor 'to' are owned by the effective user ID"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..188"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+n3=`namegen`
+n4=`namegen`
+
+expect 0 mkdir ${n4} 0755
+cdir=`pwd`
+cd ${n4}
+
+expect 0 mkdir ${n0} 0755
+expect 0 chown ${n0} 65534 65534
+
+expect 0 mkdir ${n1} 0755
+expect 0 chmod ${n1} 01777
+
+# User owns both: the sticky directory and the destination file.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n0}/${n2} 0644
+inode=`${fstest} lstat ${n0}/${n2} inode`
+expect 0 -u 65534 -g 65534 create ${n1}/${n3} 0644
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} inode
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 mkfifo ${n0}/${n2} 0644
+expect 0 -u 65534 -g 65534 rename ${n1}/${n3} ${n0}/${n2}
+expect ${inode} lstat ${n0}/${n2} inode
+expect ENOENT lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 symlink test ${n1}/${n3}
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} inode
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 unlink ${n1}/${n3}
+# User owns the sticky directory, but doesn't own the destination file.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n0}/${n2} 0644
+inode=`${fstest} lstat ${n0}/${n2} inode`
+expect 0 -u 65534 -g 65534 create ${n1}/${n3} 0644
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} type
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 mkfifo ${n0}/${n2} 0644
+expect 0 -u 65534 -g 65534 rename ${n1}/${n3} ${n0}/${n2}
+expect ${inode} lstat ${n0}/${n2} inode
+expect ENOENT lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 symlink test ${n1}/${n3}
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} inode
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 unlink ${n1}/${n3}
+# User owns the destination file, but doesn't own the sticky directory.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65534 -g 65534 create ${n0}/${n2} 0644
+inode=`${fstest} lstat ${n0}/${n2} inode`
+expect 0 -u 65534 -g 65534 create ${n1}/${n3} 0644
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} type
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 mkfifo ${n0}/${n2} 0644
+expect 0 -u 65534 -g 65534 rename ${n1}/${n3} ${n0}/${n2}
+expect ${inode} lstat ${n0}/${n2} inode
+expect ENOENT lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 symlink test ${n1}/${n3}
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} inode
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 unlink ${n1}/${n3}
+# User doesn't own the sticky directory nor the destination file.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65534 -g 65534 create ${n0}/${n2} 0644
+expect 0 -u 65533 -g 65533 create ${n1}/${n3} 0644
+inode=`${fstest} lstat ${n1}/${n3} inode`
+expect "EACCES|EPERM" -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 unlink ${n0}/${n2}
+expect 0 unlink ${n1}/${n3}
+
+# User owns both: the sticky directory and the destination file.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 mkdir ${n0}/${n2} 0755
+expect 0 -u 65534 -g 65534 mkdir ${n1}/${n3} 0755
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} type
+expect 0 rmdir ${n1}/${n3}
+# User owns the sticky directory, but doesn't own the destination file.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 mkdir ${n0}/${n2} 0755
+expect 0 -u 65534 -g 65534 mkdir ${n1}/${n3} 0755
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} type
+expect 0 rmdir ${n1}/${n3}
+# User owns the destination file, but doesn't own the sticky directory.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65534 -g 65534 mkdir ${n0}/${n2} 0755
+expect 0 -u 65534 -g 65534 mkdir ${n1}/${n3} 0755
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} type
+expect 0 rmdir ${n1}/${n3}
+# User doesn't own the sticky directory nor the destination file.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65534 -g 65534 mkdir ${n0}/${n2} 0755
+expect 0 -u 65533 -g 65533 mkdir ${n1}/${n3} 0755
+expect "EACCES|EPERM" -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect 0 rmdir ${n0}/${n2}
+expect 0 rmdir ${n1}/${n3}
+
+# User owns both: the sticky directory and the destination file.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 mkfifo ${n0}/${n2} 0644
+inode=`${fstest} lstat ${n0}/${n2} inode`
+expect 0 -u 65534 -g 65534 mkfifo ${n1}/${n3} 0644
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} inode
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 create ${n0}/${n2} 0644
+expect 0 -u 65534 -g 65534 rename ${n1}/${n3} ${n0}/${n2}
+expect ${inode} lstat ${n0}/${n2} inode
+expect ENOENT lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 symlink test ${n1}/${n3}
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} inode
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 unlink ${n1}/${n3}
+# User owns the sticky directory, but doesn't own the destination file.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 mkfifo ${n0}/${n2} 0644
+inode=`${fstest} lstat ${n0}/${n2} inode`
+expect 0 -u 65534 -g 65534 mkfifo ${n1}/${n3} 0644
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} type
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 create ${n0}/${n2} 0644
+expect 0 -u 65534 -g 65534 rename ${n1}/${n3} ${n0}/${n2}
+expect ${inode} lstat ${n0}/${n2} inode
+expect ENOENT lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 symlink test ${n1}/${n3}
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} inode
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 unlink ${n1}/${n3}
+# User owns the destination file, but doesn't own the sticky directory.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65534 -g 65534 mkfifo ${n0}/${n2} 0644
+inode=`${fstest} lstat ${n0}/${n2} inode`
+expect 0 -u 65534 -g 65534 mkfifo ${n1}/${n3} 0644
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} type
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 create ${n0}/${n2} 0644
+expect 0 -u 65534 -g 65534 rename ${n1}/${n3} ${n0}/${n2}
+expect ${inode} lstat ${n0}/${n2} inode
+expect ENOENT lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 symlink test ${n1}/${n3}
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} inode
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 unlink ${n1}/${n3}
+# User doesn't own the sticky directory nor the destination file.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65534 -g 65534 mkfifo ${n0}/${n2} 0644
+expect 0 -u 65533 -g 65533 mkfifo ${n1}/${n3} 0644
+inode=`${fstest} lstat ${n1}/${n3} inode`
+expect "EACCES|EPERM" -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 unlink ${n0}/${n2}
+expect 0 unlink ${n1}/${n3}
+
+# User owns both: the sticky directory and the destination file.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 symlink test ${n0}/${n2}
+inode=`${fstest} lstat ${n0}/${n2} inode`
+expect 0 -u 65534 -g 65534 symlink test ${n1}/${n3}
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} inode
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 create ${n0}/${n2} 0644
+expect 0 -u 65534 -g 65534 rename ${n1}/${n3} ${n0}/${n2}
+expect ${inode} lstat ${n0}/${n2} inode
+expect ENOENT lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 mkfifo ${n1}/${n3} 0644
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} inode
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 unlink ${n1}/${n3}
+# User owns the sticky directory, but doesn't own the destination file.
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 symlink test ${n0}/${n2}
+inode=`${fstest} lstat ${n0}/${n2} inode`
+expect 0 -u 65534 -g 65534 symlink test ${n1}/${n3}
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} type
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 create ${n0}/${n2} 0644
+expect 0 -u 65534 -g 65534 rename ${n1}/${n3} ${n0}/${n2}
+expect ${inode} lstat ${n0}/${n2} inode
+expect ENOENT lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 mkfifo ${n1}/${n3} 0644
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} inode
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 unlink ${n1}/${n3}
+# User owns the destination file, but doesn't own the sticky directory.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65534 -g 65534 symlink test ${n0}/${n2}
+inode=`${fstest} lstat ${n0}/${n2} inode`
+expect 0 -u 65534 -g 65534 symlink test ${n1}/${n3}
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} type
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 create ${n0}/${n2} 0644
+expect 0 -u 65534 -g 65534 rename ${n1}/${n3} ${n0}/${n2}
+expect ${inode} lstat ${n0}/${n2} inode
+expect ENOENT lstat ${n1}/${n3} inode
+expect 0 -u 65534 -g 65534 mkfifo ${n1}/${n3} 0644
+expect 0 -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ENOENT lstat ${n0}/${n2} inode
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 unlink ${n1}/${n3}
+# User doesn't own the sticky directory nor the destination file.
+expect 0 chown ${n1} 65533 65533
+expect 0 -u 65534 -g 65534 symlink test ${n0}/${n2}
+expect 0 -u 65533 -g 65533 symlink test ${n1}/${n3}
+inode=`${fstest} lstat ${n1}/${n3} inode`
+expect "EACCES|EPERM" -u 65534 -g 65534 rename ${n0}/${n2} ${n1}/${n3}
+expect ${inode} lstat ${n1}/${n3} inode
+expect 0 unlink ${n0}/${n2}
+expect 0 unlink ${n1}/${n3}
+
+expect 0 rmdir ${n1}
+expect 0 rmdir ${n0}
+
+cd ${cdir}
+expect 0 rmdir ${n4}
diff --git a/tools/regression/fstest/tests/rename/11.t b/tools/regression/fstest/tests/rename/11.t
new file mode 100644
index 0000000..6120e64
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/11.t
@@ -0,0 +1,24 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns ELOOP if too many symbolic links were encountered in translating one of the pathnames"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..10"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 symlink ${n0} ${n1}
+expect 0 symlink ${n1} ${n0}
+expect ELOOP rename ${n0}/test ${n2}
+expect ELOOP rename ${n1}/test ${n2}
+expect 0 create ${n2} 0644
+expect ELOOP rename ${n2} ${n0}/test
+expect ELOOP rename ${n2} ${n1}/test
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
+expect 0 unlink ${n2}
diff --git a/tools/regression/fstest/tests/rename/12.t b/tools/regression/fstest/tests/rename/12.t
new file mode 100644
index 0000000..504980c
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/12.t
@@ -0,0 +1,22 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns ENOTDIR if a component of either path prefix is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..8"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+expect ENOTDIR rename ${n0}/${n1}/test ${n0}/${n2}
+expect 0 create ${n0}/${n2} 0644
+expect ENOTDIR link ${n0}/${n2} ${n0}/${n1}/test
+expect 0 unlink ${n0}/${n1}
+expect 0 unlink ${n0}/${n2}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rename/13.t b/tools/regression/fstest/tests/rename/13.t
new file mode 100644
index 0000000..5697311
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/13.t
@@ -0,0 +1,34 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns ENOTDIR when the 'from' argument is a directory, but 'to' is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..17"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+
+expect 0 create ${n1} 0644
+expect ENOTDIR rename ${n0} ${n1}
+expect dir lstat ${n0} type
+expect regular lstat ${n1} type
+expect 0 unlink ${n1}
+
+expect 0 mkfifo ${n1} 0644
+expect ENOTDIR rename ${n0} ${n1}
+expect dir lstat ${n0} type
+expect fifo lstat ${n1} type
+expect 0 unlink ${n1}
+
+expect 0 symlink test ${n1}
+expect ENOTDIR rename ${n0} ${n1}
+expect dir lstat ${n0} type
+expect symlink lstat ${n1} type
+expect 0 unlink ${n1}
+
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rename/14.t b/tools/regression/fstest/tests/rename/14.t
new file mode 100644
index 0000000..806e09d
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/14.t
@@ -0,0 +1,34 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EISDIR when the 'to' argument is a directory, but 'from' is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..17"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+
+expect 0 create ${n1} 0644
+expect EISDIR rename ${n1} ${n0}
+expect dir lstat ${n0} type
+expect regular lstat ${n1} type
+expect 0 unlink ${n1}
+
+expect 0 mkfifo ${n1} 0644
+expect EISDIR rename ${n1} ${n0}
+expect dir lstat ${n0} type
+expect fifo lstat ${n1} type
+expect 0 unlink ${n1}
+
+expect 0 symlink test ${n1}
+expect EISDIR rename ${n1} ${n0}
+expect dir lstat ${n0} type
+expect symlink lstat ${n1} type
+expect 0 unlink ${n1}
+
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rename/15.t b/tools/regression/fstest/tests/rename/15.t
new file mode 100644
index 0000000..0ef6cc3
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/15.t
@@ -0,0 +1,45 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EXDEV if the link named by 'to' and the file named by 'from' are on different file systems"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}" in
+FreeBSD)
+ echo "1..14"
+
+ n0=`namegen`
+ n1=`namegen`
+ n2=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+
+ expect 0 create ${n0}/${n1} 0644
+ expect EXDEV rename ${n0}/${n1} ${n2}
+ expect 0 unlink ${n0}/${n1}
+
+ expect 0 mkdir ${n0}/${n1} 0755
+ expect EXDEV rename ${n0}/${n1} ${n2}
+ expect 0 rmdir ${n0}/${n1}
+
+ expect 0 mkfifo ${n0}/${n1} 0644
+ expect EXDEV rename ${n0}/${n1} ${n2}
+ expect 0 unlink ${n0}/${n1}
+
+ expect 0 symlink test ${n0}/${n1}
+ expect EXDEV rename ${n0}/${n1} ${n2}
+ expect 0 unlink ${n0}/${n1}
+
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/rename/16.t b/tools/regression/fstest/tests/rename/16.t
new file mode 100644
index 0000000..cda8e99
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/16.t
@@ -0,0 +1,37 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EROFS if the requested link requires writing in a directory on a read-only file system"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}" in
+FreeBSD)
+ echo "1..8"
+
+ n0=`namegen`
+ n1=`namegen`
+ n2=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 create ${n0}/${n1} 0644
+ mount -ur /dev/md${n}
+
+ expect EROFS rename ${n0}/${n1} ${n0}/${n2}
+ expect EROFS rename ${n0}/${n1} ${n2}
+ expect 0 create ${n2} 0644
+ expect EROFS rename ${n2} ${n0}/${n2}
+ expect 0 unlink ${n2}
+
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/rename/17.t b/tools/regression/fstest/tests/rename/17.t
new file mode 100644
index 0000000..a391349
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/17.t
@@ -0,0 +1,20 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EFAULT if one of the pathnames specified is outside the process's allocated address space"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..8"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+expect EFAULT rename ${n0} NULL
+expect EFAULT rename ${n0} DEADCODE
+expect 0 unlink ${n0}
+expect EFAULT rename NULL ${n0}
+expect EFAULT rename DEADCODE ${n0}
+expect EFAULT rename NULL DEADCODE
+expect EFAULT rename DEADCODE NULL
diff --git a/tools/regression/fstest/tests/rename/18.t b/tools/regression/fstest/tests/rename/18.t
new file mode 100644
index 0000000..a69913b
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/18.t
@@ -0,0 +1,22 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EINVAL when the 'from' argument is a parent directory of 'to'"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 mkdir ${n0}/${n1} 0755
+
+expect EINVAL rename ${n0} ${n0}/${n1}
+expect EINVAL rename ${n0} ${n0}/${n1}/${n2}
+
+expect 0 rmdir ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rename/19.t b/tools/regression/fstest/tests/rename/19.t
new file mode 100644
index 0000000..b068a01
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/19.t
@@ -0,0 +1,22 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EINVAL when an attempt is made to rename '.' or '..'"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 mkdir ${n0}/${n1} 0755
+
+expect EINVAL rename ${n0}/${n1}/. ${n2}
+expect EINVAL rename ${n0}/${n1}/.. ${n2}
+
+expect 0 rmdir ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rename/20.t b/tools/regression/fstest/tests/rename/20.t
new file mode 100644
index 0000000..8a00d1f
--- /dev/null
+++ b/tools/regression/fstest/tests/rename/20.t
@@ -0,0 +1,35 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rename returns EEXIST or ENOTEMPTY if the 'to' argument is a directory and is not empty"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..16"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 mkdir ${n1} 0755
+
+expect 0 create ${n1}/${n2} 0644
+expect "EEXIST|ENOTEMPTY" rename ${n0} ${n1}
+expect 0 unlink ${n1}/${n2}
+
+expect 0 mkdir ${n1}/${n2} 0755
+expect "EEXIST|ENOTEMPTY" rename ${n0} ${n1}
+expect 0 rmdir ${n1}/${n2}
+
+expect 0 mkfifo ${n1}/${n2} 0644
+expect "EEXIST|ENOTEMPTY" rename ${n0} ${n1}
+expect 0 unlink ${n1}/${n2}
+
+expect 0 symlink test ${n1}/${n2}
+expect "EEXIST|ENOTEMPTY" rename ${n0} ${n1}
+expect 0 unlink ${n1}/${n2}
+
+expect 0 rmdir ${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rmdir/00.t b/tools/regression/fstest/tests/rmdir/00.t
new file mode 100644
index 0000000..4381e66
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/00.t
@@ -0,0 +1,28 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir removes directories"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..10"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect dir lstat ${n0} type
+expect 0 rmdir ${n0}
+expect ENOENT lstat ${n0} type
+
+expect 0 mkdir ${n0} 0755
+expect 0 mkdir ${n0}/${n1} 0755
+time=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 rmdir ${n0}/${n1}
+mtime=`${fstest} stat ${n0} mtime`
+test_check $time -lt $mtime
+ctime=`${fstest} stat ${n0} ctime`
+test_check $time -lt $ctime
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rmdir/01.t b/tools/regression/fstest/tests/rmdir/01.t
new file mode 100644
index 0000000..d2d407d
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/01.t
@@ -0,0 +1,30 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns ENOTDIR if a component of the path is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..14"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+expect ENOTDIR rmdir ${n0}/${n1}/test
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
+
+expect 0 create ${n0} 0644
+expect ENOTDIR rmdir ${n0}
+expect 0 unlink ${n0}
+
+expect 0 symlink ${n1} ${n0}
+expect ENOTDIR rmdir ${n0}
+expect 0 unlink ${n0}
+
+expect 0 mkfifo ${n0} 0644
+expect ENOTDIR rmdir ${n0}
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/rmdir/02.t b/tools/regression/fstest/tests/rmdir/02.t
new file mode 100644
index 0000000..dba59ae
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/02.t
@@ -0,0 +1,14 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns ENAMETOOLONG if a component of a pathname exceeded 255 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..4"
+
+expect 0 mkdir ${name255} 0755
+expect 0 rmdir ${name255}
+expect ENOENT rmdir ${name255}
+expect ENAMETOOLONG rmdir ${name256}
diff --git a/tools/regression/fstest/tests/rmdir/03.t b/tools/regression/fstest/tests/rmdir/03.t
new file mode 100644
index 0000000..1f70eca
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/03.t
@@ -0,0 +1,22 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns ENAMETOOLONG if an entire path name exceeded 1023 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+expect 0 mkdir ${name255} 0755
+expect 0 mkdir ${name255}/${name255} 0755
+expect 0 mkdir ${name255}/${name255}/${name255} 0755
+expect 0 mkdir ${path1021} 0755
+expect 0 mkdir ${path1023} 0755
+expect 0 rmdir ${path1023}
+expect ENOENT rmdir ${path1023}
+expect ENAMETOOLONG rmdir ${path1024}
+expect 0 rmdir ${path1021}
+expect 0 rmdir ${name255}/${name255}/${name255}
+expect 0 rmdir ${name255}/${name255}
+expect 0 rmdir ${name255}
diff --git a/tools/regression/fstest/tests/rmdir/04.t b/tools/regression/fstest/tests/rmdir/04.t
new file mode 100644
index 0000000..77e1d30
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/04.t
@@ -0,0 +1,17 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns ENOENT if the named directory does not exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..4"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 rmdir ${n0}
+expect ENOENT rmdir ${n0}
+expect ENOENT rmdir ${n1}
diff --git a/tools/regression/fstest/tests/rmdir/05.t b/tools/regression/fstest/tests/rmdir/05.t
new file mode 100644
index 0000000..fd973a9
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/05.t
@@ -0,0 +1,19 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns ELOOP if too many symbolic links were encountered in translating the pathname"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 symlink ${n0} ${n1}
+expect 0 symlink ${n1} ${n0}
+expect ELOOP rmdir ${n0}/test
+expect ELOOP rmdir ${n1}/test
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
diff --git a/tools/regression/fstest/tests/rmdir/06.t b/tools/regression/fstest/tests/rmdir/06.t
new file mode 100644
index 0000000..dbb378b
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/06.t
@@ -0,0 +1,36 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns EEXIST or ENOTEMPTY the named directory contains files other than '.' and '..' in it"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..20"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 mkdir ${n0}/${n1} 0755
+expect "EEXIST|ENOTEMPTY" rmdir ${n0}
+expect 0 rmdir ${n0}/${n1}
+expect 0 rmdir ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+expect "EEXIST|ENOTEMPTY" rmdir ${n0}
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect 0 symlink test ${n0}/${n1}
+expect "EEXIST|ENOTEMPTY" rmdir ${n0}
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect 0 mkfifo ${n0}/${n1} 0644
+expect "EEXIST|ENOTEMPTY" rmdir ${n0}
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rmdir/07.t b/tools/regression/fstest/tests/rmdir/07.t
new file mode 100644
index 0000000..2528245
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/07.t
@@ -0,0 +1,27 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns EACCES when search permission is denied for a component of the path prefix"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..10"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 mkdir ${n1}/${n2} 0755
+expect 0 chmod ${n1} 0644
+expect EACCES -u 65534 -g 65534 rmdir ${n1}/${n2}
+expect 0 chmod ${n1} 0755
+expect 0 -u 65534 -g 65534 rmdir ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rmdir/08.t b/tools/regression/fstest/tests/rmdir/08.t
new file mode 100644
index 0000000..c1fb819
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/08.t
@@ -0,0 +1,27 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns EACCES when write permission is denied on the directory containing the link to be removed"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..10"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 mkdir ${n1}/${n2} 0755
+expect 0 chmod ${n1} 0555
+expect EACCES -u 65534 -g 65534 rmdir ${n1}/${n2}
+expect 0 chmod ${n1} 0755
+expect 0 -u 65534 -g 65534 rmdir ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rmdir/09.t b/tools/regression/fstest/tests/rmdir/09.t
new file mode 100644
index 0000000..6b3959d
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/09.t
@@ -0,0 +1,49 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns EPERM if the named file has its immutable, undeletable or append-only flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..30"
+
+n0=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM rmdir ${n0}
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM rmdir ${n0}
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect 0 chflags ${n0} SF_NOUNLINK
+expect EPERM rmdir ${n0}
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect 0 chflags ${n0} UF_NOUNLINK
+expect EPERM rmdir ${n0}
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect 0 chflags ${n0} SF_APPEND
+expect EPERM rmdir ${n0}
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect 0 chflags ${n0} UF_APPEND
+expect EPERM rmdir ${n0}
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rmdir/10.t b/tools/regression/fstest/tests/rmdir/10.t
new file mode 100644
index 0000000..2258041
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/10.t
@@ -0,0 +1,52 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns EPERM if the parent directory of the named file has its immutable or append-only flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..30"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+
+expect 0 mkdir ${n0}/${n1} 0755
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM rmdir ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}/${n1}
+
+expect 0 mkdir ${n0}/${n1} 0755
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM rmdir ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}/${n1}
+
+expect 0 mkdir ${n0}/${n1} 0755
+expect 0 chflags ${n0} SF_APPEND
+expect EPERM rmdir ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}/${n1}
+
+expect 0 mkdir ${n0}/${n1} 0755
+expect 0 chflags ${n0} UF_APPEND
+expect EPERM rmdir ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 rmdir ${n0}/${n1}
+
+expect 0 mkdir ${n0}/${n1} 0755
+expect 0 chflags ${n0} SF_NOUNLINK
+expect 0 rmdir ${n0}/${n1}
+expect 0 chflags ${n0} none
+
+expect 0 mkdir ${n0}/${n1} 0755
+expect 0 chflags ${n0} UF_NOUNLINK
+expect 0 rmdir ${n0}/${n1}
+expect 0 chflags ${n0} none
+
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rmdir/11.t b/tools/regression/fstest/tests/rmdir/11.t
new file mode 100644
index 0000000..b899948
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/11.t
@@ -0,0 +1,40 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns EACCES or EPERM if the directory containing the directory to be removed is marked sticky, and neither the containing directory nor the directory to be removed are owned by the effective user ID"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..15"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n2} 0755
+cdir=`pwd`
+cd ${n2}
+
+expect 0 mkdir ${n0} 0755
+expect 0 chown ${n0} 65534 65534
+expect 0 chmod ${n0} 01777
+
+# User owns both: the sticky directory and the directory to be removed.
+expect 0 -u 65534 -g 65534 mkdir ${n0}/${n1} 0755
+expect 0 -u 65534 -g 65534 rmdir ${n0}/${n1}
+# User owns the directory to be removed, but doesn't own the sticky directory.
+expect 0 -u 65533 -g 65533 mkdir ${n0}/${n1} 0755
+expect 0 -u 65533 -g 65533 rmdir ${n0}/${n1}
+# User owns the sticky directory, but doesn't own the directory to be removed.
+expect 0 -u 65533 -g 65533 mkdir ${n0}/${n1} 0755
+expect 0 -u 65534 -g 65534 rmdir ${n0}/${n1}
+# User doesn't own the sticky directory nor the directory to be removed.
+expect 0 -u 65534 -g 65534 mkdir ${n0}/${n1} 0755
+expect "EACCES|EPERM" -u 65533 -g 65533 rmdir ${n0}/${n1}
+expect 0 rmdir ${n0}/${n1}
+
+expect 0 rmdir ${n0}
+
+cd ${cdir}
+expect 0 rmdir ${n2}
diff --git a/tools/regression/fstest/tests/rmdir/12.t b/tools/regression/fstest/tests/rmdir/12.t
new file mode 100644
index 0000000..06852f4
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/12.t
@@ -0,0 +1,26 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns EINVAL if the last component of the path is '.' or '..'"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 mkdir ${n0}/${n1} 0755
+expect EINVAL rmdir ${n0}/${n1}/.
+case "${os}" in
+FreeBSD)
+ expect EINVAL rmdir ${n0}/${n1}/..
+ ;;
+*)
+ expect EEXIST rmdir ${n0}/${n1}/..
+ ;;
+esac
+expect 0 rmdir ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/rmdir/13.t b/tools/regression/fstest/tests/rmdir/13.t
new file mode 100644
index 0000000..65fb78e
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/13.t
@@ -0,0 +1,27 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns EBUSY if the directory to be removed is the mount point for a mounted file system"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}" in
+FreeBSD)
+ echo "1..3"
+
+ n0=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect EBUSY rmdir ${n0}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/rmdir/14.t b/tools/regression/fstest/tests/rmdir/14.t
new file mode 100644
index 0000000..b195933
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/14.t
@@ -0,0 +1,32 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns EROFS if the named file resides on a read-only file system"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..5"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 mkdir ${n0}/${n1} 0755
+ mount -ur /dev/md${n}
+ expect EROFS rmdir ${n0}/${n1}
+ mount -uw /dev/md${n}
+ expect 0 rmdir ${n0}/${n1}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/rmdir/15.t b/tools/regression/fstest/tests/rmdir/15.t
new file mode 100644
index 0000000..8bfa149
--- /dev/null
+++ b/tools/regression/fstest/tests/rmdir/15.t
@@ -0,0 +1,12 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="rmdir returns EFAULT if the path argument points outside the process's allocated address space"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..2"
+
+expect EFAULT rmdir NULL
+expect EFAULT rmdir DEADCODE
diff --git a/tools/regression/fstest/tests/symlink/00.t b/tools/regression/fstest/tests/symlink/00.t
new file mode 100644
index 0000000..6e6d46d
--- /dev/null
+++ b/tools/regression/fstest/tests/symlink/00.t
@@ -0,0 +1,32 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="symlink creates symbolic links"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..14"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 create ${n0} 0644
+expect regular,0644 lstat ${n0} type,mode
+expect 0 symlink ${n0} ${n1}
+expect symlink lstat ${n1} type
+expect regular,0644 stat ${n1} type,mode
+expect 0 unlink ${n0}
+expect ENOENT stat ${n1} type,mode
+expect 0 unlink ${n1}
+
+expect 0 mkdir ${n0} 0755
+time=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 symlink test ${n0}/${n1}
+mtime=`${fstest} stat ${n0} mtime`
+test_check $time -lt $mtime
+ctime=`${fstest} stat ${n0} ctime`
+test_check $time -lt $ctime
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/symlink/01.t b/tools/regression/fstest/tests/symlink/01.t
new file mode 100644
index 0000000..f19870c
--- /dev/null
+++ b/tools/regression/fstest/tests/symlink/01.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="symlink returns ENOTDIR if a component of the name2 path prefix is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..5"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+expect ENOTDIR symlink test ${n0}/${n1}/test
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/symlink/02.t b/tools/regression/fstest/tests/symlink/02.t
new file mode 100644
index 0000000..630ce8a
--- /dev/null
+++ b/tools/regression/fstest/tests/symlink/02.t
@@ -0,0 +1,20 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="symlink returns ENAMETOOLONG if a component of the name2 pathname exceeded 255 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..7"
+
+n0=`namegen`
+
+expect 0 symlink ${name255} ${n0}
+expect 0 unlink ${n0}
+expect 0 symlink ${n0} ${name255}
+expect 0 unlink ${name255}
+
+expect ENAMETOOLONG symlink ${n0} ${name256}
+expect 0 symlink ${name256} ${n0}
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/symlink/03.t b/tools/regression/fstest/tests/symlink/03.t
new file mode 100644
index 0000000..dc642d4
--- /dev/null
+++ b/tools/regression/fstest/tests/symlink/03.t
@@ -0,0 +1,26 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="symlink returns ENAMETOOLONG if an entire length of either path name exceeded 1023 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..14"
+
+n0=`namegen`
+
+expect 0 symlink ${path1023} ${n0}
+expect 0 unlink ${n0}
+expect 0 mkdir ${name255} 0755
+expect 0 mkdir ${name255}/${name255} 0755
+expect 0 mkdir ${name255}/${name255}/${name255} 0755
+expect 0 mkdir ${path1021} 0755
+expect 0 symlink ${n0} ${path1023}
+expect 0 unlink ${path1023}
+expect ENAMETOOLONG symlink ${n0} ${path1024}
+expect ENAMETOOLONG symlink ${path1024} ${n0}
+expect 0 rmdir ${path1021}
+expect 0 rmdir ${name255}/${name255}/${name255}
+expect 0 rmdir ${name255}/${name255}
+expect 0 rmdir ${name255}
diff --git a/tools/regression/fstest/tests/symlink/04.t b/tools/regression/fstest/tests/symlink/04.t
new file mode 100644
index 0000000..cc5e7b7
--- /dev/null
+++ b/tools/regression/fstest/tests/symlink/04.t
@@ -0,0 +1,16 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="symlink returns ENOENT if a component of the name2 path prefix does not exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..3"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect ENOENT symlink test ${n0}/${n1}/test
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/symlink/05.t b/tools/regression/fstest/tests/symlink/05.t
new file mode 100644
index 0000000..c823a59
--- /dev/null
+++ b/tools/regression/fstest/tests/symlink/05.t
@@ -0,0 +1,34 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="symlink returns EACCES when a component of the name2 path prefix denies search permission"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+
+expect 0 -u 65534 -g 65534 symlink test ${n1}/${n2}
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+
+expect 0 chmod ${n1} 0644
+expect EACCES -u 65534 -g 65534 symlink test ${n1}/${n2}
+expect 0 chmod ${n1} 0755
+expect 0 -u 65534 -g 65534 symlink test ${n1}/${n2}
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+
+expect 0 rmdir ${n1}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/symlink/06.t b/tools/regression/fstest/tests/symlink/06.t
new file mode 100644
index 0000000..1f27818
--- /dev/null
+++ b/tools/regression/fstest/tests/symlink/06.t
@@ -0,0 +1,34 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="symlink returns EACCES if the parent directory of the file to be created denies write permission"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+
+expect 0 -u 65534 -g 65534 symlink test ${n1}/${n2}
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+
+expect 0 chmod ${n1} 0555
+expect EACCES -u 65534 -g 65534 symlink test ${n1}/${n2}
+expect 0 chmod ${n1} 0755
+expect 0 -u 65534 -g 65534 symlink test ${n1}/${n2}
+expect 0 unlink ${n1}/${n2}
+
+expect 0 rmdir ${n1}
+
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/symlink/07.t b/tools/regression/fstest/tests/symlink/07.t
new file mode 100644
index 0000000..aa60b77
--- /dev/null
+++ b/tools/regression/fstest/tests/symlink/07.t
@@ -0,0 +1,19 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="symlink returns ELOOP if too many symbolic links were encountered in translating the name2 path name"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 symlink ${n0} ${n1}
+expect 0 symlink ${n1} ${n0}
+expect ELOOP symlink test ${n0}/test
+expect ELOOP symlink test ${n1}/test
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
diff --git a/tools/regression/fstest/tests/symlink/08.t b/tools/regression/fstest/tests/symlink/08.t
new file mode 100644
index 0000000..c4843e5
--- /dev/null
+++ b/tools/regression/fstest/tests/symlink/08.t
@@ -0,0 +1,23 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="symlink returns EEXIST if the name2 argument already exists"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..9"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+expect EEXIST symlink test ${n0}
+expect 0 unlink ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect EEXIST symlink test ${n0}
+expect 0 rmdir ${n0}
+
+expect 0 symlink test ${n0}
+expect EEXIST symlink test ${n0}
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/symlink/09.t b/tools/regression/fstest/tests/symlink/09.t
new file mode 100644
index 0000000..174b5bd
--- /dev/null
+++ b/tools/regression/fstest/tests/symlink/09.t
@@ -0,0 +1,53 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="symlink returns EPERM if the parent directory of the file named by name2 has its immutable flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..30"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+
+expect 0 symlink test ${n0}/${n1}
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM symlink test ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 symlink test ${n0}/${n1}
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM symlink test ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 symlink test ${n0}/${n1}
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} SF_APPEND
+expect 0 symlink test ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} UF_APPEND
+expect 0 symlink test ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} SF_NOUNLINK
+expect 0 symlink test ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 chflags ${n0} UF_NOUNLINK
+expect 0 symlink test ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/symlink/10.t b/tools/regression/fstest/tests/symlink/10.t
new file mode 100644
index 0000000..a8c43bf
--- /dev/null
+++ b/tools/regression/fstest/tests/symlink/10.t
@@ -0,0 +1,37 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="symlink returns EROFS if the file name2 would reside on a read-only file system"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..7"
+
+ n0=`namegen`
+ n1=`namegen`
+ n2=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+
+ expect 0 symlink test ${n0}/${n1}
+ expect 0 unlink ${n0}/${n1}
+ mount -ur /dev/md${n}
+ expect EROFS symlink test ${n0}/${n1}
+ mount -uw /dev/md${n}
+ expect 0 symlink test ${n0}/${n1}
+ expect 0 unlink ${n0}/${n1}
+
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/symlink/11.t b/tools/regression/fstest/tests/symlink/11.t
new file mode 100644
index 0000000..0459851
--- /dev/null
+++ b/tools/regression/fstest/tests/symlink/11.t
@@ -0,0 +1,36 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="symlink returns ENOSPC if there are no free inodes on the file system on which the symbolic link is being created"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..3"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 256k`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ i=0
+ while :; do
+ ln -s test ${n0}/${i} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ break
+ fi
+ i=`expr $i + 1`
+ done
+ expect ENOSPC symlink test ${n0}/${n1}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/symlink/12.t b/tools/regression/fstest/tests/symlink/12.t
new file mode 100644
index 0000000..8606a38
--- /dev/null
+++ b/tools/regression/fstest/tests/symlink/12.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="symlink returns EFAULT if one of the pathnames specified is outside the process's allocated address space"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+
+expect EFAULT symlink NULL ${n0}
+expect EFAULT symlink DEADCODE ${n0}
+expect EFAULT symlink test NULL
+expect EFAULT symlink test DEADCODE
+expect EFAULT symlink NULL DEADCODE
+expect EFAULT symlink DEADCODE NULL
diff --git a/tools/regression/fstest/tests/truncate/00.t b/tools/regression/fstest/tests/truncate/00.t
new file mode 100644
index 0000000..c09f068
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/00.t
@@ -0,0 +1,51 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate descrease/increase file size"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..21"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n1} 0755
+cdir=`pwd`
+cd ${n1}
+
+expect 0 create ${n0} 0644
+expect 0 truncate ${n0} 1234567
+expect 1234567 lstat ${n0} size
+expect 0 truncate ${n0} 567
+expect 567 lstat ${n0} size
+expect 0 unlink ${n0}
+
+dd if=/dev/random of=${n0} bs=12345 count=1 >/dev/null 2>&1
+expect 0 truncate ${n0} 23456
+expect 23456 lstat ${n0} size
+expect 0 truncate ${n0} 1
+expect 1 lstat ${n0} size
+expect 0 unlink ${n0}
+
+# successful truncate(2) updates ctime.
+expect 0 create ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 truncate ${n0} 123
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n0}
+
+# unsuccessful truncate(2) does not update ctime.
+expect 0 create ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect EACCES -u 65534 truncate ${n0} 123
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+
+cd ${cdir}
+expect 0 rmdir ${n1}
diff --git a/tools/regression/fstest/tests/truncate/01.t b/tools/regression/fstest/tests/truncate/01.t
new file mode 100644
index 0000000..ac504a1
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/01.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns ENOTDIR if a component of the path prefix is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..5"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+expect ENOTDIR truncate ${n0}/${n1}/test 123
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/truncate/02.t b/tools/regression/fstest/tests/truncate/02.t
new file mode 100644
index 0000000..e418b96
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/02.t
@@ -0,0 +1,15 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns ENAMETOOLONG if a component of a pathname exceeded 255 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..5"
+
+expect 0 create ${name255} 0644
+expect 0 truncate ${name255} 123
+expect 123 stat ${name255} size
+expect 0 unlink ${name255}
+expect ENAMETOOLONG truncate ${name256} 123
diff --git a/tools/regression/fstest/tests/truncate/03.t b/tools/regression/fstest/tests/truncate/03.t
new file mode 100644
index 0000000..6a4cd64
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/03.t
@@ -0,0 +1,22 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns ENAMETOOLONG if an entire path name exceeded 1023 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+expect 0 mkdir ${name255} 0755
+expect 0 mkdir ${name255}/${name255} 0755
+expect 0 mkdir ${name255}/${name255}/${name255} 0755
+expect 0 mkdir ${path1021} 0755
+expect 0 create ${path1023} 0644
+expect 0 truncate ${path1023} 123
+expect 0 unlink ${path1023}
+expect ENAMETOOLONG truncate ${path1024} 123
+expect 0 rmdir ${path1021}
+expect 0 rmdir ${name255}/${name255}/${name255}
+expect 0 rmdir ${name255}/${name255}
+expect 0 rmdir ${name255}
diff --git a/tools/regression/fstest/tests/truncate/04.t b/tools/regression/fstest/tests/truncate/04.t
new file mode 100644
index 0000000..14f513c
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/04.t
@@ -0,0 +1,17 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns ENOENT if the named file does not exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..4"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect ENOENT truncate ${n0}/${n1}/test 123
+expect ENOENT truncate ${n0}/${n1} 123
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/truncate/05.t b/tools/regression/fstest/tests/truncate/05.t
new file mode 100644
index 0000000..9aa65c8
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/05.t
@@ -0,0 +1,32 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns EACCES when search permission is denied for a component of the path prefix"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..15"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n1}/${n2} 0644
+expect 0 -u 65534 -g 65534 truncate ${n1}/${n2} 123
+expect 123 -u 65534 -g 65534 stat ${n1}/${n2} size
+expect 0 chmod ${n1} 0644
+expect EACCES -u 65534 -g 65534 truncate ${n1}/${n2} 1234
+expect 0 chmod ${n1} 0755
+expect 123 -u 65534 -g 65534 stat ${n1}/${n2} size
+expect 0 -u 65534 -g 65534 truncate ${n1}/${n2} 1234
+expect 1234 -u 65534 -g 65534 stat ${n1}/${n2} size
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/truncate/06.t b/tools/regression/fstest/tests/truncate/06.t
new file mode 100644
index 0000000..8e0ca5b
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/06.t
@@ -0,0 +1,24 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns EACCES if the named file is not writable by the user"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..8"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 create ${n1} 0644
+expect EACCES -u 65534 -g 65534 truncate ${n1} 123
+expect 0 chown ${n1} 65534 65534
+expect 0 chmod ${n1} 0444
+expect EACCES -u 65534 -g 65534 truncate ${n1} 123
+expect 0 unlink ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/truncate/07.t b/tools/regression/fstest/tests/truncate/07.t
new file mode 100644
index 0000000..60b8b90
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/07.t
@@ -0,0 +1,19 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns ELOOP if too many symbolic links were encountered in translating the pathname"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 symlink ${n0} ${n1}
+expect 0 symlink ${n1} ${n0}
+expect ELOOP truncate ${n0}/test 123
+expect ELOOP truncate ${n1}/test 123
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
diff --git a/tools/regression/fstest/tests/truncate/08.t b/tools/regression/fstest/tests/truncate/08.t
new file mode 100644
index 0000000..e4ea0fa
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/08.t
@@ -0,0 +1,59 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns EPERM if the named file has its immutable or append-only flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..40"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM truncate ${n0} 123
+expect 0 stat ${n0} size
+expect 0 chflags ${n0} none
+expect 0 truncate ${n0} 123
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM truncate ${n0} 123
+expect 0 stat ${n0} size
+expect 0 chflags ${n0} none
+expect 0 truncate ${n0} 123
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_APPEND
+expect EPERM truncate ${n0} 123
+expect 0 stat ${n0} size
+expect 0 chflags ${n0} none
+expect 0 truncate ${n0} 123
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_APPEND
+expect EPERM truncate ${n0} 123
+expect 0 stat ${n0} size
+expect 0 chflags ${n0} none
+expect 0 truncate ${n0} 123
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_NOUNLINK
+expect 0 truncate ${n0} 123
+expect 123 stat ${n0} size
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_NOUNLINK
+expect 0 truncate ${n0} 123
+expect 123 stat ${n0} size
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/truncate/09.t b/tools/regression/fstest/tests/truncate/09.t
new file mode 100644
index 0000000..1d95c7f
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/09.t
@@ -0,0 +1,15 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns EISDIR if the named file is a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..3"
+
+n0=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect EISDIR truncate ${n0} 123
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/truncate/10.t b/tools/regression/fstest/tests/truncate/10.t
new file mode 100644
index 0000000..2dc0b45
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/10.t
@@ -0,0 +1,37 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns EROFS if the named file resides on a read-only file system"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..10"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 create ${n0}/${n1} 0644
+ expect 0 truncate ${n0}/${n1} 123
+ expect 123 stat ${n0}/${n1} size
+ mount -ur /dev/md${n}
+ expect EROFS truncate ${n0}/${n1} 1234
+ expect 123 stat ${n0}/${n1} size
+ mount -uw /dev/md${n}
+ expect 0 truncate ${n0}/${n1} 1234
+ expect 1234 stat ${n0}/${n1} size
+ expect 0 unlink ${n0}/${n1}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/truncate/11.t b/tools/regression/fstest/tests/truncate/11.t
new file mode 100644
index 0000000..f86235b
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/11.t
@@ -0,0 +1,23 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns ETXTBSY the file is a pure procedure (shared text) file that is being executed"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}" in
+FreeBSD)
+ echo "1..2"
+
+ n0=`namegen`
+
+ cp -pf `which sleep` ${n0}
+ ./${n0} 3 &
+ expect ETXTBSY truncate ${n0} 123
+ expect 0 unlink ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/truncate/12.t b/tools/regression/fstest/tests/truncate/12.t
new file mode 100644
index 0000000..cf6a497
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/12.t
@@ -0,0 +1,27 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns EFBIG or EINVAL if the length argument was greater than the maximum file size"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..3"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+r=`${fstest} truncate ${n0} 999999999999999 2>/dev/null`
+case "${r}" in
+EFBIG|EINVAL)
+ expect 0 stat ${n0} size
+ ;;
+0)
+ expect 999999999999999 stat ${n0} size
+ ;;
+*)
+ echo "not ok ${ntest}"
+ ntest=`expr ${ntest} + 1`
+ ;;
+esac
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/truncate/13.t b/tools/regression/fstest/tests/truncate/13.t
new file mode 100644
index 0000000..1084c43
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/13.t
@@ -0,0 +1,16 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns EINVAL if the length argument was less than 0"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..4"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+expect EINVAL truncate ${n0} -1
+expect EINVAL truncate ${n0} -999999
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/truncate/14.t b/tools/regression/fstest/tests/truncate/14.t
new file mode 100644
index 0000000..53dca71
--- /dev/null
+++ b/tools/regression/fstest/tests/truncate/14.t
@@ -0,0 +1,12 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="truncate returns EFAULT if the path argument points outside the process's allocated address space"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..2"
+
+expect EFAULT truncate NULL 123
+expect EFAULT truncate DEADCODE 123
diff --git a/tools/regression/fstest/tests/unlink/00.t b/tools/regression/fstest/tests/unlink/00.t
new file mode 100644
index 0000000..af4ccbf
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/00.t
@@ -0,0 +1,115 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink removes regular files, symbolic links, fifos and sockets"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..55"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n2} 0755
+cdir=`pwd`
+cd ${n2}
+
+expect 0 create ${n0} 0644
+expect regular lstat ${n0} type
+expect 0 unlink ${n0}
+expect ENOENT lstat ${n0} type
+
+expect 0 symlink ${n1} ${n0}
+expect symlink lstat ${n0} type
+expect 0 unlink ${n0}
+expect ENOENT lstat ${n0} type
+
+expect 0 mkfifo ${n0} 0644
+expect fifo lstat ${n0} type
+expect 0 unlink ${n0}
+expect ENOENT lstat ${n0} type
+
+# TODO: sockets removal
+
+# successful unlink(2) updates ctime.
+expect 0 create ${n0} 0644
+expect 0 link ${n0} ${n1}
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 unlink ${n1}
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n0}
+
+expect 0 mkfifo ${n0} 0644
+expect 0 link ${n0} ${n1}
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 unlink ${n1}
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -lt $ctime2
+expect 0 unlink ${n0}
+
+# unsuccessful unlink(2) does not update ctime.
+expect 0 create ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect EACCES -u 65534 unlink ${n0}
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+
+expect 0 mkfifo ${n0} 0644
+ctime1=`${fstest} stat ${n0} ctime`
+sleep 1
+expect EACCES -u 65534 unlink ${n0}
+ctime2=`${fstest} stat ${n0} ctime`
+test_check $ctime1 -eq $ctime2
+expect 0 unlink ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+time=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 unlink ${n0}/${n1}
+mtime=`${fstest} stat ${n0} mtime`
+test_check $time -lt $mtime
+ctime=`${fstest} stat ${n0} ctime`
+test_check $time -lt $ctime
+expect 0 rmdir ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect 0 mkfifo ${n0}/${n1} 0644
+time=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 unlink ${n0}/${n1}
+mtime=`${fstest} stat ${n0} mtime`
+test_check $time -lt $mtime
+ctime=`${fstest} stat ${n0} ctime`
+test_check $time -lt $ctime
+expect 0 rmdir ${n0}
+
+expect 0 mkdir ${n0} 0755
+expect 0 symlink test ${n0}/${n1}
+time=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 unlink ${n0}/${n1}
+mtime=`${fstest} stat ${n0} mtime`
+test_check $time -lt $mtime
+ctime=`${fstest} stat ${n0} ctime`
+test_check $time -lt $ctime
+expect 0 rmdir ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 link ${n0} ${n1}
+time=`${fstest} stat ${n0} ctime`
+sleep 1
+expect 0 unlink ${n1}
+ctime=`${fstest} stat ${n0} ctime`
+test_check $time -lt $ctime
+expect 0 unlink ${n0}
+
+cd ${cdir}
+expect 0 rmdir ${n2}
diff --git a/tools/regression/fstest/tests/unlink/01.t b/tools/regression/fstest/tests/unlink/01.t
new file mode 100644
index 0000000..13fa0fe
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/01.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink returns ENOTDIR if a component of the path prefix is not a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..5"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+expect 0 create ${n0}/${n1} 0644
+expect ENOTDIR unlink ${n0}/${n1}/test
+expect 0 unlink ${n0}/${n1}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/unlink/02.t b/tools/regression/fstest/tests/unlink/02.t
new file mode 100644
index 0000000..0d4c579
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/02.t
@@ -0,0 +1,14 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink returns ENAMETOOLONG if a component of a pathname exceeded 255 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..4"
+
+expect 0 create ${name255} 0644
+expect 0 unlink ${name255}
+expect ENOENT unlink ${name255}
+expect ENAMETOOLONG unlink ${name256}
diff --git a/tools/regression/fstest/tests/unlink/03.t b/tools/regression/fstest/tests/unlink/03.t
new file mode 100644
index 0000000..2c62eef
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/03.t
@@ -0,0 +1,22 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink returns ENAMETOOLONG if an entire path name exceeded 1023 characters"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..12"
+
+expect 0 mkdir ${name255} 0755
+expect 0 mkdir ${name255}/${name255} 0755
+expect 0 mkdir ${name255}/${name255}/${name255} 0755
+expect 0 mkdir ${path1021} 0755
+expect 0 create ${path1023} 0644
+expect 0 unlink ${path1023}
+expect ENOENT unlink ${path1023}
+expect ENAMETOOLONG unlink ${path1024}
+expect 0 rmdir ${path1021}
+expect 0 rmdir ${name255}/${name255}/${name255}
+expect 0 rmdir ${name255}/${name255}
+expect 0 rmdir ${name255}
diff --git a/tools/regression/fstest/tests/unlink/04.t b/tools/regression/fstest/tests/unlink/04.t
new file mode 100644
index 0000000..7885f27
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/04.t
@@ -0,0 +1,17 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink returns ENOENT if the named file does not exist"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..4"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 create ${n0} 0644
+expect 0 unlink ${n0}
+expect ENOENT unlink ${n0}
+expect ENOENT unlink ${n1}
diff --git a/tools/regression/fstest/tests/unlink/05.t b/tools/regression/fstest/tests/unlink/05.t
new file mode 100644
index 0000000..c30c353
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/05.t
@@ -0,0 +1,27 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink returns EACCES when search permission is denied for a component of the path prefix"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..10"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n1}/${n2} 0644
+expect 0 chmod ${n1} 0644
+expect EACCES -u 65534 -g 65534 unlink ${n1}/${n2}
+expect 0 chmod ${n1} 0755
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/unlink/06.t b/tools/regression/fstest/tests/unlink/06.t
new file mode 100644
index 0000000..3a64aa2
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/06.t
@@ -0,0 +1,27 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink returns EACCES when write permission is denied on the directory containing the link to be removed"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..10"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n0} 0755
+cdir=`pwd`
+cd ${n0}
+expect 0 mkdir ${n1} 0755
+expect 0 chown ${n1} 65534 65534
+expect 0 -u 65534 -g 65534 create ${n1}/${n2} 0644
+expect 0 chmod ${n1} 0555
+expect EACCES -u 65534 -g 65534 unlink ${n1}/${n2}
+expect 0 chmod ${n1} 0755
+expect 0 -u 65534 -g 65534 unlink ${n1}/${n2}
+expect 0 rmdir ${n1}
+cd ${cdir}
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/unlink/07.t b/tools/regression/fstest/tests/unlink/07.t
new file mode 100644
index 0000000..ea9d2a3
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/07.t
@@ -0,0 +1,19 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink returns ELOOP if too many symbolic links were encountered in translating the pathname"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..6"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 symlink ${n0} ${n1}
+expect 0 symlink ${n1} ${n0}
+expect ELOOP unlink ${n0}/test
+expect ELOOP unlink ${n1}/test
+expect 0 unlink ${n0}
+expect 0 unlink ${n1}
diff --git a/tools/regression/fstest/tests/unlink/08.t b/tools/regression/fstest/tests/unlink/08.t
new file mode 100644
index 0000000..5b0f03b
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/08.t
@@ -0,0 +1,23 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink returns EPERM if the named file is a directory"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..3"
+
+n0=`namegen`
+
+expect 0 mkdir ${n0} 0755
+case "${os}:${fs}" in
+SunOS:UFS)
+ expect 0 unlink ${n0}
+ expect ENOENT rmdir ${n0}
+ ;;
+*)
+ expect EPERM unlink ${n0}
+ expect 0 rmdir ${n0}
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/unlink/09.t b/tools/regression/fstest/tests/unlink/09.t
new file mode 100644
index 0000000..c069b0d
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/09.t
@@ -0,0 +1,49 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink returns EPERM if the named file has its immutable, undeletable or append-only flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..30"
+
+n0=`namegen`
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM unlink ${n0}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM unlink ${n0}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_NOUNLINK
+expect EPERM unlink ${n0}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_NOUNLINK
+expect EPERM unlink ${n0}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} SF_APPEND
+expect EPERM unlink ${n0}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
+
+expect 0 create ${n0} 0644
+expect 0 chflags ${n0} UF_APPEND
+expect EPERM unlink ${n0}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}
diff --git a/tools/regression/fstest/tests/unlink/10.t b/tools/regression/fstest/tests/unlink/10.t
new file mode 100644
index 0000000..cf4188a
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/10.t
@@ -0,0 +1,52 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink returns EPERM if the parent directory of the named file has its immutable or append-only flag set"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+require chflags
+
+echo "1..30"
+
+n0=`namegen`
+n1=`namegen`
+
+expect 0 mkdir ${n0} 0755
+
+expect 0 create ${n0}/${n1} 0644
+expect 0 chflags ${n0} SF_IMMUTABLE
+expect EPERM unlink ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 create ${n0}/${n1} 0644
+expect 0 chflags ${n0} UF_IMMUTABLE
+expect EPERM unlink ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 create ${n0}/${n1} 0644
+expect 0 chflags ${n0} SF_APPEND
+expect EPERM unlink ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 create ${n0}/${n1} 0644
+expect 0 chflags ${n0} UF_APPEND
+expect EPERM unlink ${n0}/${n1}
+expect 0 chflags ${n0} none
+expect 0 unlink ${n0}/${n1}
+
+expect 0 create ${n0}/${n1} 0644
+expect 0 chflags ${n0} SF_NOUNLINK
+expect 0 unlink ${n0}/${n1}
+expect 0 chflags ${n0} none
+
+expect 0 create ${n0}/${n1} 0644
+expect 0 chflags ${n0} UF_NOUNLINK
+expect 0 unlink ${n0}/${n1}
+expect 0 chflags ${n0} none
+
+expect 0 rmdir ${n0}
diff --git a/tools/regression/fstest/tests/unlink/11.t b/tools/regression/fstest/tests/unlink/11.t
new file mode 100644
index 0000000..68084ec
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/11.t
@@ -0,0 +1,68 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink returns EACCES or EPERM if the directory containing the file is marked sticky, and neither the containing directory nor the file to be removed are owned by the effective user ID"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..33"
+
+n0=`namegen`
+n1=`namegen`
+n2=`namegen`
+
+expect 0 mkdir ${n2} 0755
+cdir=`pwd`
+cd ${n2}
+
+expect 0 mkdir ${n0} 0755
+expect 0 chown ${n0} 65534 65534
+expect 0 chmod ${n0} 01777
+
+# User owns both: the sticky directory and the file to be removed.
+expect 0 -u 65534 -g 65534 create ${n0}/${n1} 0644
+expect 0 -u 65534 -g 65534 unlink ${n0}/${n1}
+# User owns the file to be removed, but doesn't own the sticky directory.
+expect 0 -u 65533 -g 65533 create ${n0}/${n1} 0644
+expect 0 -u 65533 -g 65533 unlink ${n0}/${n1}
+# User owns the sticky directory, but doesn't own the file to be removed.
+expect 0 -u 65533 -g 65533 create ${n0}/${n1} 0644
+expect 0 -u 65534 -g 65534 unlink ${n0}/${n1}
+# User doesn't own the sticky directory nor the file to be removed.
+expect 0 -u 65534 -g 65534 create ${n0}/${n1} 0644
+expect "EACCES|EPERM" -u 65533 -g 65533 unlink ${n0}/${n1}
+expect 0 unlink ${n0}/${n1}
+
+# User owns both: the sticky directory and the fifo to be removed.
+expect 0 -u 65534 -g 65534 mkfifo ${n0}/${n1} 0644
+expect 0 -u 65534 -g 65534 unlink ${n0}/${n1}
+# User owns the fifo to be removed, but doesn't own the sticky directory.
+expect 0 -u 65533 -g 65533 mkfifo ${n0}/${n1} 0644
+expect 0 -u 65533 -g 65533 unlink ${n0}/${n1}
+# User owns the sticky directory, but doesn't own the fifo to be removed.
+expect 0 -u 65533 -g 65533 mkfifo ${n0}/${n1} 0644
+expect 0 -u 65534 -g 65534 unlink ${n0}/${n1}
+# User doesn't own the sticky directory nor the fifo to be removed.
+expect 0 -u 65534 -g 65534 mkfifo ${n0}/${n1} 0644
+expect "EACCES|EPERM" -u 65533 -g 65533 unlink ${n0}/${n1}
+expect 0 unlink ${n0}/${n1}
+
+# User owns both: the sticky directory and the symlink to be removed.
+expect 0 -u 65534 -g 65534 symlink test ${n0}/${n1}
+expect 0 -u 65534 -g 65534 unlink ${n0}/${n1}
+# User owns the symlink to be removed, but doesn't own the sticky directory.
+expect 0 -u 65533 -g 65533 symlink test ${n0}/${n1}
+expect 0 -u 65533 -g 65533 unlink ${n0}/${n1}
+# User owns the sticky directory, but doesn't own the symlink to be removed.
+expect 0 -u 65533 -g 65533 symlink test ${n0}/${n1}
+expect 0 -u 65534 -g 65534 unlink ${n0}/${n1}
+# User doesn't own the sticky directory nor the symlink to be removed.
+expect 0 -u 65534 -g 65534 symlink test ${n0}/${n1}
+expect "EACCES|EPERM" -u 65533 -g 65533 unlink ${n0}/${n1}
+expect 0 unlink ${n0}/${n1}
+
+expect 0 rmdir ${n0}
+
+cd ${cdir}
+expect 0 rmdir ${n2}
diff --git a/tools/regression/fstest/tests/unlink/12.t b/tools/regression/fstest/tests/unlink/12.t
new file mode 100644
index 0000000..65a3aaf
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/12.t
@@ -0,0 +1,32 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink returns EROFS if the named file resides on a read-only file system"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+case "${os}:${fs}" in
+FreeBSD:UFS)
+ echo "1..5"
+
+ n0=`namegen`
+ n1=`namegen`
+
+ expect 0 mkdir ${n0} 0755
+ n=`mdconfig -a -n -t malloc -s 1m`
+ newfs /dev/md${n} >/dev/null
+ mount /dev/md${n} ${n0}
+ expect 0 create ${n0}/${n1} 0644
+ mount -ur /dev/md${n}
+ expect EROFS unlink ${n0}/${n1}
+ mount -uw /dev/md${n}
+ expect 0 unlink ${n0}/${n1}
+ umount /dev/md${n}
+ mdconfig -d -u ${n}
+ expect 0 rmdir ${n0}
+ ;;
+*)
+ quick_exit
+ ;;
+esac
diff --git a/tools/regression/fstest/tests/unlink/13.t b/tools/regression/fstest/tests/unlink/13.t
new file mode 100644
index 0000000..da5e718
--- /dev/null
+++ b/tools/regression/fstest/tests/unlink/13.t
@@ -0,0 +1,12 @@
+#!/bin/sh
+# $FreeBSD$
+
+desc="unlink returns EFAULT if the path argument points outside the process's allocated address space"
+
+dir=`dirname $0`
+. ${dir}/../misc.sh
+
+echo "1..2"
+
+expect EFAULT unlink NULL
+expect EFAULT unlink DEADCODE
OpenPOWER on IntegriCloud