[med-svn] [Git][med-team/libsis-base-java][upstream] New upstream version 18.09~pre1+git20180827.fe4953e+dfsg

Andreas Tille gitlab at salsa.debian.org
Wed Sep 26 08:50:30 BST 2018


Andreas Tille pushed to branch upstream at Debian Med / libsis-base-java


Commits:
e42bd7e6 by Andreas Tille at 2018-09-26T07:08:47Z
New upstream version 18.09~pre1+git20180827.fe4953e+dfsg
- - - - -


16 changed files:

- source/c/compile_windows_x64.mak → source/c/Makefile_Win64.mak
- source/c/compile_linux_amd64.sh
- source/c/compile_linux_arm.sh
- − source/c/compile_linux_i386.sh
- − source/c/compile_macosx_i386.sh
- source/c/compile_macosx_x86_64.sh
- − source/c/compile_solaris_amd64.sh
- − source/c/compile_solaris_sparc.sh
- − source/c/compile_solaris_sparcv9.sh
- − source/c/compile_solaris_x86.sh
- − source/c/compile_windows_i386.mak
- source/c/unix.c
- source/java/ch/systemsx/cisd/base/unix/Unix.java
- sourceTest/java/ch/systemsx/cisd/base/AllTests.java
- + sourceTest/java/ch/systemsx/cisd/base/unix/UnixRootTests.java
- sourceTest/java/ch/systemsx/cisd/base/unix/UnixTests.java


Changes:

=====================================
source/c/compile_windows_x64.mak → source/c/Makefile_Win64.mak
=====================================
@@ -6,13 +6,13 @@
 #============================================================================
 
 # Visual C++ directory, for example
-VCPPDIR=C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC
+VCPPDIR=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC
 
 # Directory where JDK is installed (We require JDK 1.6)
-JAVADIR=C:\Program Files\Java\jdk1.6.0_37
+JAVADIR=C:\Program Files\Java\jdk1.8.0_181
 
 # Common parent directory
-PARENTDIR=C:\nativeData
+PARENTDIR=F:\base
 
 # Directory of the HDF Java Products, for example
 SRCDIR=$(PARENTDIR)\c\


=====================================
source/c/compile_linux_amd64.sh
=====================================
@@ -1,6 +1,7 @@
 #! /bin/bash
 
-gcc -shared -O3 -fPIC unix.c -I/usr/java/jdk1.6.0/include -I/usr/java/jdk1.6.0/include/linux -o libunix.so
+JAVA_INCLUDE=/usr/lib/jvm/java-1.8.0/include 
+gcc -shared -O3 -fPIC unix.c -I$JAVA_INCLUDE -I$JAVA_INCLUDE/linux -o libunix.so
 
 # MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
-gcc -shared -O3 -fPIC -DMACHINE_BYTE_ORDER=1 copy*.c  -I/usr/java/jdk1.6.0/include -I/usr/java/jdk1.6.0/include/linux -o libnativedata.so
+gcc -shared -O3 -fPIC -DMACHINE_BYTE_ORDER=1 copy*.c -I$JAVA_INCLUDE -I$JAVA_INCLUDE/linux -o libnativedata.so


=====================================
source/c/compile_linux_arm.sh
=====================================
@@ -1,6 +1,6 @@
 #! /bin/bash
 
-gcc -shared -O3 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I/usr/java/jdk1.7.0/include -I/usr/java/jdk1.7.0/include/linux unix.c -o libunix.so
+gcc -shared -O3 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I/usr/java/jdk1.8.0/include -I/usr/java/jdk1.8.0/include/linux unix.c -o libunix.so
 
 # MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
-gcc -shared -O3 -fPIC -DMACHINE_BYTE_ORDER=1 copy*.c  -I/usr/java/jdk1.7.0/include -I/usr/java/jdk1.7.0/include/linux -o libnativedata.so
+gcc -shared -O3 -fPIC -DMACHINE_BYTE_ORDER=1 copy*.c -I/usr/java/jdk1.8.0/include -I/usr/java/jdk1.8.0/include/linux -o libnativedata.so


=====================================
source/c/compile_linux_i386.sh deleted
=====================================
@@ -1,6 +0,0 @@
-#! /bin/bash
-
-gcc -m32 -shared -O3 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I/usr/java/jdk1.6.0/include -I/usr/java/jdk1.6.0/include/linux unix.c -o libunix.so
-
-# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
-gcc -m32 -shared -O3 -fPIC -DMACHINE_BYTE_ORDER=1 copy*.c  -I/usr/java/jdk1.6.0/include -I/usr/java/jdk1.6.0/include/linux -o libnativedata.so


=====================================
source/c/compile_macosx_i386.sh deleted
=====================================
@@ -1,6 +0,0 @@
-#! /bin/bash
-
-gcc -m32 -mmacosx-version-min=10.6 -bundle -O3 unix.c -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libunix.jnilib
-
-# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
-gcc -m32 -mmacosx-version-min=10.6 -bundle -O3 -DMACHINE_BYTE_ORDER=1 copy*.c -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libnativedata.jnilib


=====================================
source/c/compile_macosx_x86_64.sh
=====================================
@@ -1,6 +1,6 @@
 #! /bin/bash
 
-gcc -m64 -mmacosx-version-min=10.6 -dynamiclib -D_DARWIN_USE_64_BIT_INODE -O3 unix.c -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libunix.jnilib
+gcc -m64 -mmacosx-version-min=10.11 -dynamiclib -D_DARWIN_USE_64_BIT_INODE -O3 unix.c -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libunix.jnilib
 
 # MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
-gcc -m64 -mmacosx-version-min=10.6 -dynamiclib -O3 -DMACHINE_BYTE_ORDER=1 copy*.c -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libnativedata.jnilib
+gcc -m64 -mmacosx-version-min=10.11 -dynamiclib -O3 -DMACHINE_BYTE_ORDER=1 copy*.c -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libnativedata.jnilib


=====================================
source/c/compile_solaris_amd64.sh deleted
=====================================
@@ -1,6 +0,0 @@
-#! /bin/bash
-
-cc -G -KPIC -fast -m64 -I/usr/java/include -I/usr/java/include/solaris unix.c -o libunix.so
-
-# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
-cc -G -KPIC -fast -m64 -DMACHINE_BYTE_ORDER=1 copy*.c  -I/usr/java/include -I/usr/java/include/solaris -o libnativedata.so


=====================================
source/c/compile_solaris_sparc.sh deleted
=====================================
@@ -1,6 +0,0 @@
-#! /bin/bash
-
-cc -G -KPIC -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I/usr/java/include -I/usr/java/include/solaris unix.c -o libunix.so
-
-# MACHINE_BYTE_ORDER=2 corresponds to 'big endian'
-cc -G -KPIC -DMACHINE_BYTE_ORDER=2 copy*.c  -I/usr/java/include -I/usr/java/include/solaris -o libnativedata.so


=====================================
source/c/compile_solaris_sparcv9.sh deleted
=====================================
@@ -1,6 +0,0 @@
-#! /bin/bash
-
-cc -G -KPIC -fast -m64 -I/usr/java/include -I/usr/java/include/solaris unix.c -o libunix.so
-
-# MACHINE_BYTE_ORDER=2 corresponds to 'big endian'
-cc -G -KPIC -fast -m64 -DMACHINE_BYTE_ORDER=2 copy*.c  -I/usr/java/include -I/usr/java/include/solaris -o libnativedata.so


=====================================
source/c/compile_solaris_x86.sh deleted
=====================================
@@ -1,6 +0,0 @@
-#! /bin/bash
-
-cc -G -KPIC -fast -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I/usr/java/include -I/usr/java/include/solaris unix.c -o libunix.so
-
-# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
-cc -G -KPIC -fast -DMACHINE_BYTE_ORDER=1 copy*.c  -I/usr/java/include -I/usr/java/include/solaris -o libnativedata.so


