Index: /trunk/libc/include/klibc/backend.h
===================================================================
--- /trunk/libc/include/klibc/backend.h	(revision 3815)
+++ /trunk/libc/include/klibc/backend.h	(revision 3816)
@@ -1,8 +1,9 @@
 /* $Id$ */
 /** @file
- *
  * kLIBC - Backend header.
- *
- * Copyright (c) 2004-2006 knut st. osmundsen <bird-srcspam@anduin.net>
+ */
+
+/*
+ * Copyright (c) 2004-2014 knut st. osmundsen <bird-srcspam@anduin.net>
  *
  *
@@ -163,5 +164,5 @@
 
 
-/** @defgroup __libc_Back_fs   kLIBC Backend - File Handle
+/** @defgroup __libc_Back_fh   kLIBC Backend - File Handle
  * @{ */
 
@@ -412,4 +413,16 @@
 
 /**
+ * Changes the ownership and/or group, without following any final symlink.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   pszPath     Path to the file to modify ownership of.  If this is a
+ *                      symbolic link, the link it self will modified.
+ * @param   uid         The user id of the new owner, pass -1 to not change it.
+ * @param   gid         The group id of the new group, pass -1 to not change it.
+ */
+int __libc_Back_fsSymlinkOwnerSet(const char *pszPath, uid_t uid, gid_t gid);
+
+/**
  * Stats a file.
  *
@@ -472,4 +485,26 @@
  */
 int __libc_Back_fsFileTimesSetFH(int fh, const struct timeval *paTimes);
