From 041554fa5df287a64c075d71121ff4e76ddccee2 Mon Sep 17 00:00:00 2001 From: nlevitt Date: Fri, 24 Jun 2011 19:24:28 +0000 Subject: [PATCH] Fix for HER-1906 checkpointing gives error on Windows * HardLinker.java makeHardLink() - wrap unix link() and windows CreateHardLink() and choose depending on platform * BdbModule.java doCheckpoint() - use HardLinker.makeHardLink() --- .../main/java/org/archive/bdb/BdbModule.java | 4 +- .../java/org/archive/util/HardLinker.java | 95 +++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 commons/src/main/java/org/archive/util/HardLinker.java diff --git a/commons/src/main/java/org/archive/bdb/BdbModule.java b/commons/src/main/java/org/archive/bdb/BdbModule.java index 8b38db39..709ac7b2 100644 --- a/commons/src/main/java/org/archive/bdb/BdbModule.java +++ b/commons/src/main/java/org/archive/bdb/BdbModule.java @@ -43,6 +43,7 @@ import org.archive.checkpointing.Checkpoint; import org.archive.checkpointing.Checkpointable; import org.archive.spring.ConfigPath; import org.archive.util.CLibrary; +import org.archive.util.HardLinker; import org.archive.util.IdentityCacheable; import org.archive.util.ObjectIdentityBdbManualCache; import org.archive.util.ObjectIdentityCache; @@ -486,8 +487,7 @@ public class BdbModule implements Lifecycle, Checkpointable, Closeable { filedata[i] += ","+f.length(); if(getUseHardLinkCheckpoints()) { File hardLink = new File(envCpDir,filedata[i]); - int status = CLibrary.INSTANCE.link(f.getAbsolutePath(), hardLink.getAbsolutePath()); - if(status!=0) { + if (!HardLinker.makeHardLink(f.getAbsolutePath(), hardLink.getAbsolutePath())) { LOGGER.log(Level.SEVERE, "unable to create required checkpoint link "+hardLink); } } diff --git a/commons/src/main/java/org/archive/util/HardLinker.java b/commons/src/main/java/org/archive/util/HardLinker.java new file mode 100644 index 00000000..ad784ada --- /dev/null +++ b/commons/src/main/java/org/archive/util/HardLinker.java @@ -0,0 +1,95 @@ +/* + * This file is part of the Heritrix web crawler (crawler.archive.org). + * + * Licensed to the Internet Archive (IA) by one or more individual + * contributors. + * + * The IA licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.archive.util; +import java.io.File; +import java.io.IOException; + +import com.sun.jna.Native; +import com.sun.jna.Platform; +import com.sun.jna.Pointer; +import com.sun.jna.Structure; +import com.sun.jna.win32.StdCallLibrary; + +/** + * Wrapper for platform-dependent hard link creation. + * + * @see http://stackoverflow.com/questions/783075/creating-a-hard-link-in-java/3023349#3023349 + */ +public class HardLinker { + + // see https://github.com/twall/jna/blob/master/www/GettingStarted.md + public interface Kernel32Library extends StdCallLibrary { + Kernel32Library INSTANCE = (Kernel32Library) (Platform.isWindows() + ? Native.loadLibrary("kernel32", Kernel32Library.class) + : null); + + /* http://msdn.microsoft.com/en-us/library/aa379560%28VS.85%29.aspx + * http://en.wikipedia.org/wiki/Java_Native_Access + * + * typedef struct _SECURITY_ATTRIBUTES { + * DWORD nLength; + * LPVOID lpSecurityDescriptor; + * BOOL bInheritHandle; + * } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; + */ + public static class LPSECURITY_ATTRIBUTES extends Structure { + public int nLength; + public Pointer lpSecurityDescriptor; + public boolean bInheritHandle; + } + + /* + * http://msdn.microsoft.com/en-us/library/aa363860%28VS.85%29.aspx + * CreateHardLink is a macro that maps to CreateHardLinkA (ansi) or + * CreateHardLinkW (unicode). In initial testing CreateHardLinkW() + * worked, but then it stopped working... go figure. + */ + boolean CreateHardLinkA(String newPath, String existingPath, LPSECURITY_ATTRIBUTES lpSecurityAttributes); + // boolean CreateHardLinkW(String newPath, String existingPath, LPSECURITY_ATTRIBUTES lpSecurityAttributes); + } + + /** + * Wrapper over platform-dependent system calls to create a hard link. + * + * @return true on success + */ + public static boolean makeHardLink(String existingPath, String newPath) { + if (Platform.isWindows()) { + return Kernel32Library.INSTANCE.CreateHardLinkA(newPath, existingPath, null); + } else { + int status = CLibrary.INSTANCE.link(existingPath, newPath); + return status == 0; + } + } + + public static void main(String[] args) throws IOException { + File existingPath = File.createTempFile("heritrixHardLinkTestExistingFile", ".tmp"); + File newPath = File.createTempFile("heritrixHardLinkTestNewFile", ".tmp"); + newPath.delete(); + + if (HardLinker.makeHardLink(existingPath.getAbsolutePath(), newPath.getAbsolutePath())) { + System.out.println("success - made hard link from " + newPath.getAbsolutePath() + " to " + existingPath.getAbsolutePath()); + } else { + System.out.println("failed to make hard link from " + newPath.getAbsolutePath() + " to " + existingPath.getAbsolutePath()); + } + } +} + +