=====================================
source/c/compile_windows_i386.mak deleted
=====================================
@@ -1,181 +0,0 @@
-#============================================================================
-#
-#              Makefile to compile the 'nativedata' native library
-#              Usage: nmake /f compile_windows_i386.mak
-#
-#============================================================================
-
-# Visual C++ directory, for example
-VCPPDIR=C:\Program Files\Microsoft Visual Studio 9.0\VC
-
-# Directory where JDK is installed (We require JDK 1.6)
-JAVADIR=C:\Program Files\Java\jdk1.6.0_37
-
-# Common parent directory
-PARENTDIR=C:\nativeData
-
-# Directory of the HDF Java Products, for example
-SRCDIR=$(PARENTDIR)\c\
-
-#===========================================================================
-#   Do not make any change below this line unless you know what you do
-#===========================================================================
-PATH=$(PATH);$(VCPPDIR)\BIN
-SRCDIR=$(SRCDIR)
-
-VALID_PATH_SET=YES
-#-------------------------------------------------------
-# Test if all path is valid
-
-!IF EXISTS("$(VCPPDIR)")
-!ELSE
-!MESSAGE ERROR: Visual C++ directory $(VCPPDIR) does not exist
-VALID_PATH_SET=NO 
-!ENDIF
-
-!IF EXISTS("$(JAVADIR)")
-!ELSE
-!MESSAGE ERROR: JDK directory $(JAVADIR) does not exist
-VALID_PATH_SET=NO 
-!ENDIF
-
-!IF EXISTS("$(SRCDIR)")
-!ELSE
-!MESSAGE ERROR: C source directory $(SRCDIR) does not exist
-VALID_PATH_SET=NO 
-!ENDIF
-
-#-------------------------------------------------------
-
-
-!IF "$(VALID_PATH_SET)" == "YES"
-
-!IF "$(OS)" == "Windows_NT"
-NULL=
-!ELSE 
-NULL=nul
-!ENDIF 
-
-INTDIR=.\nativedata\Release
-OUTDIR=$(SRCDIR)\lib\win
-
-INCLUDES =  \
-	"$(JAVADIR)\include\jni.h" \
-	"$(JAVADIR)\include\win32\jni_md.h"
-
-
-ALL : "$(OUTDIR)\nativedata.dll"
-
-"$(INTDIR)" :
-    if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
-
-"$(OUTDIR)" :
-    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /W3 /EHsc /O2 /I "$(JAVADIR)\include" /I "$(JAVADIR)\include\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "MACHINE_BYTE_ORDER=1" /Fp"$(INTDIR)\nativedata.pch" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
-
-.c{$(INTDIR)}.obj::
-   $(CPP) @<<
-   $(CPP_PROJ) $< 
-<<
-
-.cpp{$(INTDIR)}.obj::
-   $(CPP) @<<
-   $(CPP_PROJ) $< 
-<<
-
-.cxx{$(INTDIR)}.obj::
-   $(CPP) @<<
-   $(CPP_PROJ) $< 
-<<
-
-.c{$(INTDIR)}.sbr::
-   $(CPP) @<<
-   $(CPP_PROJ) $< 
-<<
-
-.cpp{$(INTDIR)}.sbr::
-   $(CPP) @<<
-   $(CPP_PROJ) $< 
-<<
-
-.cxx{$(INTDIR)}.sbr::
-   $(CPP) @<<
-   $(CPP_PROJ) $< 
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 
-RSC=rc.exe
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(INTDIR)\nativedata.bsc" 
-BSC32_SBRS= \
-	
-LINK=link.exe
-LINK_FLAGS=/nologo /dll /nodefaultlib:msvcrt /incremental:no /pdb:"$(INTDIR)\nativedata.pdb" /machine:I386 /out:"$(OUTDIR)\nativedata.dll" /implib:"$(INTDIR)\nativedata.lib" 
-LINK_OBJS= \
-	"$(INTDIR)\copyCommon.obj" \
-	"$(INTDIR)\copyByteDouble.obj" \
-	"$(INTDIR)\copyByteFloat.obj" \
-	"$(INTDIR)\copyByteInt.obj" \
-	"$(INTDIR)\copyByteLong.obj" \
-	"$(INTDIR)\copyByteShort.obj" \
-	"$(INTDIR)\copyByteChar.obj"
-
-"$(OUTDIR)\nativedata.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK_OBJS)
-    $(LINK) @<<
-  $(LINK_FLAGS) $(LINK_OBJS)
-<<
-
-
-SOURCE=$(SRCDIR)\copyCommon.c
-
-"$(INTDIR)\copyCommon.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
-	$(CPP) $(CPP_PROJ) $(SOURCE)
-
-
-SOURCE=$(SRCDIR)\copyByteDouble.c
-
-"$(INTDIR)\copyByteDouble.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
-	$(CPP) $(CPP_PROJ) $(SOURCE)
-
-SOURCE=$(SRCDIR)\copyByteFloat.c
-
-"$(INTDIR)\copyByteFloat.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
-	$(CPP) $(CPP_PROJ) $(SOURCE)
-
-SOURCE=$(SRCDIR)\copyByteInt.c
-
-"$(INTDIR)\copyByteInt.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
-	$(CPP) $(CPP_PROJ) $(SOURCE)
-
-SOURCE=$(SRCDIR)\copyByteLong.c
-
-"$(INTDIR)\copyByteLong.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
-	$(CPP) $(CPP_PROJ) $(SOURCE)
-
-SOURCE=$(SRCDIR)\copyByteShort.c
-
-"$(INTDIR)\copyByteShort.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
-	$(CPP) $(CPP_PROJ) $(SOURCE)
-
-SOURCE=$(SRCDIR)\copyByteChar.c
-
-"$(INTDIR)\copyByteChar.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
-	$(CPP) $(CPP_PROJ) $(SOURCE)
-
-CLEAN :
-	- at erase "$(INTDIR)\copyCommon.obj"
-	- at erase "$(INTDIR)\copyByteDouble.obj"
-	- at erase "$(INTDIR)\copyByteFloat.obj"
-	- at erase "$(INTDIR)\copyByteInt.obj"
-	- at erase "$(INTDIR)\copyByteLong.obj"
-	- at erase "$(INTDIR)\copyByteShort.obj"
-	- at erase "$(INTDIR)\copyByteChar.obj"
-	- at erase "$(INTDIR)\vc90.idb"
-	- at erase "$(INTDIR)\nativedata.exp"
-	- at erase "$(INTDIR)\nativedata.lib"
-	- at erase "$(OUTDIR)\nativedata.dll"
-
-!ENDIF


=====================================
source/c/unix.c
=====================================
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <time.h>
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
@@ -20,6 +21,7 @@
 #include <grp.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 #include <jni.h>
 
 /* Types of links. Keep in sync with Java enum. */
@@ -28,6 +30,17 @@
 #define SYMLINK 2
 #define OTHER 3
 
+/* Field name for nano second precission of file stat times. */
+#ifdef __MACH__
+#define ST_ATIME_NANO st_atimespec.tv_nsec
+#define ST_MTIME_NANO st_mtimespec.tv_nsec
+#define ST_CTIME_NANO st_ctimespec.tv_nsec
+#else
+#define ST_ATIME_NANO st_atim.tv_nsec
+#define ST_MTIME_NANO st_mtim.tv_nsec
+#define ST_CTIME_NANO st_ctim.tv_nsec
+#endif
+
 #ifndef __STAT
 #define __STAT stat
 #endif
@@ -44,6 +57,82 @@ jclass groupClass;
 jmethodID groupConstructorID;
 jclass statClass;
 jmethodID statConstructorID;
+jboolean statConstructorHasNanos;
+
+/* 
+ * Error and Exception Handling 
+ */
+ 
+#define THROWEXCEPTION(className,args) {                                    \
+    jclass     jc;                                                          \
+    jmethodID  jm;                                                          \
+    jobject    ex;                                                          \
+    jc = (*env)->FindClass(env, (className));                               \
+    if (jc == NULL) {                                                       \
+        return JNI_FALSE;                                                   \
+    }                                                                       \
+    jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");   \
+    if (jm == NULL) {                                                       \
+        printf("THROWEXCEPTION FATAL ERROR: GetMethodID failed\n");         \
+        return JNI_FALSE;                                                   \
+    }                                                                       \
+    ex = (*env)->NewObjectA (env, jc, jm, (jvalue*)(args));                 \
+    if (ex == NULL) {                                                       \
+        printf("THROWEXCEPTION FATAL ERROR:  %s: Creation failed\n", (className)); \
+        return JNI_FALSE;                                                   \
+    }                                                                       \
+    if ((*env)->Throw(env, (jthrowable)ex) < 0) {                           \
+        printf("THROWEXCEPTION FATAL ERROR:  %s: Throw failed\n", (className));    \
+        return JNI_FALSE;                                                   \
+    }                                                                       \
+    return JNI_TRUE;                                                        \
+}
+
+/*
+ *  Routine to raise particular Java exceptions from C
+ */
+static jboolean
+jni_error_class
+    (JNIEnv *env, const char *message, const char *className)
+{
+    char *args[2];
+    jstring str = (*env)->NewStringUTF(env, message);
+    args[0] = (char *)str;
+    args[1] = 0;
+
+    THROWEXCEPTION(className, args);
+} /* end jni_error_class() */
+
+/*
+ *  A NULL argument in an HDF5 call
+ *  Create and throw an 'NullPointerException'
+ *
+ *  Note:  This routine never returns from the 'throw',
+ *  and the Java native method immediately raises the
+ *  exception.
+ */
+jboolean null_pointer_exception(JNIEnv *env, const char *functName)
+{
+    return jni_error_class(env, functName, "java/lang/NullPointerException");
+} /* end null_pointer_exception() */
+
+/*
+ *  A fatal error in a JNI call
+ *  Create and throw an 'InternalError'
+ *
+ *  Note:  This routine never returns from the 'throw',
+ *  and the Java native method immediately raises the
+ *  exception.
+ */
+jboolean internal_error(JNIEnv *env, const char *functName)
+{
+    return jni_error_class(env, functName, "java/lang/InternalError");
+} /* end iternal_error() */
+
+
+/*
+ * End Error and Exception Handling 
+ */
 
 JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_init
   (JNIEnv *env, jclass clss)
@@ -82,11 +171,18 @@ JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_init
         return -1;
     }
     statClass = (*env)->NewGlobalRef(env, statClass);
