You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mt...@apache.org on 2009/04/21 08:39:32 UTC

svn commit: r767011 - in /commons/sandbox/runtime/trunk/src: main/java/org/apache/commons/runtime/io/File.java main/native/include/arch/windows/acr_arch.h main/native/os/unix/file.c main/native/os/win32/file.c test/org/apache/commons/runtime/TestFile.java

Author: mturk
Date: Tue Apr 21 06:39:32 2009
New Revision: 767011

URL: http://svn.apache.org/viewvc?rev=767011&view=rev
Log:
Add support for hard links

Modified:
    commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/io/File.java
    commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h
    commons/sandbox/runtime/trunk/src/main/native/os/unix/file.c
    commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c
    commons/sandbox/runtime/trunk/src/test/org/apache/commons/runtime/TestFile.java

Modified: commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/io/File.java
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/io/File.java?rev=767011&r1=767010&r2=767011&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/io/File.java (original)
+++ commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/io/File.java Tue Apr 21 06:39:32 2009
@@ -36,9 +36,10 @@
     private static native boolean   mkslink0(String target, String link)
                                         throws IOException, SecurityException,
                                                UnsupportedOperationException;
+    private static native boolean   mkhlink0(String target, String link)
+                                        throws IOException, SecurityException;
     private static native String    target0(String link)
-                                        throws IOException, SecurityException,
-                                               UnsupportedOperationException;
+                                        throws IOException, SecurityException;
 
     // Catched FileType Enum integer value.
     private int fileType = -1;
@@ -285,18 +286,75 @@
     }
 
     /**
+     * Creates a hard link named {@code link} which contains the string
+     * {@code target}.
+     * <p>
+     * This new name may be used exactly as the old one for any operation;
+     * both names refer to the same file (and so
+     * have the same permissions and ownership) and it is impossible to
+     * tell which name was the <em>original</em>.
+     * On some operating systems like
+     * {@code Microsoft Windows} this operation is only supported on the
+     * {@code NTFS} file system, and only for files, not directories.
+     * </p>
+     *
+     * @param target The abstract pathname of the existinf file.
+     * @param link The link name.
+     * @return {@code true} if hard link was created, false if it already
+     *         exists.
+     * @throws IOException in case of error.
+     * @throws SecurityException if Write access to the directory containing
+     *         {@code link} is denied, or one of the directories in the
+     *         path prefix of {@code link} did not allow search permission.
+     */
+    public static boolean createHardLink(String target, String link)
+        throws IOException, SecurityException
+    {
+        return mkhlink0(target, link);
+    }
+
+    /**
+     * Creates a new abstract {@code File} hard link instance with
+     * the path {@code link} which contains the string of this {@code File}
+     * isnstance pathname.
+     * <p>
+     * This new name may be used exactly as the old one for any operation;
+     * both names refer to the same file (and so
+     * have the same permissions and ownership) and it is impossible to
+     * tell which name was the <em>original</em>.
+     * On some operating systems like
+     * {@code Microsoft Windows} this operation is only supported on the
+     * {@code NTFS} file system, and only for files, not directories.
+     * </p>
+     *
+     * @param link The link name.
+     * @return New {@code File} instance containing hard link to this
+     *         file instance.
+     * @throws IOException in case of error.
+     * @throws SecurityException if Write access to the directory containing
+     *         {@code link} is denied, or one of the directories in the
+     *         path prefix of {@code link} did not allow search permission.
+     */
+    public File createHardLink(String link)
+        throws IOException, SecurityException
+    {
+        // False means EEXIST, so just consider it opened
+        // Check is made wather it points to the same target
+        mkhlink0(getPath(), link);
+        return new File(link, fileType);
+    }
+
+    /**
      * Return target pathname of this abstract {@code File} instance.
      *
      * @return Pathname this {@code File} points to.
-     * @throws IOException if this {@code File} is not symbolic link
+     * @throws IOException if this {@code File} is not symbolic or hard link
      *         or an I/O error occured.
      * @throws SecurityException if search permission is denied for a
      *         component of this abstract {@code File} pathname prefix.
-     * @throws UnsupportedOperationException if the operating system doesn't
-     *         support symbolic links.
      */
     public String getTargetPath()