+
+/**
+ * Changes the ownership and/or group, following all symbolic links.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   pszPath     Path to the file to modify ownership of.
+ * @param   uid         The user id of the new owner, pass -1 to not change it.
+ * @param   gid         The group id of the new group, pass -1 to not change it.
+ */
+int __libc_Back_fsFileOwnerSet(const char *pszPath, uid_t uid, gid_t gid);
+
+/**
+ * Changes the ownership and/or group.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   fh          Handle to file.
+ * @param   uid         The user id of the new owner, pass -1 to not change it.
+ * @param   gid         The group id of the new group, pass -1 to not change it.
+ */
+int __libc_Back_fsFileOwnerSetFH(int fh, uid_t uid, gid_t gid);
 
 /**
Index: /trunk/libc/include/klibc/io.h
===================================================================
--- /trunk/libc/include/klibc/io.h	(revision 3815)
+++ /trunk/libc/include/klibc/io.h	(revision 3816)
@@ -1,8 +1,9 @@
 /* $Id: $ */
 /** @file
- *
  * kLIBC I/O
- *
- * Copyright (c) 2006 knut st. osmundsen <bird@innotek.de>
+ */
+
+/*
+ * Copyright (c) 2006-2014 knut st. osmundsen <bird-src-spam@anduin.net>
  *
  *
@@ -242,7 +243,8 @@
      * @returns Negated error code (errno.h) on failure.
      * @param   pFH         Pointer to the handle structure to operate on.
-     * @param   uid         The id of the new owner.
-     */
-    int (*pfnSetOwner)(struct __libc_FileHandle *pFH, uid_t uid);
+     * @param   uid         The id of the new owner, -1 if not to be changed.
+     * @param   gid         The id of the new owner group, if no change,
+     */
+    int (*pfnSetOwner)(struct __libc_FileHandle *pFH, uid_t uid, gid_t gid);
 
     /**
Index: /trunk/libc/src/kNIX/Makefile.kmk
===================================================================
--- /trunk/libc/src/kNIX/Makefile.kmk	(revision 3815)
+++ /trunk/libc/src/kNIX/Makefile.kmk	(revision 3816)
@@ -1,8 +1,9 @@
 # $Id$
 ## @file
-#
 # kBuild Sub-Makefile for kLIBC - src/libc/sys.
 #
-# Copyright (c) 2006 knut st. osmundsen <bird-src-spam@anduin.net>
+
+#
+# Copyright (c) 2006-2014 knut st. osmundsen <bird-src-spam@anduin.net>
 #
 #
@@ -41,4 +42,5 @@
     $(PATH_LIBC_SRC)/kNIX/b_fsPathResolve.c \
     $(PATH_LIBC_SRC)/kNIX/b_fsSymlinkModeSet.c \
+    $(PATH_LIBC_SRC)/kNIX/b_fsSymlinkOwnerSet.c \
     $(PATH_LIBC_SRC)/kNIX/b_fsSymlinkCreate.c \
     $(PATH_LIBC_SRC)/kNIX/b_fsFileTimesSet.c \
@@ -47,4 +49,6 @@
     $(PATH_LIBC_SRC)/kNIX/b_fsFileModeSet.c \
     $(PATH_LIBC_SRC)/kNIX/b_fsFileModeSetFH.c \
+    $(PATH_LIBC_SRC)/kNIX/b_fsFileOwnerSet.c \
+    $(PATH_LIBC_SRC)/kNIX/b_fsFileOwnerSetFH.c \
     $(PATH_LIBC_SRC)/kNIX/b_fsFileStat.c \
     $(PATH_LIBC_SRC)/kNIX/b_fsFileStatFH.c \
@@ -98,4 +102,5 @@
     $(PATH_LIBC_SRC)/kNIX/os2/b_fsDriveDefaultSet.c \
     $(PATH_LIBC_SRC)/kNIX/os2/b_fsNativeFileModeSet.c \
+    $(PATH_LIBC_SRC)/kNIX/os2/b_fsNativeFileOwnerSet.c \
     $(PATH_LIBC_SRC)/kNIX/os2/b_fsNativeFileStat.c \
     $(PATH_LIBC_SRC)/kNIX/os2/b_fsNativeFileTimesSet.c \
Index: /trunk/libc/src/kNIX/b_fsFileOwnerSet.c
===================================================================
--- /trunk/libc/src/kNIX/b_fsFileOwnerSet.c	(revision 3816)
+++ /trunk/libc/src/kNIX/b_fsFileOwnerSet.c	(revision 3816)
@@ -0,0 +1,59 @@
+/* $Id$ */
+/** @file
+ * kNIX - chown.
+ */
+
+/*
+ * Copyright (c) 2004-2014 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ *
+ * 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
+ *
+ */
+
+#include "kNIX.h"
+#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_BACK_FS
+#include <klibc/logstrict.h>
+
+/**
+ * Changes the ownership and/or group, without following any final symlink.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   pszPath     Path to the file to modify ownership of.  If this is a
+ *                      symbolic link, the link it self will modified.
+ * @param   uid         The user id of the new owner, pass -1 to not change it.
+ * @param   gid         The group id of the new group, pass -1 to not change it.
+ */
+int __libc_Back_fsFileOwnerSet(const char *pszPath, uid_t uid, gid_t gid)
+{
+    LIBCLOG_ENTER("pszPath=%p:{%s} %ld %ld\n", (void *)pszPath, pszPath, (long)uid, (long)gid);
+
+    /*
+     * Resolve the path.
+     */
+    char szNativePath[PATH_MAX];
+    int rc = __libc_back_fsResolve(pszPath, BACKFS_FLAGS_RESOLVE_FULL | BACKFS_FLAGS_RESOLVE_DIR_MAYBE,
+                                   szNativePath, NULL);
+    if (!rc)
+        rc = __libc_back_fsNativeFileOwnerSet(szNativePath, uid, gid);
+
+    if (!rc)
+        LIBCLOG_RETURN_INT(rc);
+    LIBCLOG_ERROR_RETURN_INT(rc);
+}
+
Index: /trunk/libc/src/kNIX/b_fsFileOwnerSetFH.c
===================================================================
--- /trunk/libc/src/kNIX/b_fsFileOwnerSetFH.c	(revision 3816)
+++ /trunk/libc/src/kNIX/b_fsFileOwnerSetFH.c	(revision 3816)
@@ -0,0 +1,64 @@
+/* $Id$ */
+/** @file
+ * kNIX - fchown().
+ */
+
+/*
+ * Copyright (c) 2005-2014 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ *
+ * 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
+ *
+ */
+
+#include "kNIX.h"
+#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_BACK_FS
+#include <klibc/logstrict.h>
+
+
+/**
+ * Sets the file ownership of a file by filehandle.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   fh          Handle to file.
+ * @param   uid         The user id of the new owner, pass -1 to not change it.
+ * @param   gid         The group id of the new group, pass -1 to not change it.
+ */
+int __libc_Back_fsFileOwnerSetFH(int fh, uid_t uid, gid_t gid)
+{
+    LIBCLOG_ENTER("fh=%d uid=%ld gid=%ld\n", fh, (long)uid, (long)gid);
+
+    /*
+     * Get filehandle.
+     */
+    __LIBC_PFH pFH;
+    int rc = __libc_FHGet(fh, &pFH);
+    if (!rc)
+    {
+        /*
+         * If supported, do handle operation, otherwise predend it's a pipe (see SuS).
+         */
+        if (pFH->pOps->pfnSetOwner)
+            rc = pFH->pOps->pfnSetOwner(pFH, uid, gid);
+        else
+            rc = EINVAL;
+        __libc_FHPut(pFH);
+    }
+    LIBCLOG_MIX_RETURN_INT(rc);
+}
+
Index: /trunk/libc/src/kNIX/b_fsSymlinkOwnerSet.c
===================================================================
--- /trunk/libc/src/kNIX/b_fsSymlinkOwnerSet.c	(revision 3816)
+++ /trunk/libc/src/kNIX/b_fsSymlinkOwnerSet.c	(revision 3816)
@@ -0,0 +1,59 @@
+/* $Id$ */
+/** @file
+ * kNIX - lchown.
+ */
+
+/*
+ * Copyright (c) 2004-2014 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ *
+ * 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
+ *
+ */
+
+#include "kNIX.h"
+#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_BACK_FS
+#include <klibc/logstrict.h>
+
+/**
+ * Changes the ownership and/or group, without following any final symlink.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   pszPath     Path to the file to modify ownership of.  If this is a
+ *                      symbolic link, the link it self will modified.
+ * @param   uid         The user id of the new owner, pass -1 to not change it.
+ * @param   gid         The group id of the new group, pass -1 to not change it.
+ */
+int __libc_Back_fsSymlinkOwnerSet(const char *pszPath, uid_t uid, gid_t gid)
+{
+    LIBCLOG_ENTER("pszPath=%p:{%s} %ld %ld\n", (void *)pszPath, pszPath, (long)uid, (long)gid);
+
+    /*
+     * Resolve the path.
+     */
+    char szNativePath[PATH_MAX];
+    int rc = __libc_back_fsResolve(pszPath, BACKFS_FLAGS_RESOLVE_FULL_SYMLINK | BACKFS_FLAGS_RESOLVE_DIR_MAYBE,
+                                   szNativePath, NULL);
+    if (!rc)
+        rc = __libc_back_fsNativeFileOwnerSet(szNativePath, uid, gid);
+
+    if (!rc)
+        LIBCLOG_RETURN_INT(rc);
+    LIBCLOG_ERROR_RETURN_INT(rc);
+}
+
Index: /trunk/libc/src/kNIX/kNIX.h
===================================================================
--- /trunk/libc/src/kNIX/kNIX.h	(revision 3815)
+++ /trunk/libc/src/kNIX/kNIX.h	(revision 3816)
@@ -1,8 +1,9 @@
 /* $Id$ */
 /** @file
- *
  * kNIX - Main header.
- *
- * Copyright (c) 2006 knut st. osmundsen <bird-src-spam@anduin.net>
+ */
+
+/*
+ * Copyright (c) 2006-2014 knut st. osmundsen <bird-src-spam@anduin.net>
  *
  *
@@ -232,4 +233,7 @@
 int __libc_back_fsNativeFileModeSet(const char *pszNativePath, mode_t Mode);
 int __libc_back_fsNativeFileTimesSet(const char *pszNativePath, const struct timeval *paTimes);
+int __libc_back_fsNativeFileOwnerSet(const char *pszNativePath, uid_t uid, gid_t gid);
+int __libc_back_fsNativeFileOwnerSetCommon(intptr_t hNative, const char *pszNativePath, int fUnixEAs, uid_t uid, gid_t gid);
+int __libc_back_fsNativeSetEAs(intptr_t hNative, const char *pszNativePath, PFEA2LIST pEAs, PEAOP2 pEaOp2);
 dev_t __libc_back_fsPathCalcInodeAndDev(const char *pszNativePath, ino_t *pInode);
 __LIBC_PFSINFO __libc_back_fsInfoObjByDev(dev_t Dev);
Index: /trunk/libc/src/kNIX/os2/b_fsNativeFileModeSet.c
===================================================================
--- /trunk/libc/src/kNIX/os2/b_fsNativeFileModeSet.c	(revision 3815)
+++ /trunk/libc/src/kNIX/os2/b_fsNativeFileModeSet.c	(revision 3816)
@@ -1,8 +1,9 @@
 /* $Id$ */
 /** @file
- *
  * kNIX - internal [l]chmod, OS/2.
- *
- * Copyright (c) 2005-2006 knut st. osmundsen <bird-src-spam@anduin.net>
+ */
+
+/*
+ * Copyright (c) 2005-2014 knut st. osmundsen <bird-src-spam@anduin.net>
  *
  *
@@ -180,8 +181,4 @@
             };
             #pragma pack()
-            EAOP2 EaOp2;
-            EaOp2.fpGEA2List = NULL;
-            EaOp2.fpFEA2List = (PFEA2LIST)&EAs;
-            EaOp2.oError = 0;
 
             if (!S_ISREG(Mode) && !S_ISDIR(Mode))
@@ -189,10 +186,11 @@
 
             /* finally, try update / add the EA. */
