Index: trunk/libc/tests/libc/Makefile
===================================================================
--- trunk/libc/tests/libc/Makefile	(revision 3812)
+++ trunk/libc/tests/libc/Makefile	(revision 3813)
@@ -155,4 +155,5 @@
 	io/open-1.c \
 	io/open-2.c \
+	io/chown-1.c \
 	io/sprintf-1.c \
 	io/sscanf-1.c \
Index: trunk/libc/tests/libc/io/chown-1.c
===================================================================
--- trunk/libc/tests/libc/io/chown-1.c	(revision 3813)
+++ trunk/libc/tests/libc/io/chown-1.c	(revision 3813)
@@ -0,0 +1,196 @@
+/* $Id$ */
+/** @file
+ * Testcase chown-1, tests simple owner ship changes using chown, lchown and fchown.
+ */
+
+/*
+ *
+ * Copyright (c) 2006-2014 knut st. osmundsen <bird@innotek.de>
+ *
+ *
+ * This file is part of kLIBC.
+ *
+ * kLIBC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kLIBC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kLIBC; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#define XSTR_SUB(a_Expr)    #a_Expr
+#define XSTR(a_Expr)        XSTR_SUB(a_Expr)
+
+#define TEST_CHANGE(a_OperationExpr, a_uidExpect, a_gidExpect) \
+    do { \
+        int rc = a_OperationExpr; \
+        if (rc != 0) \
+        { \
+            g_cErrors++; \
+            int err = errno; \
+            fprintf(stderr, "chown-1: errno=%d (%s) at line " XSTR(__LINE__) " doing: " #a_OperationExpr "\n", \
+                    err, strerror(err)); \
+        } \
+        else \
+            assertOwners(fd, szTmp, a_uidExpect, a_gidExpect, #a_OperationExpr " at line " XSTR(__LINE__)); \
+    } while (0)
+
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+static int g_cErrors = 0;
+
+
+static int assertOwners(int fd, const char *pszFilename, uid_t uidExpect, gid_t gidExpect, const char *pszClue)
+{
+    int rc;
+    struct stat st;
+    if (fd != -1)
+        rc = fstat(fd, &st);
+    else
+        rc = lstat(pszFilename, &st);
+    if (rc)
+    {
+        g_cErrors++;
+        int err = errno;
+        fprintf(stderr, "chown-1: failed to stat the file%s (fd=%d,%s): errno=%d (%s)\n",
+                pszClue, fd, pszFilename, err, strerror(err));
+        rc = 1;
+    }
+    else
+    {
+
+        if (st.st_uid != uidExpect)
+        {
+            g_cErrors++;
+            rc++;
+            fprintf(stderr, "chown-1: st_uid mismatch%s (fd=%d,%s): expected=%u, found %u\n",
+                    pszClue, fd, pszFilename, uidExpect, st.st_uid);
+        }
+
+        if (st.st_gid != gidExpect)
+        {
+            g_cErrors++;
+            rc++;
+            fprintf(stderr, "chown-1: st_gid mismatch%s (fd=%d,%s): expected=%u, found %u\n",
+                    pszClue, fd, pszFilename, gidExpect, st.st_gid);
+        }
+    }
+    return rc;
+}
+
+int main()
+{
+
+    /*
+     * Get a non-existing temp filename we can play around with.
+     */
+    char szTmp[L_tmpnam];
+    int fd;
+    for (;;)
+    {
+        if (!tmpnam(szTmp))
+            return !!printf("chown-1: FAILURE - tmpnam failed!\n");
+        fd = open(szTmp, O_RDWR | O_CREAT | O_EXCL, 0666);
+        if (fd >= 0)
+            break;
+
+        int err = errno;
+        struct stat st;
+        if (    fd < 0
+            &&  stat(szTmp, &st))
+            return !!printf("chown-1: FAILURE - open O_EXCL failed. file='%s' errno=%d %s\n",
+                            szTmp, err, strerror(err));
+        /* racing someone, retry. */
+    }
+
+    /*
+     * Get the current ownership.
+     */
+    struct stat st1;
+    if (fstat(fd, &st1) != 0)
+    {
+        g_cErrors++;
+        int err = errno;
+        printf("chown-1: FAILURE - fstat failed - errno=%d (%s)\n", err, strerror(err));
+        memset(&st1, 0, sizeof(st1));
+    }
+
+    /*
+     * No change.
+     */
+    TEST_CHANGE(fchown(fd, st1.st_uid, st1.st_gid), st1.st_uid, st1.st_gid);
+    TEST_CHANGE(chown(szTmp, st1.st_uid, st1.st_gid), st1.st_uid, st1.st_gid);
+    TEST_CHANGE(lchown(szTmp, st1.st_uid, st1.st_gid), st1.st_uid, st1.st_gid);
+
+    TEST_CHANGE(fchown(fd, -1, -1), st1.st_uid, st1.st_gid);
+    TEST_CHANGE(chown(szTmp, -1, -1), st1.st_uid, st1.st_gid);
+    TEST_CHANGE(lchown(szTmp, -1, -1), st1.st_uid, st1.st_gid);
+
+    TEST_CHANGE(fchown(fd, st1.st_uid, -1), st1.st_uid, st1.st_gid);
+    TEST_CHANGE(chown(szTmp, -1, st1.st_gid), st1.st_uid, st1.st_gid);
+    TEST_CHANGE(lchown(szTmp, -1, st1.st_gid), st1.st_uid, st1.st_gid);
+
+    /*
+     * If we're super user we change change the file ownership without
+     * restriction, otherwise we cannot.  Restrictions are also affected on group
+     * changes.
+     *
+     * However, on OS/2 we don't check these things right now, so the below always works fine.
+     */
+    TEST_CHANGE(fchown(fd,    st1.st_uid + 1, st1.st_gid + 1), st1.st_uid + 1, st1.st_gid + 1);
+    TEST_CHANGE(lchown(szTmp, st1.st_uid + 1, st1.st_gid + 1), st1.st_uid + 1, st1.st_gid + 1);
+    TEST_CHANGE(chown(szTmp,  st1.st_uid + 1, st1.st_gid + 1), st1.st_uid + 1, st1.st_gid + 1);
+
+    TEST_CHANGE(fchown(fd,    st1.st_uid + 2, -1), st1.st_uid + 2, st1.st_gid + 1);
+    TEST_CHANGE(lchown(szTmp, st1.st_uid + 2, -1), st1.st_uid + 2, st1.st_gid + 1);
+    TEST_CHANGE(chown(szTmp,  st1.st_uid + 2, -1), st1.st_uid + 2, st1.st_gid + 1);
+
+    TEST_CHANGE(fchown(fd,    -1, st1.st_gid + 3), st1.st_uid + 2, st1.st_gid + 3);
+    TEST_CHANGE(lchown(szTmp, -1, st1.st_gid + 3), st1.st_uid + 2, st1.st_gid + 3);
+    TEST_CHANGE(chown(szTmp,  -1, st1.st_gid + 3), st1.st_uid + 2, st1.st_gid + 3);
+
+    /*
+     * Cleanup.
+     */
+    if (unlink(szTmp))
+    {
+        g_cErrors++;
+        int err = errno;
+        printf("chown-1: FAILURE - unlink(%s) failed! errno=%d (%s)\n", szTmp, err, strerror(err));
+    }
+
+    /*
+     * Summary.
+     */
+    if (!g_cErrors)
+        printf("chown-1: SUCCESS\n");
+    else
+        printf("chown-1: FAILURE - %d errors\n", g_cErrors);
+    return !!g_cErrors;
+}