-        throws IOException, SecurityException, UnsupportedOperationException
+        throws IOException, SecurityException
     {
         return target0(getPath());
     }
@@ -306,15 +364,13 @@
      * abstract {@code File} instance.
      *
      * @return New {@code File} instance this {@code File} points to.
-     * @throws IOException if this {@code File} is not symbolic link
+     * @throws IOException if this {@code File} is not symbolic or hard link
      *         or an I/O error occured.
      * @throws SecurityException if search permission is denied for a
      *         component of this abstract {@code File} pathname prefix.
-     * @throws UnsupportedOperationException if the operating system doesn't
-     *         support symbolic links.
      */
     public File getTargetFile()
-        throws IOException, SecurityException, UnsupportedOperationException
+        throws IOException, SecurityException
     {
         return new File(getTargetPath());
     }

Modified: commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h?rev=767011&r1=767010&r2=767011&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h Tue Apr 21 06:39:32 2009
@@ -96,8 +96,11 @@
 #pragma warning( default : 4201 )
 #endif
 
+#ifndef IO_REPARSE_TAG_MOUNT_POINT
+#define IO_REPARSE_TAG_MOUNT_POINT              (0xA0000003L)       
+#endif
 #ifndef IO_REPARSE_TAG_SYMLINK
-#define IO_REPARSE_TAG_SYMLINK  (0xA000000CL)
+#define IO_REPARSE_TAG_SYMLINK                  (0xA000000CL)
 #endif
 
 /*

Modified: commons/sandbox/runtime/trunk/src/main/native/os/unix/file.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/unix/file.c?rev=767011&r1=767010&r2=767011&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/unix/file.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/unix/file.c Tue Apr 21 06:39:32 2009
@@ -131,10 +131,38 @@
     WITH_CSTR(target) {
     WITH_CSTR(lnkname) {
         if (symlink(J2S(target), J2S(lnkname))) {
-            if (errno == EACCES)
+            int err = ACR_GET_OS_ERROR();
+            if (ACR_STATUS_IS_EACCES(err)) {
                 ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ESECURITY, 0);
-            else if (errno != EEXIST) {
-                ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EIO, errno);
+            }
+            else if (!ACR_STATUS_IS_EEXIST(err)) {
+                ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EIO, err);
+            }
+        }
+        else
+            rc = JNI_TRUE;
+    } END_WITH_CSTR(lnkname);
+    } END_WITH_CSTR(target);
+
+    return rc;
+}
+
+ACR_JNI_EXPORT_DECLARE(jboolean, io_File, mkhlink0)(ACR_JNISTDARGS,
+                                                    jstring target,
+                                                    jstring lnkname)
+{
+    jboolean rc = JNI_FALSE;
+
+    UNREFERENCED_O;
+    WITH_CSTR(target) {
+    WITH_CSTR(lnkname) {
+        if (link(J2S(target), J2S(lnkname))) {
+            int err = ACR_GET_OS_ERROR();
+            if (ACR_STATUS_IS_EACCES(err)) {
+                ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ESECURITY, 0);
+            }
+            else if (!ACR_STATUS_IS_EEXIST(err)) {
+                ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EIO, err);
             }
         }
         else

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c?rev=767011&r1=767010&r2=767011&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c Tue Apr 21 06:39:32 2009
@@ -116,12 +116,40 @@
     WITH_WSTR(target) {
     WITH_WSTR(lnkname) {
         DWORD dwFlags = 0;
-        if (J2W(target)[wcslen(J2W(target))] == L'\\')
+        size_t tlen = wcslen(J2W(target));
+        if (tlen > 0 && J2W(target)[tlen - 1] == L'\\')
             dwFlags = SYMBOLIC_LINK_FLAG_DIRECTORORY;
         if (!CreateSymbolicLinkW(J2W(lnkname), J2W(target), dwFlags)) {
             int err = ACR_GET_OS_ERROR();
-            if (ACR_STATUS_IS_EACCES(err))
+            if (ACR_STATUS_IS_EACCES(err)) {
                 ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ESECURITY, 0);
+            }
+            else if (!ACR_STATUS_IS_EEXIST(err)) {
+                ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EIO, err);
+            }
+        }
+        else
+            rc = JNI_TRUE;
+    } END_WITH_WSTR(lnkname);
+    } END_WITH_WSTR(target);
+
+    return rc;
+}
+
+ACR_JNI_EXPORT_DECLARE(jboolean, io_File, mkhlink0)(ACR_JNISTDARGS,
+                                                    jstring target,
+                                                    jstring lnkname)
+{
+    jboolean rc = JNI_FALSE;
+
+    UNREFERENCED_O;
+    WITH_WSTR(target) {
+    WITH_WSTR(lnkname) {
+        if (!CreateHardLinkW(J2W(lnkname), J2W(target), NULL)) {
+            int err = ACR_GET_OS_ERROR();
+            if (ACR_STATUS_IS_EACCES(err)) {
+                ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ESECURITY, 0);
+            }
             else if (!ACR_STATUS_IS_EEXIST(err)) {
                 ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EIO, err);
             }
@@ -140,10 +168,6 @@
     jstring rv = NULL;
 
     UNREFERENCED_O;
-    if (!ACR_HAVE_LATE_DLL_FUNC(CreateSymbolicLinkW)) {
-        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ENOTIMPL, 0);
-        return JNI_FALSE;
-    }
     WITH_WSTR(lnkname) {
         void *buf = ACR_Calloc(_E, THROW_FMARK, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
         if (buf) {
@@ -153,10 +177,11 @@
                                     NULL,
                                     OPEN_EXISTING,
                                     FILE_FLAG_OPEN_REPARSE_POINT,
-                                    NULL);    
+                                    NULL);
             if (sh != INVALID_HANDLE_VALUE) {
                 DWORD dl;
                 PREPARSE_DATA_BUFFER repb;
+                char *pb;
                 DeviceIoControl(sh,
                                 FSCTL_GET_REPARSE_POINT,
                                 NULL,
@@ -166,10 +191,17 @@
                                 &dl,
                                 NULL);
                 repb = (PREPARSE_DATA_BUFFER)buf;
-                if (repb->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
-                    char *pb = (char *)repb->SymbolicLinkReparseBuffer.PathBuffer;
-                    rv = (*_E)->NewString(_E, (const jchar *)(pb + repb->SymbolicLinkReparseBuffer.PrintNameOffset),
-                                          repb->SymbolicLinkReparseBuffer.PrintNameLength >> 1);
+                switch (repb->ReparseTag) {
+                    case IO_REPARSE_TAG_MOUNT_POINT:
+                        char *pb = (char *)repb->MountPointReparseBuffer.PathBuffer;
+                        rv = (*_E)->NewString(_E, (const jchar *)(pb + repb->MountPointReparseBuffer.SubstituteNameOffset),
+                                              repb->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
+                    break;
+                    case IO_REPARSE_TAG_SYMLINK:
+                        pb = (char *)repb->SymbolicLinkReparseBuffer.PathBuffer;
+                        rv = (*_E)->NewString(_E, (const jchar *)(pb + repb->SymbolicLinkReparseBuffer.SubstituteNameOffset),
+                                              repb->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
+                    break;
                 }
                 CloseHandle(sh);
             }

Modified: commons/sandbox/runtime/trunk/src/test/org/apache/commons/runtime/TestFile.java
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/test/org/apache/commons/runtime/TestFile.java?rev=767011&r1=767010&r2=767011&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/test/org/apache/commons/runtime/TestFile.java (original)
+++ commons/sandbox/runtime/trunk/src/test/org/apache/commons/runtime/TestFile.java Tue Apr 21 06:39:32 2009
@@ -145,4 +145,22 @@
 
     }
 
+    public void testMakeHardlink()
+        throws Exception
+    {
+        try {
+            boolean rc;
+            File target = new File("hfoo");
+            rc = target.createNewFile();
+            File hrdlnk = target.createHardLink("hbar");
+            FileType t = hrdlnk.getFileType();
+            assertEquals("Name", "hbar", hrdlnk.getPath());
+            assertEquals("Type", FileType.REG, t);
+            hrdlnk.delete();
+            target.delete();
+        } catch (UnsupportedOperationException u) {
+            // fail("Unsupported Operating system");
+        }
+    }
+
 }