-    statConstructorID = (*env)->GetMethodID(env, statClass, "<init>", "(JJSBIIIJJJJJI)V");
-    if (groupConstructorID == NULL) /* Really shouldn't happen, will throw NoSuchMethodError. */
-    {
-        return -1;
-    }
+    statConstructorHasNanos = JNI_TRUE;
+    statConstructorID = (*env)->GetMethodID(env, statClass, "<init>", "(JJSBIIIJJJJJJJJI)V");
+    if (statConstructorID == NULL) /* We have an old Java class without the "microsecond constructor". */
+    {
+        (*env)->ExceptionClear(env);
+	    statConstructorHasNanos = JNI_FALSE;
+	    statConstructorID = (*env)->GetMethodID(env, statClass, "<init>", "(JJSBIIIJJJJJI)V");
+	    if (statConstructorID == NULL) /* Really shouldn't happen, will throw NoSuchMethodError. */
+	    {
+	        return -1;
+	    }
+	}
     return 0;
 }
 
@@ -165,10 +261,20 @@ jobject call_stat(JNIEnv *env, jclass clss, jstring filename, stat_func_ptr stat
         {
             type = OTHER;
         }
-        result = (*env)->NewObject(env, statClass, statConstructorID, (jlong) s.st_dev, (jlong) s.st_ino, 
-                   (jshort) (s.st_mode & 07777), (jbyte) type, (jint) s.st_nlink, 
-                   (jint) s.st_uid, (jint) s.st_gid, (jlong) s.st_atime, (jlong) s.st_mtime, 
-                   (jlong) s.st_ctime, (jlong) s.st_size, (jlong) s.st_blocks, (jint) s.st_blksize);
+        if (statConstructorHasNanos)
+        {
+            result = (*env)->NewObject(env, statClass, statConstructorID, (jlong) s.st_dev, (jlong) s.st_ino, 
+                       (jshort) (s.st_mode & 07777), (jbyte) type, (jint) s.st_nlink, 
+                       (jint) s.st_uid, (jint) s.st_gid, (jlong) s.st_atime, (jlong) s.ST_ATIME_NANO, 
+                       (jlong) s.st_mtime, (jlong) s.ST_MTIME_NANO, (jlong) s.st_ctime, (jlong) s.ST_CTIME_NANO, 
+                       (jlong) s.st_size, (jlong) s.st_blocks, (jint) s.st_blksize);
+        } else
+        {
+            result = (*env)->NewObject(env, statClass, statConstructorID, (jlong) s.st_dev, (jlong) s.st_ino, 
+                       (jshort) (s.st_mode & 07777), (jbyte) type, (jint) s.st_nlink, 
+                       (jint) s.st_uid, (jint) s.st_gid, (jlong) s.st_atime, (jlong) s.st_mtime, 
+                       (jlong) s.st_ctime, (jlong) s.st_size, (jlong) s.st_blocks, (jint) s.st_blksize);
+        }
         return result;
     }
 }