-            rc = DosSetPathInfo((PCSZ)pszNativePath, FIL_QUERYEASIZE, &EaOp2, sizeof(EaOp2), 0);
+            EAOP2 EaOp2;
+            rc = __libc_back_fsNativeSetEAs(-1, pszNativePath, (PFEA2LIST)&EAs, &EaOp2);
             if (__predict_false(rc != NO_ERROR))
             {
-                LIBCLOG_ERROR("DosSetPathInfo('%s',,,,) -> %d, oError=%#lx\n", pszNativePath, rc, EaOp2.oError);
+                LIBCLOG_ERROR("__libc_back_fsNativeSetEAs('%s',,,,) -> %d, oError=%#lx\n", pszNativePath, rc, EaOp2.oError);
                 if (rc == ERROR_EAS_NOT_SUPPORTED)
-                    rc = 0;
+                    rc = NO_ERROR;
                 else
                     rc = -__libc_back_native2errno(rc);
Index: /trunk/libc/src/kNIX/os2/b_fsNativeFileOwnerSet.c
===================================================================
--- /trunk/libc/src/kNIX/os2/b_fsNativeFileOwnerSet.c	(revision 3816)
+++ /trunk/libc/src/kNIX/os2/b_fsNativeFileOwnerSet.c	(revision 3816)
@@ -0,0 +1,196 @@
+/* $Id$ */
+/** @file
+ * kNIX - internal [l]chown, OS/2.
+ */
+
+/*
+ * Copyright (c) 2005-2014 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ *
+ * 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
+ *
+ */
+
+#include "kNIX.h"
+#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_BACK_FS
+#include <klibc/logstrict.h>
+
+
+/**
+ * Sets the file ownership of a native file.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   hNative         Native handle, -1 if only the path is available.
+ * @param   pszNativePath   The native path.
+ * @param   uid             The user id of the new owner, pass -1 to not change it.
+ * @param   gid             The group id of the new group, pass -1 to not change it.
+ */
+int __libc_back_fsNativeFileOwnerSetCommon(intptr_t hNative, const char *pszNativePath, int fUnixEAs, uid_t uid, gid_t gid)
+{
+    FS_VAR_SAVE_LOAD();
+    int rc;
+    if (fUnixEAs)
+    {
+        struct stat StOrg;
+        memset(&StOrg, 0, sizeof(StOrg));
+        rc = __libc_back_fsUnixAttribsGet(hNative, pszNativePath, &StOrg);
+        if (__predict_true(!rc || rc == -ENOTSUP))
+        {
+            /** @todo check for permissions to change file ownership. */
+            if (uid != (uid_t)-1 || gid != (gid_t)-1)
+            {
+                /* construct FEA2 stuff. */
+                #pragma pack(1)
+                struct __LIBC_FSUNIXATTRIBSSETOWNER
+                {
+                    ULONG   cbList;
+
+                    ULONG   offUid;
+                    BYTE    fUidEA;
+                    BYTE    cbUidName;
+                    USHORT  cbUidValue;
+                    CHAR    szUidName[sizeof(EA_UID)];
+                    USHORT  usUidType;
+                    USHORT  cbUidData;
+                    uint32_t u32Uid;
+                    CHAR    achUidAlign[((sizeof(EA_UID) + 4) & ~3) - sizeof(EA_UID)];
+
+                    ULONG   offGid;
+                    BYTE    fGidEA;
+                    BYTE    cbGidName;
+                    USHORT  usGidValue;
+                    CHAR    szGidName[sizeof(EA_GID)];
+                    USHORT  usGidType;
+                    USHORT  cbGidData;
+                    uint32_t u32Gid;
+                    CHAR    achGidAlign[((sizeof(EA_GID) + 4) & ~3) - sizeof(EA_GID)];
+                } EAs =
+                {
+                    sizeof(EAs),
+
+                    /* .offUid      =*/ offsetof(struct __LIBC_FSUNIXATTRIBSSETOWNER, offGid)
+                                      - offsetof(struct __LIBC_FSUNIXATTRIBSSETOWNER, offUid),
+                    /* .fUidEA      =*/ 0,
+                    /* .cbUidName   =*/ sizeof(EA_UID) - 1,
+                    /* .cbUidValue  =*/ sizeof(uint32_t) + 4,
+                    /* .szUidName   =*/ EA_UID,
+                    /* .usUidType   =*/ EAT_BINARY,
+                    /* .cbUidData   =*/ sizeof(uint32_t),
+                    /* .u32Uid      =*/ uid != (uid_t)-1 ? uid : StOrg.st_uid,
+                    /* .achUidAlign =*/ "",
+
+                    /* .offGid      =*/ 0,
+                    /* .fGidEA      =*/ 0,
+                    /* .cbGidName   =*/ sizeof(EA_GID) - 1,
+                    /* .cbGidValue  =*/ sizeof(uint32_t) + 4,
+                    /* .szGidName   =*/ EA_GID,
+                    /* .usGidType   =*/ EAT_BINARY,
+                    /* .cbGidData   =*/ sizeof(uint32_t),
+                    /* .u32Gid      =*/ gid != (gid_t)-1 ? gid : StOrg.st_gid,
+                    /* .achGidAlign =*/ "",
+                };
+                #pragma pack()
+
+                if (uid != -1 && uid != 0)
+                    EAs.fUidEA = FEA_NEEDEA;
+                if (gid != -1 && gid != 0)
+                    EAs.fGidEA = FEA_NEEDEA;
+
+                EAOP2 EaOp2;
+                rc = __libc_back_fsNativeSetEAs(hNative, pszNativePath, (PFEA2LIST)&EAs, &EaOp2);
+                if (__predict_false(rc != NO_ERROR))
+                {
+                    LIBCLOG_ERROR2("__libc_back_fsNativeSetEAs('%s',,,,) -> %d, oError=%#lx\n", pszNativePath, rc, EaOp2.oError);
+                    if (   rc == ERROR_EAS_NOT_SUPPORTED
+                        && (uid == -1 || uid == 0)
+                        && (gid == -1 || gid == 0) )
+                        rc = 0;
+                    else
+                        rc = -__libc_back_native2errno(rc);
+                }
+            }
+            else
+                rc = 0; /* No change and thus no not-supported complaints. */
+        }
+    }
+    else
+    {
+        /*
+         * In this mode we'll simply check if the file exists and return the
+         * appropriate errors if it doesn't or we cannot access it.
+         */
+        union
+        {
+            FILESTATUS4     fsts4;
+            FILESTATUS4L    fsts4L;
+        } info;
+
+#if OFF_MAX > LONG_MAX
+        if (__libc_gpfnDosOpenL)
+            rc = DosQueryPathInfo((PCSZ)pszNativePath, FIL_STANDARDL, &info, sizeof(info.fsts4L) - sizeof(info.fsts4L.cbList));
+        else
+#endif
+            rc = DosQueryPathInfo((PCSZ)pszNativePath, FIL_STANDARD, &info, sizeof(info.fsts4) - sizeof(info.fsts4.cbList));
+
+        if (rc != NO_ERROR)
+            rc = -__libc_back_native2errno(rc);
+    }
+    FS_RESTORE();
+    return rc;
+}
+
+
+/**
+ * Sets the file ownership of a native file.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   pszNativePath   The native path.
+ * @param   uid             The user id of the new owner, pass -1 to not change it.
+ * @param   gid             The group id of the new group, pass -1 to not change it.
+ */
+int __libc_back_fsNativeFileOwnerSet(const char *pszNativePath, uid_t uid, gid_t gid)
+{
+    LIBCLOG_ENTER("pszNativePath=%p:{%s} uid=%ld gid=%ld\n", (void *)pszNativePath, pszNativePath, (long)uid, (long)gid);
+
+    /*
+     * Validate input, refusing named pipes.
+     */
+    if (    (pszNativePath[0] == '/' || pszNativePath[0] == '\\')
+        &&  (pszNativePath[1] == 'p' || pszNativePath[1] == 'P')
+        &&  (pszNativePath[2] == 'i' || pszNativePath[2] == 'I')
+        &&  (pszNativePath[3] == 'p' || pszNativePath[3] == 'P')
+        &&  (pszNativePath[4] == 'e' || pszNativePath[4] == 'E')
+        &&  (pszNativePath[5] == '/' || pszNativePath[5] == '\\'))
+        LIBCLOG_ERROR_RETURN_INT(-ENOENT);
+
+    /*
+     * If potential device, then perform real check.
+     * (Devices are subject to mode in POSIX.)
+     */
+    /** @todo copy device check from the path resolver. */
+
+    /*
+     * Join paths with the file handle base code path.
+     */
+    int rc = __libc_back_fsNativeFileOwnerSetCommon(-1, pszNativePath, __libc_back_fsInfoSupportUnixEAs(pszNativePath), uid, gid);
+    if (__predict_false(rc != 0))
+        LIBCLOG_ERROR_RETURN_INT(rc);
+    LIBCLOG_RETURN_INT(0);
+}
+
Index: /trunk/libc/src/kNIX/os2/fhOS2File.c
===================================================================
--- /trunk/libc/src/kNIX/os2/fhOS2File.c	(revision 3815)
+++ /trunk/libc/src/kNIX/os2/fhOS2File.c	(revision 3816)
@@ -1,8 +1,9 @@
 /* $Id$ */
 /** @file
- *
  * kNIX - Native file handles.
- *
- * Copyright (c) 2006 knut st. osmundsen <bird-src-spam@anduin.net>
+ */
+
+/*
+ * Copyright (c) 2006-2014 knut st. osmundsen <bird-src-spam@anduin.net>
  *
  *
@@ -635,8 +636,4 @@
                 };
                 #pragma pack()
-                EAOP2 EaOp2;
-                EaOp2.fpGEA2List = NULL;
-                EaOp2.fpFEA2List = (PFEA2LIST)&EAs;
-                EaOp2.oError = 0;
 
                 if (!S_ISREG(fMode) && !S_ISDIR(fMode))
@@ -644,15 +641,9 @@
 
                 /* finally, try update / add the EA. */
-                rc = DosSetFileInfo(pFH->fh, FIL_QUERYEASIZE, &EaOp2, sizeof(EaOp2));
+                EAOP2 EaOp2;
+                rc = __libc_back_fsNativeSetEAs(pFH->fh, pFH->pszNativePath, (PFEA2LIST)&EAs, &EaOp2);
                 if (__predict_false(rc != NO_ERROR))
                 {
-                    LIBCLOG_ERROR("DosSetFileInfo(%d,,,,) -> %d, oError=%#lx\n", pFH->fh, rc, EaOp2.oError);
-                    if (rc != ERROR_EAS_NOT_SUPPORTED && pFH->pszNativePath)
-                    {
-                        EaOp2.oError = 0;
-                        int rc2 = DosSetPathInfo((PCSZ)pFH->pszNativePath, FIL_QUERYEASIZE, &EaOp2, sizeof(EaOp2), 0);
-                        if (rc2)
-                            LIBCLOG_ERROR("DosSetPathInfo('%s',,,,) -> %d, oError=%#lx\n", pFH->pszNativePath, rc2, EaOp2.oError);
-                    }
+                    LIBCLOG_ERROR("__libc_back_fsNativeSetEAs('%s',,,,) -> %d, oError=%#lx\n", pFH->pszNativePath, rc, EaOp2.oError);
                     if (rc == ERROR_EAS_NOT_SUPPORTED)
                         rc = 0;
@@ -683,14 +674,13 @@
 
 /** @copydoc __LIBC_FHOPS::pfnSetOwner */
-static int fhOs2FileSetOwner(__LIBC_PFH pFH, uid_t uid)
-{
-    LIBCLOG_ENTER("pFH=%p:{.fd=%d} uid=%d\n", (void *)pFH, pFH->fh, uid);
+static int fhOs2FileSetOwner(__LIBC_PFH pFH, uid_t uid, gid_t gid)
+{
+    LIBCLOG_ENTER("pFH=%p:{.fd=%d} uid=%ld gid=%ld\n", (void *)pFH, pFH->fh, (long)uid, (long)gid);
     int rc;
-    /** @todo fchown */
-    /*if (pFH->pszNativePath)
-        rc = -ENOSYS;//rc = __libc_back_fsNativeSetOwner(pFH->pszNativePath, uid);
-    else
-        rc = -EINVAL;*/
-    rc = -ENOSYS;
+    if (pFH->pszNativePath)
+        rc = __libc_back_fsNativeFileOwnerSetCommon(pFH->hNative, pFH->pszNativePath, pFH->pFsInfo ? pFH->pFsInfo->fUnixEAs : 0,
+                                                    uid, gid);
+    else
+        rc = -EINVAL;
     LIBCLOG_MIX_RETURN_INT(rc);
 }
Index: /trunk/libc/src/kNIX/os2/fs-os2.c
===================================================================
--- /trunk/libc/src/kNIX/os2/fs-os2.c	(revision 3815)
+++ /trunk/libc/src/kNIX/os2/fs-os2.c	(revision 3816)
@@ -1,8 +1,9 @@
 /* $Id$ */
 /** @file
- *
  * kNIX - file system, OS/2 common bits.
- *
- * Copyright (c) 2004-2006 knut st. osmundsen <bird-src-spam@anduin.net>
+ */
+
+/*
+ * Copyright (c) 2004-2014 knut st. osmundsen <bird-src-spam@anduin.net>
  *
  *
@@ -1741,4 +1742,76 @@
 
 /**
+ * Helper path and handle based native functions for writing EAs.
+ *
+ * This tries to work around sharing issues as well as trying to use
+ * fchmod/fchown on handles opened without write access.
+ *
+ * @returns Native status code.
+ * @param   hNative         The native handle, -1 if not available.
+ * @param   pszNativePath   The native path.
+ * @param   pEAs            The list of EAs to set.
+ * @param   pEaOp2          The EA operation 2 buffer to use.  This is passed in
+ *                          as a parameter so that the calling code can access
+ *                          error information.
+ */
+int __libc_back_fsNativeSetEAs(intptr_t hNative, const char *pszNativePath, PFEA2LIST pEAs, PEAOP2 pEaOp2)
+{
+    /*
+     * First copy the EAs so we can do a retry with a different access path.
+     */
+    PFEA2LIST pCopyEAs = (PFEA2LIST)alloca(pEAs->cbList);
+    memcpy(pCopyEAs, pEAs, pEAs->cbList);
+
+    /*
+     * First try.
+     */
+    APIRET rc;
+    pEaOp2->fpGEA2List = NULL;
+    pEaOp2->fpFEA2List = pEAs;
+    pEaOp2->oError     = 0;
+    if (hNative != -1)
+        rc = DosSetFileInfo(hNative, FIL_QUERYEASIZE, pEaOp2, sizeof(*pEaOp2));
+    else
+        rc = DosSetPathInfo((PCSZ)pszNativePath, FIL_QUERYEASIZE, pEaOp2, sizeof(*pEaOp2), 0);
+
+    if (   (   rc == ERROR_SHARING_VIOLATION
+            || rc == ERROR_ACCESS_DENIED)
+        && pszNativePath
+        && pszNativePath[0])
+    {
+        /*
+         * To write EAs using DosSetPathInfo, the system requires deny-all
+         * access, but when using DosSetFileInfo we're seemingly free to choose
+         * this ourselves. So, try open the file with write access and retry.
+         */
+        APIRET rc2;
+        HFILE  hFile2      = (HFILE)-1;
+        ULONG  ulAction    = 0;
+        ULONG  flOpenFlags = OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
+        ULONG  flOpenMode  = OPEN_ACCESS_WRITEONLY | OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYNONE;
+
+#if OFF_MAX > LONG_MAX
+        if (__libc_gpfnDosOpenL)
+            rc2 = __libc_gpfnDosOpenL((PCSZ)pszNativePath, &hFile2, &ulAction, 0, FILE_NORMAL, flOpenFlags, flOpenMode, NULL);
+        else
+#endif
+            rc2 = DosOpen((PCSZ)pszNativePath, &hFile2, &ulAction, 0, FILE_NORMAL, flOpenFlags, flOpenMode, NULL);
+        if (rc2 == NO_ERROR)
+        {
+            memcpy(pEAs, pCopyEAs, pCopyEAs->cbList);
+            pEaOp2->fpGEA2List = NULL;
+            pEaOp2->fpFEA2List = pEAs;
+            pEaOp2->oError     = 0;
+            rc = DosSetFileInfo(hFile2, FIL_QUERYEASIZE, pEaOp2, sizeof(*pEaOp2));
+
+            DosClose(hFile2);
+        }
+    }
+
+    return rc;
+}
+
+
+/**
  * Reads the content of a symbolic link.
  *
Index: /trunk/libc/src/libc/io/fchown.c
===================================================================
--- /trunk/libc/src/libc/io/fchown.c	(revision 3815)
+++ /trunk/libc/src/libc/io/fchown.c	(revision 3816)
@@ -1,8 +1,9 @@
 /* $Id$ */
 /** @file
- *
  * fchown()
- *
- * Copyright (c) 2004 knut st. osmundsen <bird-srcspam@anduin.net>
+ */
+
+/*
+ * Copyright (c) 2004-2014 knut st. osmundsen <bird-srcspam@anduin.net>
  *
  *
@@ -26,5 +27,4 @@
 
 
-
 /*******************************************************************************
 *   Header Files                                                               *
@@ -34,30 +34,23 @@
 #include <unistd.h>
 #include <errno.h>
-#include <klibc/io.h>
-#include <klibc/logstrict.h>
-
+#include <klibc/backend.h>
+#include <InnoTekLIBC/logstrict.h>
 
 
 /**
- * Change the owner and group over a file.
- *
- * This is a stub. It only validates the filehandle and returns without changing anything.
+ * Change the owner and group if an open file.
  *
  * @returns 0 on success.
  * @returns -1 and errno on failure.
  * @param   fh      Handle to the file.
- * @param   owner   Owner id.
- * @param   group   Group id.
+ * @param   uid     The user id of the new owner, pass -1 to not change it.
+ * @param   gid     The group id of the new group, pass -1 to not change it.
  */
-int _STD(fchown)(int fh, uid_t owner, gid_t group)
+int _STD(fchown)(int fh, uid_t uid, gid_t gid)
 {
-    LIBCLOG_ENTER("fh=%d owner=%d group=%d\n", fh, owner, group);
-    __LIBC_PFH pFH;
-    int rc = __libc_FHGet(fh, &pFH);
+    LIBCLOG_ENTER("fh=%d uid=%ld gid=%ld\n", fh, (long)uid, (long)gid);
+    int rc = __libc_Back_fsFileOwnerSetFH(fh, uid, gid);
     if (!rc)
-    {
-        __libc_FHPut(pFH);
         LIBCLOG_RETURN_INT(0);
-    }
     errno = -rc;
     LIBCLOG_ERROR_RETURN_INT(-1);
Index: /trunk/libc/src/libc/io/lchown.c
===================================================================
--- /trunk/libc/src/libc/io/lchown.c	(revision 3815)
+++ /trunk/libc/src/libc/io/lchown.c	(revision 3816)
@@ -1,8 +1,9 @@
 /* $Id$ */
 /** @file
- *
  * lchown()
- *
- * Copyright (c) 2004 knut st. osmundsen <bird-srcspam@anduin.net>
+ */
+
+/*
+ * Copyright (c) 2004-2014 knut st. osmundsen <bird-srcspam@anduin.net>
  *
  *
@@ -26,34 +27,32 @@
 
 
-
 /*******************************************************************************
 *   Header Files                                                               *
 *******************************************************************************/
+#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_IO
 #include "libc-alias.h"
 #include <unistd.h>
-#include <sys/stat.h>
-#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_IO
+#include <errno.h>
+#include <klibc/backend.h>
 #include <InnoTekLIBC/logstrict.h>
 
 
-
 /**
- * Change the owner and group over a symbolic link.
- *
- * This is stub. It only validates the path and returns without changing anything.
+ * Change the owner and group of a symbolic link or file.
  *
  * @returns 0 on success.
  * @returns -1 and errno on failure.
- * @param   path    Path to the link to change owner/group of.
- * @param   owner   Owner id.
- * @param   group   Group id.
+ * @param   pszPath Path to the file to change owner/group of, symbolic link in
+ *                  the final component is not followed.
+ * @param   uid     The user id of the new owner, pass -1 to not change it.
+ * @param   gid     The group id of the new group, pass -1 to not change it.
  */
-int	 _STD(lchown)(const char *path, uid_t owner, gid_t group)
+int	 _STD(lchown)(const char *pszPath, uid_t uid, gid_t gid)
 {
-    LIBCLOG_ENTER("path=%p:{%s} owner=%d group=%d\n", (void *)path, path, owner, group);
-    struct stat st;
-    int rc = lstat(path, &st);
+    LIBCLOG_ENTER("pszPath=%p:{%s} uid=%ld gid=%ld\n", (void *)pszPath, pszPath, (long)uid, (long)gid);
+    int rc = __libc_Back_fsSymlinkOwnerSet(pszPath, uid, gid);
     if (!rc)
         LIBCLOG_RETURN_INT(0);
+    errno = -rc;
     LIBCLOG_ERROR_RETURN_INT(-1);
 }
Index: /trunk/libc/src/libc/misc/chown.c
===================================================================
--- /trunk/libc/src/libc/misc/chown.c	(revision 3815)
+++ /trunk/libc/src/libc/misc/chown.c	(revision 3816)
@@ -1,8 +1,9 @@
 /* $Id$ */
 /** @file
- *
  * chown()
- *
- * Copyright (c) 2004 knut st. osmundsen <bird-srcspam@anduin.net>
+ */
+
+/*
+ * Copyright (c) 2004-2014 knut st. osmundsen <bird-srcspam@anduin.net>
  *
  *
@@ -26,35 +27,33 @@
 
 
-
 /*******************************************************************************
 *   Header Files                                                               *
 *******************************************************************************/
+#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_IO
 #include "libc-alias.h"
 #include <unistd.h>
-#include <sys/stat.h>
-#define __LIBC_LOG_GROUP __LIBC_LOG_GRP_IO
+#include <errno.h>
+#include <klibc/backend.h>
 #include <InnoTekLIBC/logstrict.h>
 
 
-
 /**
- * Change the owner and group over a file.
- *
- * This is stub. It only validates the path and returns without changing anything.
+ * Change the owner and group of a file.
  *
  * @returns 0 on success.
  * @returns -1 and errno on failure.
- * @param   path    Path to the file to change owner/group of.
- * @param   owner   Owner id.
- * @param   group   Group id.
+ * @param   pszPath Path to the file to change owner/group of, all symbolic
+ *                  links are followed.
+ * @param   uid     The user id of the new owner, pass -1 to not change it.
+ * @param   gid     The group id of the new group, pass -1 to not change it.
  */
-int	 _STD(chown)(const char *path, uid_t owner, gid_t group)
+int	 _STD(chown)(const char *pszPath, uid_t uid, gid_t gid)
 {
-    LIBCLOG_ENTER("path=%p:{%s} owner=%d group=%d\n", (void *)path, path, owner, group);
-    struct stat st;
-    int rc = stat(path, &st);
+    LIBCLOG_ENTER("pszPath=%p:{%s} uid=%ld gid=%ld\n", (void *)pszPath, pszPath, (long)uid, (long)gid);
+    int rc = __libc_Back_fsFileOwnerSet(pszPath, uid, gid);
     if (!rc)
-        LIBCLOG_RETURN_INT(rc);
-    LIBCLOG_ERROR_RETURN_INT(rc);
+        LIBCLOG_RETURN_INT(0);
+    errno = -rc;
+    LIBCLOG_ERROR_RETURN_INT(-1);
 }
 
Index: /trunk/libc/tests/libc/io/chown-1.c
===================================================================
--- /trunk/libc/tests/libc/io/chown-1.c	(revision 3815)
+++ /trunk/libc/tests/libc/io/chown-1.c	(revision 3816)
@@ -56,5 +56,5 @@
         } \
         else \
-            assertOwners(fd, szTmp, a_uidExpect, a_gidExpect, #a_OperationExpr " at line " XSTR(__LINE__)); \
+            assertOwners(fd, szTmp, a_uidExpect, a_gidExpect, " " #a_OperationExpr " at line " XSTR(__LINE__)); \
     } while (0)
 
@@ -176,8 +176,19 @@
     TEST_CHANGE(chown(szTmp,  -1, st1.st_gid + 3), st1.st_uid + 2, st1.st_gid + 3);
 
+    close(fd);
+    fd = -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(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(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.
      */
-    close(fd);
     if (unlink(szTmp))
     {