@@ -236,6 +342,23 @@ JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_chown(JNIEnv *env, j
     }
 }
 
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_lchown(JNIEnv *env, jclass clss, jstring linkname, jint uid, jint gid)
+{
+    const char* plinkname;
+    int retval;
+	
+    plinkname = (char *)(*env)->GetStringUTFChars(env, linkname, NULL);
+    retval = lchown(plinkname, uid, gid);
+    (*env)->ReleaseStringUTFChars(env, linkname, plinkname);
+    if (retval < 0)
+    {
+		    return -errno;
+    } else
+    {
+        return 0;
+    }
+}
+
 JNIEXPORT jstring JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getuser(JNIEnv *env, jclass clss, jint uid)
 {
     struct passwd *pw;
@@ -444,3 +567,133 @@ JNIEXPORT jstring JNICALL Java_ch_systemsx_cisd_base_unix_Unix_strerror__(JNIEnv
 {
     return (*env)->NewStringUTF(env, strerror(errno));
 }
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_lutimes
+  (JNIEnv *env, jclass clss, jstring filename, jlong accessTimeSecs, jlong accessTimeMicroSecs, jlong modificationTimeSecs, jlong modificationTimeMicroSecs)
+{
+    const char* pfilename;
+    struct timeval times[2];
+    int retval;
+
+    pfilename = (char *)(*env)->GetStringUTFChars(env, filename, NULL);
+    times[0].tv_sec = accessTimeSecs;
+    times[0].tv_usec = accessTimeMicroSecs;
+    times[1].tv_sec = modificationTimeSecs;
+    times[1].tv_usec = modificationTimeMicroSecs;
+
+    retval = lutimes(pfilename, times);
+    if (retval < 0)
+    {
+        retval = -errno;
+    }
+
+    (*env)->ReleaseStringUTFChars(env, filename, pfilename);
+
+   return retval;
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_utimes
+  (JNIEnv *env, jclass clss, jstring filename, jlong accessTimeSecs, jlong accessTimeMicroSecs, jlong modificationTimeSecs, jlong modificationTimeMicroSecs)
+{
+    const char* pfilename;
+    struct timeval times[2];
+    int retval;
+
+    pfilename = (char *)(*env)->GetStringUTFChars(env, filename, NULL);
+    times[0].tv_sec = accessTimeSecs;
+    times[0].tv_usec = accessTimeMicroSecs;
+    times[1].tv_sec = modificationTimeSecs;
+    times[1].tv_usec = modificationTimeMicroSecs;
+
+    retval = utimes(pfilename, times);
+    if (retval < 0)
+    {
+        retval = -errno;
+    }
+
+    (*env)->ReleaseStringUTFChars(env, filename, pfilename);
+
+   return retval;
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_clock_1gettime
+  (JNIEnv *env, jclass clss, jlongArray time)
+{
+    struct timespec spec;
+    jlong   *timeP;
+    jboolean isCopy;
+    int retval;
+    
+    if (time == NULL) 
+    {
+        null_pointer_exception(env, "clock_gettime: time is NULL");
+    } /* end if */
+    timeP = (jlong*)(*env)->GetPrimitiveArrayCritical(env, time, &isCopy);
+    if (timeP == NULL) 
+    {
+        internal_error(env, "clock_gettime: time not pinned");
+    } /* end if */
+
+
+    retval = clock_gettime(CLOCK_REALTIME, &spec);
+    if (retval < 0)
+    {
+        retval = -errno;
+    } else
+    {
+	    timeP[0] = spec.tv_sec;
+	    timeP[1] = spec.tv_nsec;
+	}
+
+    (*env)->ReleasePrimitiveArrayCritical(env, time, timeP, 0);    
+    
+    return retval;
+}
+
+int clock_gettime2(int clk_id, struct timespec* t) {
+    struct timeval now;
+    
+    int rv = gettimeofday(&now, NULL);
+    if (rv) 
+    {
+        return rv;
+    }
+    t->tv_sec  = now.tv_sec;
+    t->tv_nsec = now.tv_usec * 1000;
+    
+    return 0;
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_clock_1gettime2
+  (JNIEnv *env, jclass clss, jlongArray time)
+{
+    struct timespec spec;
+    jlong   *timeP;
+    jboolean isCopy;
+    int retval;
+    
+    if (time == NULL) 
+    {
+        null_pointer_exception(env, "clock_gettime: time is NULL");
+    } /* end if */
+    timeP = (jlong*)(*env)->GetPrimitiveArrayCritical(env, time, &isCopy);
+    if (timeP == NULL) 
+    {
+        internal_error(env, "clock_gettime: time not pinned");
+    } /* end if */
+
+
+    retval = clock_gettime2(CLOCK_REALTIME, &spec);
+    if (retval < 0)
+    {
+        retval = -errno;
+    } else
+    {
+	    timeP[0] = spec.tv_sec;
+	    timeP[1] = spec.tv_nsec;
+	}
+
+    (*env)->ReleasePrimitiveArrayCritical(env, time, timeP, 0);    
+    
+    return retval;
+}


=====================================
source/java/ch/systemsx/cisd/base/unix/Unix.java
=====================================
@@ -25,26 +25,45 @@ import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
 import ch.systemsx.cisd.base.utilities.NativeLibraryUtilities;
 
 /**
- * A utility class that provides access to common Unix system calls. Obviously, this will only work
- * on Unix platforms and it requires a native library to be loaded.
+ * A utility class that provides access to common Unix system calls. Obviously, this will only work on Unix platforms and it requires a native library
+ * to be loaded.
  * <p>
- * <i>Check with {@link #isOperational()} if this class is operational and only call the other
- * methods if <code>Unix.isOperational() == true</code>.</i>
+ * <i>Check with {@link #isOperational()} if this class is operational and only call the other methods if
+ * <code>Unix.isOperational() == true</code>.</i>
  * 
  * @author Bernd Rinn
  */
 public final class Unix
 {
 
+    /**
+     * Method how processes are detected on this host.
+     *
+     */
     private enum ProcessDetection
     {
-        PROCFS, PS, NONE
+        /**
+         * Process detection via <code>procfs</code> (Linux only).
+         */
+        PROCFS,
+        
+        /**
+         * Process detection via the command line tool <code>ps</code>.
+         */
+        PS,
+        
+        /**
+         * No working process detection found. 
+         */
+        NONE
     }
 
     private final static boolean operational;
-
+    
     private final static ProcessDetection processDetection;
 
+    private static volatile boolean useUnixRealtimeTimer = false;
+
     static
     {
         operational = NativeLibraryUtilities.loadNativeLibrary("unix");
@@ -66,6 +85,7 @@ public final class Unix
         {
             processDetection = ProcessDetection.NONE;
         }
+        useUnixRealtimeTimer = Boolean.getBoolean("unix.realtime.timer");
     }
 
     /** set user ID on execution */
@@ -104,6 +124,103 @@ public final class Unix
     /** execute/search by others */
     public static final short S_IXOTH = 00001;
 
+    /**
+     * A class to represent a Unix <code>struct timespec</code> that holds a system time in nano-second resolution. 
+     */
+    public static final class Time
+    {
+        private final long secs;
+        
+        private final long nanos;
+
+        private Time(long secs, long nanos)
+        {
+            this.secs = secs;
+            this.nanos = nanos;
+        }
+
+        public long getSecs()
+        {
+            return secs;
+        }
+
+        public long getNanoSecPart()
+        {
+            return nanos;
+        }
+
+        public long getMicroSecPart()
+        {
+            if (nanos % 1000 >= 500)
+            {
+                return nanos / 1_000 + 1;
+            } else
+            {
+                return nanos / 1_000;
+            }
+        }
+
+        public long getMilliSecPart()
+        {
+            if (nanos % 1000000 >= 500000)
+            {
+                return nanos / 1_000_000 + 1;
+            } else
+            {
+                return nanos / 1_000_000;
+            }
+        }
+        
+        public long getMillis()
+        {
+            return secs * 1_000 + getMilliSecPart();
+        }
+
+        @Override
+        public String toString()
+        {
+            return "Time [secs=" + secs + ", nanos=" + nanos + "]";
+        }
+
+        @Override
+        public int hashCode()
+        {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + (int) (nanos ^ (nanos >>> 32));
+            result = prime * result + (int) (secs ^ (secs >>> 32));
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj)
+        {
+            if (this == obj)
+            {
+                return true;
+            }
+            if (obj == null)
+            {
+                return false;
+            }
+            if (getClass() != obj.getClass())
+            {
+                return false;
+            }
+            final Time other = (Time) obj;
+            if (nanos != other.nanos)
+            {
+                return false;
+            }
+            if (secs != other.secs)
+            {
+                return false;
+            }
+            return true;
+        }
+
+    }
+    
     /**
      * A class representing the Unix <code>stat</code> structure.
      */
@@ -125,11 +242,11 @@ public final class Unix
 
         private final int gid;
 
-        private final long lastAccess;
+        private final Time lastAccess;
 
-        private final long lastModified;
+        private final Time lastModified;
 
-        private final long lastStatusChange;
+        private final Time lastStatusChange;
 
         private final long size;
 
@@ -140,6 +257,16 @@ public final class Unix
         Stat(long deviceId, long inode, short permissions, byte linkType, int numberOfHardLinks,
                 int uid, int gid, long lastAccess, long lastModified, long lastStatusChange,
                 long size, long numberOfBlocks, int blockSize)
+        {
+            this(deviceId, inode, permissions, linkType, numberOfHardLinks, uid, gid,
+                    lastAccess, 0, lastModified, 0, lastStatusChange, 0, size, numberOfBlocks, blockSize);
+        }
+
+        Stat(long deviceId, long inode, short permissions, byte linkType, int numberOfHardLinks,
+                int uid, int gid, long lastAccess, long lastAccessNanos,
+                long lastModified, long lastModifiedNanos,
+                long lastStatusChange, long lastStatusChangeNanos,
+                long size, long numberOfBlocks, int blockSize)
         {
             this.deviceId = deviceId;
             this.inode = inode;
@@ -148,9 +275,9 @@ public final class Unix
             this.numberOfHardLinks = numberOfHardLinks;
             this.uid = uid;
             this.gid = gid;
-            this.lastAccess = lastAccess;
-            this.lastModified = lastModified;
-            this.lastStatusChange = lastStatusChange;
+            this.lastAccess = new Time(lastAccess, lastAccessNanos);
+            this.lastModified = new Time(lastModified, lastModifiedNanos);
+            this.lastStatusChange = new Time(lastStatusChange, lastStatusChangeNanos);
             this.size = size;
             this.numberOfBlocks = numberOfBlocks;
             this.blockSize = blockSize;
@@ -161,6 +288,9 @@ public final class Unix
             this.symbolicLinkOrNull = symbolicLinkOrNull;
         }
 
+        /**
+         * Get link target of the symbolic link or <code>null</code>, if this is not a link or the link target has not been read.
+         */
         public String tryGetSymbolicLink()
         {
             return symbolicLinkOrNull;
@@ -171,6 +301,9 @@ public final class Unix
             return deviceId;
         }
 
+        /**
+         * Returns the inode. 
+         */
         public long getInode()
         {
             return inode;
@@ -194,6 +327,11 @@ public final class Unix
             return FileLinkType.SYMLINK == linkType;
         }
 
+        /**
+         * Returns the number of hard links for the <var>linkName</var>. Does not dereference a symbolic link.
+         * 
+         * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link does not exist.
+         */ 
         public int getNumberOfHardLinks()
         {
             return numberOfHardLinks;
@@ -209,21 +347,78 @@ public final class Unix
             return gid;
         }
 
-        public long getLastAccess()
+        /**
+         * Time when file data last accessed.
+         * <p>
+         * Changed by the mknod(2), utimes(2) and read(2) system calls.
+         * 
+         * @return {@link Time} object containing seconds (to nano-second resolution) since the epoch.
+         */
+        public Time getLastAccessTime()
         {
             return lastAccess;
         }
 
-        public long getLastModified()
+        /**
+         * Time when file data last accessed.
+         * <p>
+         * Changed by the mknod(2), utimes(2) and read(2) system calls.
+         * 
+         * @return Seconds since the epoch.
+         */
+        public long getLastAccess()
+        {
+            return lastAccess.getSecs();
+        }
+
+        /**
+         * Time when file data last modified.
+         * <p>
+         * Changed by the mknod(2), utimes(2) and write(2) system calls.
+         * 
+         * @return {@link Time} object containing seconds (to nano-second resolution) since the epoch.
+         */
+        public Time getLastModifiedTime()
         {
             return lastModified;
         }
 
-        public long getLastStatusChange()
+        /**
+         * Time when file data last modified.
+         * <p>
+         * Changed by the mknod(2), utimes(2) and write(2) system calls.
+         * 
+         * @return Seconds since the epoch.
+         */
+        public long getLastModified()
+        {
+            return lastModified.getSecs();
+        }
+
+        /**
+         * Time when file status was last changed (inode data modification).
+         * <p>
+         * Changed by the chmod(2), chown(2), link(2), mknod(2), rename(2), unlink(2), utimes(2) and write(2) system calls.
+         * 
+         * @return {@link Time} object containing seconds (to nano-second resolution) since the epoch.
+         */
+        public Time getLastStatusChangeTime()
         {
             return lastStatusChange;
         }
 
+        /**
+         * Time when file status was last changed (inode data modification).
+         * <p>
+         * Changed by the chmod(2), chown(2), link(2), mknod(2), rename(2), unlink(2), utimes(2) and write(2) system calls.
+         * 
+         * @return Seconds since the epoch.
+         */
+        public long getLastStatusChange()
+        {
+            return lastStatusChange.getSecs();
+        }
+
         public long getSize()
         {
             return size;
@@ -369,8 +564,31 @@ public final class Unix
                 operation, filename, errorMessage)));
     }
 
+    private static void throwRuntimeException(String operation, String errorMessage)
+    {
+        throw new RuntimeException(String.format("Error on %s: %s", operation, errorMessage));
+    }
+
     private static native int init();
 
+    public static boolean isUseUnixRealtimeTimer()
+    {
+        return useUnixRealtimeTimer;
+    }
+
+    /**
+     * Sets whether to use the Unix realttime timer.
+     * <p>
+     * <i>Note that old versions of Linux and MacOSX do not yet support this and will terminate the Java program when 
+     * this flag is set to <code>true</code> and {@link #getSystemTime()} is called!</i>
+     * @param useUnixRealTimeTimer if <code>true</code>, the realtime timer (nano-second resolution) will be used, 
+     * otherwise the regular timer (micro-second resolution) will be used.
+     */
+    public static void setUseUnixRealtimeTimer(boolean useUnixRealTimeTimer)
+    {
+        Unix.useUnixRealtimeTimer = useUnixRealTimeTimer;
+    }
+
     private static native int getpid();
 
     private static native int getuid();
@@ -395,6 +613,20 @@ public final class Unix
 
     private static native int chown(String filename, int uid, int gid);
 
+    private static native int lchown(String filename, int uid, int gid);
+
+    private static native int clock_gettime(final long[] time);
+    
+    private static native int clock_gettime2(final long[] time);
+    
+    private static native int lutimes(String filename,
+            long accessTimeSecs, long accessTimeMicroSecs,
+            long modificationTimeSecs, long modificationTimeMicroSecs);
+
+    private static native int utimes(String filename,
+            long accessTimeSecs, long accessTimeMicroSecs,
+            long modificationTimeSecs, long modificationTimeMicroSecs);
+
     private static native String getuser(int uid);
 
     private static native String getgroup(int gid);
@@ -414,7 +646,7 @@ public final class Unix
     private static native String strerror(int errnum);
 
     private static native String strerror();
-
+    
     @Private
     static boolean isProcessRunningProcFS(int pid)
     {
@@ -426,8 +658,7 @@ public final class Unix
     {
         try
         {
-            return Runtime.getRuntime().exec(new String[]
-                { "ps", "-p", Integer.toString(pid) }).waitFor() == 0;
+            return Runtime.getRuntime().exec(new String[] { "ps", "-p", Integer.toString(pid) }).waitFor() == 0;
         } catch (IOException ex)
         {
             return false;
@@ -442,8 +673,8 @@ public final class Unix
     //
 
     /**
-     * Returns <code>true</code>, if the native library has been loaded successfully and the link
-     * utilities are operational, <code>false</code> otherwise.
+     * Returns <code>true</code>, if the native library has been loaded successfully and the link utilities are operational, <code>false</code>
+     * otherwise.
      */
     public static final boolean isOperational()
     {
@@ -459,9 +690,8 @@ public final class Unix
     }
 
     /**
-     * Returns the last error that occurred in this class. Use this to find out what went wrong
-     * after {@link #tryGetLinkInfo(String)} or {@link #tryGetFileInfo(String)} returned
-     * <code>null</code>.
+     * Returns the last error that occurred in this class. Use this to find out what went wrong after {@link #tryGetLinkInfo(String)} or
+     * {@link #tryGetFileInfo(String)} returned <code>null</code>.
      */
     public static String getLastError()
     {
@@ -481,9 +711,8 @@ public final class Unix
     }
 
     /**
-     * Returns <code>true</code>, if the process with <var>pid</var> is currently running and
-     * <code>false</code>, if it is not running or if process detection is not available (
-     * {@link #canDetectProcesses()} <code>== false</code>).
+     * Returns <code>true</code>, if the process with <var>pid</var> is currently running and <code>false</code>, if it is not running or if process
+     * detection is not available ( {@link #canDetectProcesses()} <code>== false</code>).
      */
     public static boolean isProcessRunning(int pid)
     {
@@ -530,6 +759,37 @@ public final class Unix
         return getegid();
     }
 
+    //
+    // Time functions
+    //
+
+    /**
+     * Gets the current system time.
+     * 
+     * @return the system time as <i>seconds since the epoch</i> and, in addition, 
+     *         nano-seconds since the current second.
+     */
+    public static final Time getSystemTime()
+    {
+        final long[] time = new long[2];
+        final int result = useUnixRealtimeTimer ? clock_gettime(time) : clock_gettime2(time);
+        if (result < 0)
+        {
+            throwRuntimeException("get system time", strerror(result));
+        }
+        return new Time(time[0], time[1]);
+    }
+    
+    /**
+     * Gets the current system time.
+     * 
+     * @return the system time as <i>milli-seconds since the epoch</i>.
+     */
+    public static final long getSystemTimeMillis()
+    {
+        return getSystemTime().getMillis();
+    }
+    
     //
     // File functions
     //
@@ -537,8 +797,8 @@ public final class Unix
     /**
      * Creates a hard link <var>linkName</var> that points to <var>fileName</var>.
      * 
-     * @throws IOExceptionUnchecked If the underlying system call fails, e.g. because
-     *             <var>linkName</var> already exists or <var>fileName</var> does not exist.
+     * @throws IOExceptionUnchecked If the underlying system call fails, e.g. because <var>linkName</var> already exists or <var>fileName</var> does
+     *             not exist.
      */
     public static final void createHardLink(String fileName, String linkName)
             throws IOExceptionUnchecked
@@ -561,8 +821,7 @@ public final class Unix
     /**
      * Creates a symbolic link <var>linkName</var> that points to <var>fileName</var>.
      * 
-     * @throws IOExceptionUnchecked If the underlying system call fails, e.g. because
-     *             <var>linkName</var> already exists.
+     * @throws IOExceptionUnchecked If the underlying system call fails, e.g. because <var>linkName</var> already exists.
      */
     public static final void createSymbolicLink(String fileName, String linkName)
             throws IOExceptionUnchecked
@@ -629,45 +888,45 @@ public final class Unix
     }
 
     /**
-     * Returns the inode for the <var>fileName</var>.
+     * Returns the inode for the <var>fileName</var>. Does not dereference a symbolic link. 
+     * 
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link does not exist.
      * 
-     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
-     *             does not exist.
+     * @deprecated Use method {@link Stat#getInode(String)} from {@link #getLinkInfo(String)} instead.
      */
-    public static final long getInode(String fileName) throws IOExceptionUnchecked
+    @Deprecated
+    public static final long getInode(String linkName) throws IOExceptionUnchecked
     {
-        return getLStat(fileName).getInode();
+        return getLStat(linkName).getInode();
     }
 
     /**
-     * Returns the number of hard links for the <var>fileName</var>.
+     * Returns the number of hard links for the <var>linkName</var>. Does not dereference a symbolic link.
      * 
-     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
-     *             does not exist.
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link does not exist.
+     * 
+     * @deprecated Use method {@link Stat#getNumberOfHardLinks(String)} from {@link #getLinkInfo(String)} instead.
      */
-    public static final int getNumberOfHardLinks(String fileName) throws IOExceptionUnchecked
+    @Deprecated
+    public static final int getNumberOfHardLinks(String linkName) throws IOExceptionUnchecked
     {
-        return getLStat(fileName).getNumberOfHardLinks();
+        return getLStat(linkName).getNumberOfHardLinks();
     }
 
     /**
-     * Returns <code>true</code> if <var>fileName</var> is a symbolic link and <code>false</code>
-     * otherwise.
+     * Returns <code>true</code> if <var>linkName</var> is a symbolic link and <code>false</code> otherwise.
      * 
-     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
-     *             does not exist.
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link does not exist.
      */
-    public static final boolean isSymbolicLink(String fileName) throws IOExceptionUnchecked
+    public static final boolean isSymbolicLink(String linkName) throws IOExceptionUnchecked
     {
-        return getLStat(fileName).isSymbolicLink();
+        return getLStat(linkName).isSymbolicLink();
     }
 
     /**
-     * Returns the value of the symbolik link <var>linkName</var>, or <code>null</code>, if
-     * <var>linkName</var> is not a symbolic link.
+     * Returns the value of the symbolik link <var>linkName</var>, or <code>null</code>, if <var>linkName</var> is not a symbolic link.
      * 
-     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
-     *             does not exist.
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link does not exist.
      */
     public static final String tryReadSymbolicLink(String linkName) throws IOExceptionUnchecked
     {
@@ -678,8 +937,7 @@ public final class Unix
     /**
      * Returns the information about <var>fileName</var>.
      * 
-     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the file
-     *             does not exist.
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the file does not exist.
      */
     public static final Stat getFileInfo(String fileName) throws IOExceptionUnchecked
     {
@@ -687,9 +945,8 @@ public final class Unix
     }
 
     /**
-     * Returns the information about <var>fileName</var>, or {@link NullPointerException}, if the
-     * information could not be obtained, e.g. because the file does not exist (call
-     * {@link #getLastError()} to find out what went wrong).
+     * Returns the information about <var>fileName</var>, or {@link NullPointerException}, if the information could not be obtained, e.g. because the
+     * file does not exist (call {@link #getLastError()} to find out what went wrong).
      */
     public static final Stat tryGetFileInfo(String fileName) throws IOExceptionUnchecked
     {
@@ -699,8 +956,7 @@ public final class Unix
     /**
      * Returns the information about <var>linkName</var>.
      * 
-     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
-     *             does not exist.
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link does not exist.
      */
     public static final Stat getLinkInfo(String linkName) throws IOExceptionUnchecked
     {
@@ -708,12 +964,10 @@ public final class Unix
     }
 
     /**
-     * Returns the information about <var>linkName</var>. If
-     * <code>readSymbolicLinkTarget == true</code>, then the symbolic link target is read when
+     * Returns the information about <var>linkName</var>. If <code>readSymbolicLinkTarget == true</code>, then the symbolic link target is read when
      * <var>linkName</var> is a symbolic link.
      * 
-     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
-     *             does not exist.
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link does not exist.
      */
     public static final Stat getLinkInfo(String linkName, boolean readSymbolicLinkTarget)
             throws IOExceptionUnchecked
@@ -727,9 +981,8 @@ public final class Unix
     }
 
     /**
-     * Returns the information about <var>linkName</var>, or {@link NullPointerException}, if the
-     * information could not be obtained, e.g. because the link does not exist (call
-     * {@link #getLastError()} to find out what went wrong).
+     * Returns the information about <var>linkName</var>, or {@link NullPointerException}, if the information could not be obtained, e.g. because the
+     * link does not exist (call {@link #getLastError()} to find out what went wrong).
      */
     public static final Stat tryGetLinkInfo(String linkName) throws IOExceptionUnchecked
     {
@@ -737,10 +990,9 @@ public final class Unix
     }
 
     /**
-     * Returns the information about <var>linkName</var>, or <code>null</code> if the information
-     * can not be obtained, e.g. because the link does not exist (call {@link #getLastError()} to
-     * find out what went wrong). If <code>readSymbolicLinkTarget == true</code>, then the symbolic
-     * link target is read when <var>linkName</var> is a symbolic link.
+     * Returns the information about <var>linkName</var>, or <code>null</code> if the information can not be obtained, e.g. because the link does not
+     * exist (call {@link #getLastError()} to find out what went wrong). If <code>readSymbolicLinkTarget == true</code>, then the symbolic link target
+     * is read when <var>linkName</var> is a symbolic link.
      */
     public static final Stat tryGetLinkInfo(String linkName, boolean readSymbolicLinkTarget)
             throws IOExceptionUnchecked
@@ -759,6 +1011,7 @@ public final class Unix
 
     /**
      * Sets the access mode of <var>filename</var> to the specified <var>mode</var> value.
+     * Dereferences a symbolic link.
      */
     public static final void setAccessMode(String fileName, short mode) throws IOExceptionUnchecked
     {
@@ -774,8 +1027,8 @@ public final class Unix
     }
 
     /**
-     * Sets the owner of <var>filename</var> to the specified <var>uid</var> and <var>gid</var>
-     * values.
+     * Sets the owner of <var>fileName</var> to the specified <var>uid</var> and <var>gid</var> values. 
+     * Dereferences a symbolic link.
      */
     public static final void setOwner(String fileName, int uid, int gid)
             throws IOExceptionUnchecked
@@ -791,6 +1044,186 @@ public final class Unix
         }
     }
 
+    /**
+     * Sets the owner of <var>fileName</var> to the <var>uid</var> and <var>gid</var> of the specified <code>user</code>. 
+     * Dereferences a symbolic link.
+     */
+    public static final void setOwner(String fileName, Password user)
+            throws IOExceptionUnchecked
+    {
+        if (fileName == null)
+        {
+            throw new NullPointerException("fileName");
+        }
+        final int result = chown(fileName, user.getUid(), user.getGid());
+        if (result < 0)
+        {
+            throwFileException("set owner", fileName, strerror(result));
+        }
+    }
+
+    /**
+     * Sets the owner of <var>linkName</var> to the specified <var>uid</var> and <var>gid</var> values. 
+     * Does not dereference a symbolic link.
+     */
+    public static final void setLinkOwner(String linkName, int uid, int gid)
+            throws IOExceptionUnchecked
+    {
+        if (linkName == null)
+        {
+            throw new NullPointerException("linkName");
+        }
+        final int result = lchown(linkName, uid, gid);
+        if (result < 0)
+        {
+            throwFileException("set link owner", linkName, strerror(result));
+        }
+    }
+
+    /**
+     * Sets the owner of <var>linkName</var> to the <var>uid</var> and <var>gid</var> of the specified <code>user</code>. 
+     * Does not dereference a symbolic link.
+     */
+    public static final void setLinkOwner(String linkName, Password user)
+            throws IOExceptionUnchecked
+    {
+        if (linkName == null)
+        {
+            throw new NullPointerException("linkName");
+        }
+        final int result = lchown(linkName, user.getUid(), user.getGid());
+        if (result < 0)
+        {
+            throwFileException("set owner", linkName, strerror(result));
+        }
+    }
+
+    /**
+     * Change link timestamps of a file, directory or link. Does not dereference a symbolic link.
+     * 
+     * @param fileName The name of the file or link to change the timestamp of.
+     * @param accessTimeSecs The new access time in seconds since start of the epoch.
+     * @param accessTimeMicroSecs The micro-second part of the new access time.
+     * @param modificationTimeSecs The new modification time in seconds since start of the epoch.
+     * @param modificationTimeMicroSecs The micro-second part of the new modification time.
+     */
+    public static void setLinkTimestamps(String fileName,
+            long accessTimeSecs, long accessTimeMicroSecs,
+            long modificationTimeSecs, long modificationTimeMicroSecs) throws IOExceptionUnchecked
+    {
+        final int result = lutimes(fileName, accessTimeSecs, accessTimeMicroSecs,
+                            modificationTimeSecs, modificationTimeMicroSecs);
+        if (result < 0)
+        {
+            throwFileException("set file timestamps", fileName, strerror(result));
+        }
+    }
+
+    /**
+     * Change file timestamps of a file, directory or link. Does not dereference a symbolic link.
+     * 
+     * @param fileName The name of the file or link to change the timestamp of.
+     * @param accessTimeSecs The new access time in seconds since start of the epoch.
+     * @param modificationTimeSecs The new modification time in seconds since start of the epoch.
+     */
+    public static void setLinkTimestamps(String fileName,
+            long accessTimeSecs, long modificationTimeSecs) throws IOExceptionUnchecked
+    {
+        setLinkTimestamps(fileName, accessTimeSecs, 0, modificationTimeSecs, 0);
+    }
+
+    /**
+     * Change file timestamps of a file, directory or link. Does not dereference a symbolic link.
+     * 
+     * @param fileName The name of the file or link to change the timestamp of.
+     * @param accessTime The new access time as {@link Time} object.
+     * @param modificationTime The new modification time as {@link Time} object.
+     */
+    public static void setLinkTimestamps(String fileName,
+            Time accessTime, Time modificationTime) throws IOExceptionUnchecked
+    {
+        setLinkTimestamps(fileName, accessTime.getSecs(), accessTime.getMicroSecPart(), 
+                modificationTime.getSecs(), modificationTime.getMicroSecPart());
+    }
+
+    /**
+     * Change file timestamps of a file, directory or link to the current time. Does not dereference a symbolic link.
+     * 
+     * @param fileName The name of the file or link to change the timestamp of.
+     */
+    public static void setLinkTimestamps(String fileName) throws IOExceptionUnchecked
+    {
+        final Time now = getSystemTime();
+        final int result = lutimes(fileName, now.getSecs(), now.getMicroSecPart(), now.getSecs(), now.getMicroSecPart());
+        if (result < 0)
+        {
+            throwFileException("set file timestamps", fileName, strerror(result));
+        }
+    }
+
+    /**
+     * Change file timestamps of a file, directory or link. Dereferences a symbolic link.
+     * 
+     * @param fileName The name of the file or link to change the timestamp of.
+     * @param accessTimeSecs The new access time in seconds since start of the epoch.
+     * @param accessTimeMicroSecs The micro-second part of the new access time.
+     * @param modificationTimeSecs The new modification time in seconds since start of the epoch.
+     * @param modificationTimeMicroSecs The micro-second part of the new modification time.
+     */
+    public static void setFileTimestamps(String fileName,
+            long accessTimeSecs, long accessTimeMicroSecs,
+            long modificationTimeSecs, long modificationTimeMicroSecs) throws IOExceptionUnchecked
+    {
+        final int result = utimes(fileName, accessTimeSecs, accessTimeMicroSecs,
+                            modificationTimeSecs, modificationTimeMicroSecs);
+        if (result < 0)
+        {
+            throwFileException("set file timestamps", fileName, strerror(result));
+        }
+    }
+
+    /**
+     * Change file timestamps of a file, directory or link. Does not dereference a symbolic link.
+     * 
+     * @param fileName The name of the file or link to change the timestamp of.
+     * @param accessTimeSecs The new access time in seconds since start of the epoch.
+     * @param modificationTimeSecs The new modification time in seconds since start of the epoch.
+     */
+    public static void setFileTimestamps(String fileName,
+            long accessTimeSecs, long modificationTimeSecs) throws IOExceptionUnchecked
+    {
+        setFileTimestamps(fileName, accessTimeSecs, 0, modificationTimeSecs, 0);
+    }
+
+    /**
+     * Change file timestamps of a file, directory or link. Does not dereference a symbolic link.
+     * 
+     * @param fileName The name of the file or link to change the timestamp of.
+     * @param accessTime The new access time as {@link Time} object.
+     * @param modificationTime The new modification time as {@link Time} object.
+     */
+    public static void setFileTimestamps(String fileName,
+            Time accessTime, Time modificationTime) throws IOExceptionUnchecked
+    {
+        setFileTimestamps(fileName, accessTime.getSecs(), accessTime.getMicroSecPart(), 
+                modificationTime.getSecs(), modificationTime.getMicroSecPart());
+    }
+
+    /**
+     * Change file timestamps of a file, directory or link to the current time. Does not dereference a symbolic link.
+     * 
+     * @param fileName The name of the file or link to change the timestamp of.
+     */
+    public static void setFileTimestamps(String fileName) throws IOExceptionUnchecked
+    {
+        final Time now = getSystemTime();
+        final int result = utimes(fileName, now.getSecs(), now.getMicroSecPart(), now.getSecs(), now.getMicroSecPart());
+        if (result < 0)
+        {
+            throwFileException("set file timestamps", fileName, strerror(result));
+        }
+    }
+
     //
     // User functions
     //
@@ -804,8 +1237,7 @@ public final class Unix
     }
 
     /**
-     * Returns the uid of the <var>userName</var>, or <code>-1</code>, if no user with this name
-     * exists.
+     * Returns the uid of the <var>userName</var>, or <code>-1</code>, if no user with this name exists.
      */
     public static final int getUidForUserName(String userName)
     {
@@ -817,8 +1249,7 @@ public final class Unix
     }
 
     /**
-     * Returns the {@link Password} for the given <var>userName</var>, or <code>null</code>, if no
-     * user with that name exists.
+     * Returns the {@link Password} for the given <var>userName</var>, or <code>null</code>, if no user with that name exists.
      */
     public static final Password tryGetUserByName(String userName)
     {
@@ -830,8 +1261,7 @@ public final class Unix
     }
 
     /**
-     * Returns the {@link Password} for the given <var>userName</var>, or <code>null</code>, if no
-     * user with that name exists.
+     * Returns the {@link Password} for the given <var>userName</var>, or <code>null</code>, if no user with that name exists.
      */
     public static final Password tryGetUserByUid(int uid)
     {
@@ -843,8 +1273,7 @@ public final class Unix
     //
 
     /**
-     * Returns the name of the group identified by <var>gid</var>, or <code>null</code>, if no group
-     * with that <var>gid</var> exists.
+     * Returns the name of the group identified by <var>gid</var>, or <code>null</code>, if no group with that <var>gid</var> exists.
      */
     public static final String tryGetGroupNameForGid(int gid)
     {
@@ -852,8 +1281,7 @@ public final class Unix
     }
 
     /**
-     * Returns the gid of the <var>groupName</var>, or <code>-1</code>, if no group with this name
-     * exists.
+     * Returns the gid of the <var>groupName</var>, or <code>-1</code>, if no group with this name exists.
      */
     public static final int getGidForGroupName(String groupName)
     {
@@ -865,8 +1293,7 @@ public final class Unix
     }
 
     /**
-     * Returns the {@link Group} for the given <var>groupName</var>, or <code>null</code>, if no
-     * group with that name exists.
+     * Returns the {@link Group} for the given <var>groupName</var>, or <code>null</code>, if no group with that name exists.
      */
     public static final Group tryGetGroupByName(String groupName)
     {
@@ -878,8 +1305,7 @@ public final class Unix
     }
 
     /**
-     * Returns the {@link Group} for the given <var>gid</var>, or <code>null</code>, if no group
-     * with that gid exists.
+     * Returns the {@link Group} for the given <var>gid</var>, or <code>null</code>, if no group with that gid exists.
      */
     public static final Group tryGetGroupByGid(int gid)
     {


=====================================
sourceTest/java/ch/systemsx/cisd/base/AllTests.java
=====================================
@@ -24,6 +24,7 @@ import ch.systemsx.cisd.base.io.RandomAccessFileImplTests;
 import ch.systemsx.cisd.base.mdarray.MDArrayTests;
 import ch.systemsx.cisd.base.namedthread.NamingThreadPoolExecutorTest;
 import ch.systemsx.cisd.base.unix.Unix;
+import ch.systemsx.cisd.base.unix.UnixRootTests;
 import ch.systemsx.cisd.base.unix.UnixTests;
 
 /**
@@ -53,6 +54,7 @@ public class AllTests
         if (Unix.isOperational())
         {
             UnixTests.main(args);
+            UnixRootTests.main(args);
         } else
         {
             System.err.println("No unix library found.");


=====================================
sourceTest/java/ch/systemsx/cisd/base/unix/UnixRootTests.java
=====================================
@@ -0,0 +1,108 @@
+package ch.systemsx.cisd.base.unix;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.charset.Charset;
+
+import org.apache.commons.io.FileUtils;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
+import ch.systemsx.cisd.base.unix.Unix.Stat;
+
+/**
+ * Tests of the {@link Unix} class that can only be performed as user root.
+ */
+public class UnixRootTests extends AbstractFileSystemTestCase
+{
+    @Test(groups =
+        { "requires_unix" })
+    public void testChown() throws IOException
+    {
+        if (Unix.getUid() != 0)
+        {
+            System.out.println("Skipping test as we are not root.");
+            return;
+        }
+        final short accessMode = (short) 0777;
+        final String content = "someText\n";
+        final File f = new File(workingDirectory, "someFile");
+        final File s = new File(workingDirectory, "MyLink");
+        FileUtils.writeStringToFile(f, content, Charset.defaultCharset());
+        Unix.setAccessMode(f.getAbsolutePath(), accessMode);
+        final Stat info = Unix.getLinkInfo(f.getAbsolutePath());
+        Unix.setOwner(f.getAbsolutePath(), info.getUid(), info.getGid());
+        assertEquals(1, info.getNumberOfHardLinks());
+        assertEquals(content.length(), info.getSize());
+        assertEquals(accessMode, info.getPermissions());
+        final Unix.Password nobody = Unix.tryGetUserByName("nobody");
+        assertNotNull(nobody);
+        final Unix.Password daemon = Unix.tryGetUserByName("daemon");
+        assertNotNull(daemon);
+        Unix.setOwner(f.getAbsolutePath(), nobody);
+        Unix.createSymbolicLink(f.getAbsolutePath(), s.getAbsolutePath());
+        Unix.setLinkOwner(s.getAbsolutePath(), daemon);
+
+        final Unix.Stat fileInfo = Unix.getFileInfo(s.getAbsolutePath());
+        assertEquals(nobody.getUid(), fileInfo.getUid());
+        assertEquals(nobody.getGid(), fileInfo.getGid());
+        
+        final Unix.Stat linkInfo = Unix.getLinkInfo(s.getAbsolutePath());
+        assertEquals(daemon.getUid(), linkInfo.getUid());
+        assertEquals(daemon.getGid(), linkInfo.getGid());
+    }
+    
+    public static void main(String[] args)  throws Throwable
+    {
+        System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+        System.out.println("Test class: " + UnixRootTests.class.getSimpleName());
+        System.out.println();
+        if (Unix.isOperational() == false)
+        {
+            System.err.println("No unix library found.");
+            System.exit(1);
+        }
+        final UnixRootTests test = new UnixRootTests();
+        try
+        {
+            for (Method m : UnixRootTests.class.getMethods())
+            {
+                final Test testAnnotation = m.getAnnotation(Test.class);
+                if (testAnnotation == null)
+                {
+                    continue;
+                }
+                System.out.println("Running " + m.getName());
+                test.setUp();
+                try
+                {
+                    m.invoke(test);
+                } catch (InvocationTargetException wrapperThrowable)
+                {
+                    final Throwable th = wrapperThrowable.getCause();
+                    boolean exceptionFound = false;
+                    for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+                    {
+                        if (expectedExClazz == th.getClass())
+                        {
+                            exceptionFound = true;
+                            break;
+                        }
+                    }
+                    if (exceptionFound == false)
+                    {
+                        throw th;
+                    }
+                }
+            }
+            System.out.println("Tests OK!");
+        } finally
+        {
+            test.afterClass();
+        }
+    }
+
+}


=====================================
sourceTest/java/ch/systemsx/cisd/base/unix/UnixTests.java
=====================================
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.base.unix;
 
+import static org.testng.Assert.assertNotEquals;
+
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
@@ -40,6 +42,15 @@ import ch.systemsx.cisd.base.unix.Unix.Stat;
 @Friend(toClasses = Unix.class)
 public class UnixTests extends AbstractFileSystemTestCase
 {
+    private UnixTests()
+    {
+        super();
+    }
+
+    private UnixTests(boolean cleanAfterMethod)
+    {
+        super(cleanAfterMethod);
+    }
 
     @Test(groups =
         { "requires_unix" })
@@ -58,7 +69,7 @@ public class UnixTests extends AbstractFileSystemTestCase
         assertEquals("root", Unix.tryGetUserNameForUid(0));
         assertEquals(FileLinkType.REGULAR_FILE, info.getLinkType());
         assertFalse(info.isSymbolicLink());
-        assertEquals(f.lastModified(), 1000 * info.getLastModified());
+        assertEquals(f.lastModified()/1000, info.getLastModified());
     }
 
     @Test(groups =
@@ -105,6 +116,124 @@ public class UnixTests extends AbstractFileSystemTestCase
         assertNull(info2.tryGetSymbolicLink());
     }
 
+    @Test(groups =
+        { "requires_unix" })
+    public void testTouchSymLinkAndFileRealtimeTimer() throws IOException, InterruptedException
+    {
+        if (BuildAndEnvironmentInfo.INSTANCE.getOS().contains("2.6.32"))
+        {
+            System.out.println("  ...skipping as CentOS6 does not yet support the realtime timer.");
+            return;
+        }
+        Unix.setUseUnixRealtimeTimer(true);
+        final File f = new File(workingDirectory, "someOtherFile");
+        final String content = "someMoreText\n";
+        FileUtils.writeStringToFile(f, content, Charset.defaultCharset());
+        final File s = new File(workingDirectory, "someLink");
+        Unix.createSymbolicLink(f.getAbsolutePath(), s.getAbsolutePath());
+        final Stat info = Unix.getLinkInfo(s.getAbsolutePath());
+        assertEquals(1, info.getNumberOfHardLinks());
+        assertEquals(FileLinkType.SYMLINK, info.getLinkType());
+        assertTrue(info.isSymbolicLink());
+        assertEquals(f.getAbsolutePath(), info.tryGetSymbolicLink());
+        assertEquals(f.getAbsolutePath(), Unix.tryReadSymbolicLink(s.getAbsolutePath()));
+        assertNull(Unix.getLinkInfo(s.getAbsolutePath(), false).tryGetSymbolicLink());
+        final long lastMicros = info.getLastModifiedTime().getMicroSecPart();
+        final long newLastModifiedLink = info.getLastModifiedTime().getSecs() - 24 * 3600;
+        Unix.setLinkTimestamps(s.getAbsolutePath(), newLastModifiedLink, lastMicros, newLastModifiedLink, lastMicros);
+
+        final long newLastModifiedFile = info.getLastModifiedTime().getSecs() - 2 * 24 * 3600;
+        Unix.setFileTimestamps(f.getAbsolutePath(), newLastModifiedFile, lastMicros, newLastModifiedFile, lastMicros);
+
+        final Stat info2l = Unix.getLinkInfo(s.getAbsolutePath(), false);
+        assertEquals(newLastModifiedLink, info2l.getLastModifiedTime().getSecs());
+        assertEquals(lastMicros, info2l.getLastModifiedTime().getMicroSecPart());
+        assertEquals(newLastModifiedLink, info2l.getLastAccessTime().getSecs());
+        assertEquals(lastMicros, info2l.getLastAccessTime().getMicroSecPart());
+
+        final Stat info2f = Unix.getFileInfo(s.getAbsolutePath());
+        final Stat info2f2 = Unix.getLinkInfo(f.getAbsolutePath());
+        assertNotEquals(info2l.getLastModifiedTime(), info2f2.getLastModifiedTime());
+        assertEquals(info2f2.getLastModifiedTime(), info2f.getLastModifiedTime());
+        assertEquals(newLastModifiedFile, info2f.getLastModifiedTime().getSecs());
+        assertEquals(lastMicros, info2f.getLastModifiedTime().getMicroSecPart());
+        assertEquals(newLastModifiedFile, info2f.getLastAccessTime().getSecs());
+        assertEquals(lastMicros, info2f.getLastAccessTime().getMicroSecPart());
+
+        Thread.sleep(10);
+
+        final Unix.Time now1 = Unix.getSystemTime();
+        assertNotEquals(0, now1.getNanoSecPart() % 1_000);
+        Unix.setLinkTimestamps(s.getAbsolutePath());
+        final Unix.Time now2 = Unix.getSystemTime();
+        final Stat info3 = Unix.getLinkInfo(s.getAbsolutePath());
+        
+        assertTrue(now1.getSecs() <= info3.getLastModified() && info3.getLastModified() <= now2.getSecs());
+        assertTrue(now1.getMicroSecPart() <= info3.getLastModifiedTime().getMicroSecPart() && info.getLastModifiedTime().getMilliSecPart() <= now2.getMicroSecPart());
+        assertTrue(now1.getSecs() <= info3.getLastAccess() && info3.getLastAccess() <= now2.getSecs());
+        assertTrue(now1.getMicroSecPart() <= info3.getLastAccessTime().getMicroSecPart() && info.getLastAccessTime().getMilliSecPart() <= now2.getMicroSecPart());
+        assertNotEquals(lastMicros, info3.getLastModifiedTime().getMicroSecPart());
+        assertNotEquals(lastMicros, info3.getLastAccessTime().getMicroSecPart());
+
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testTouchSymLinkAndFile() throws IOException, InterruptedException
+    {
+        Unix.setUseUnixRealtimeTimer(false);
+        final File f = new File(workingDirectory, "someOtherFile");
+        final String content = "someMoreText\n";
+        FileUtils.writeStringToFile(f, content, Charset.defaultCharset());
+        final File s = new File(workingDirectory, "someLink");
+        Unix.createSymbolicLink(f.getAbsolutePath(), s.getAbsolutePath());
+        final Stat info = Unix.getLinkInfo(s.getAbsolutePath());
+        assertEquals(1, info.getNumberOfHardLinks());
+        assertEquals(FileLinkType.SYMLINK, info.getLinkType());
+        assertTrue(info.isSymbolicLink());
+        assertEquals(f.getAbsolutePath(), info.tryGetSymbolicLink());
+        assertEquals(f.getAbsolutePath(), Unix.tryReadSymbolicLink(s.getAbsolutePath()));
+        assertNull(Unix.getLinkInfo(s.getAbsolutePath(), false).tryGetSymbolicLink());
+        final long lastMicros = info.getLastModifiedTime().getMicroSecPart();
+        final long newLastModifiedLink = info.getLastModifiedTime().getSecs() - 24 * 3600;
+        Unix.setLinkTimestamps(s.getAbsolutePath(), newLastModifiedLink, lastMicros, newLastModifiedLink, lastMicros);
+
+        final long newLastModifiedFile = info.getLastModifiedTime().getSecs() - 2 * 24 * 3600;
+        Unix.setFileTimestamps(f.getAbsolutePath(), newLastModifiedFile, lastMicros, newLastModifiedFile, lastMicros);
+
+        final Stat info2l = Unix.getLinkInfo(s.getAbsolutePath(), false);
+        assertEquals(newLastModifiedLink, info2l.getLastModifiedTime().getSecs());
+        assertEquals(lastMicros, info2l.getLastModifiedTime().getMicroSecPart());
+        assertEquals(newLastModifiedLink, info2l.getLastAccessTime().getSecs());
+        assertEquals(lastMicros, info2l.getLastAccessTime().getMicroSecPart());
+
+        final Stat info2f = Unix.getFileInfo(s.getAbsolutePath());
+        final Stat info2f2 = Unix.getLinkInfo(f.getAbsolutePath());
+        assertNotEquals(info2l.getLastModifiedTime(), info2f2.getLastModifiedTime());
+        assertEquals(info2f2.getLastModifiedTime(), info2f.getLastModifiedTime());
+        assertEquals(newLastModifiedFile, info2f.getLastModifiedTime().getSecs());
+        assertEquals(lastMicros, info2f.getLastModifiedTime().getMicroSecPart());
+        assertEquals(newLastModifiedFile, info2f.getLastAccessTime().getSecs());
+        assertEquals(lastMicros, info2f.getLastAccessTime().getMicroSecPart());
+
+
+        Thread.sleep(10);
+
+        final Unix.Time now1 = Unix.getSystemTime();
+        assertEquals(0, now1.getNanoSecPart() % 1_000);
+        Unix.setLinkTimestamps(s.getAbsolutePath());
+        final Unix.Time now2 = Unix.getSystemTime();
+        final Stat info3 = Unix.getLinkInfo(s.getAbsolutePath());
+        
+        assertTrue(now1.getSecs() <= info3.getLastModified() && info3.getLastModified() <= now2.getSecs());
+        assertTrue(now1.getMicroSecPart() <= info3.getLastModifiedTime().getMicroSecPart() && info.getLastModifiedTime().getMilliSecPart() <= now2.getMicroSecPart());
+        assertTrue(now1.getSecs() <= info3.getLastAccess() && info3.getLastAccess() <= now2.getSecs());
+        assertTrue(now1.getMicroSecPart() <= info3.getLastAccessTime().getMicroSecPart() && info.getLastAccessTime().getMilliSecPart() <= now2.getMicroSecPart());
+        assertNotEquals(lastMicros, info3.getLastModifiedTime().getMicroSecPart());
+        assertNotEquals(lastMicros, info3.getLastAccessTime().getMicroSecPart());
+
+    }
+
     @Test(groups =
         { "requires_unix" })
     public void testGetLinkInfoSymLinkDanglingLink() throws IOException
@@ -167,14 +296,14 @@ public class UnixTests extends AbstractFileSystemTestCase
         { "requires_unix" })
     public void testGetUid()
     {
-        assertTrue(Unix.getUid() > 0);
+        assertTrue(Unix.getUid() >= 0);
     }
 
     @Test(groups =
         { "requires_unix" })
     public void testGetEuid()
     {
-        assertTrue(Unix.getEuid() > 0);
+        assertTrue(Unix.getEuid() >= 0);
         assertEquals(Unix.getUid(), Unix.getEuid());
     }
 
@@ -182,14 +311,14 @@ public class UnixTests extends AbstractFileSystemTestCase
         { "requires_unix" })
     public void testGetGid()
     {
-        assertTrue(Unix.getGid() > 0);
+        assertTrue(Unix.getGid() >= 0);
     }
 
     @Test(groups =
         { "requires_unix" })
     public void testGetEgid()
     {
-        assertTrue(Unix.getEgid() > 0);
+        assertTrue(Unix.getEgid() >= 0);
         assertEquals(Unix.getGid(), Unix.getEgid());
     }
 
@@ -309,6 +438,8 @@ public class UnixTests extends AbstractFileSystemTestCase
             System.err.println("No unix library found.");
             System.exit(1);
         }
+        boolean stopOnError = args.length > 0 && "stopOnError".equalsIgnoreCase(args[0]);
+        int failed = 0;
         final UnixTests test = new UnixTests();
         try
         {
@@ -338,14 +469,29 @@ public class UnixTests extends AbstractFileSystemTestCase
                     }
                     if (exceptionFound == false)
                     {
-                        throw th;
+                        ++failed;
+                        System.out.println("Caught exception in method " + m.getName());
+                        th.printStackTrace();
+                        if (stopOnError)
+                        {
+                            System.exit(1);
+                        }
                     }
                 }
             }
-            System.out.println("Tests OK!");
+            if (failed == 0)
+            {
+                System.out.println("Tests OK!");
+            } else
+            {   
+                System.out.printf("%d tests FAILED!\n", failed);
+            }
         } finally
         {
-            test.afterClass();
+            if (failed == 0)
+            {
+                test.afterClass();
+            }
         }
     }
 



View it on GitLab: https://salsa.debian.org/med-team/libsis-base-java/commit/e42bd7e6bfdb4d5c3a828f104a750d1794dd0905

-- 
View it on GitLab: https://salsa.debian.org/med-team/libsis-base-java/commit/e42bd7e6bfdb4d5c3a828f104a750d1794dd0905
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20180926/838b7c57/attachment-0001.html>


More information about the debian-med-commit mailing list