Merge branch 'stable-4.8' into stable-4.9
* stable-4.8: Silence boxing warning Prepare 4.5.5-SNAPSHOT builds JGit v4.5.4.201711221230-r Fix LockFile semantics when running on NFS Honor trustFolderStats also when reading packed-refs Prepare 4.5.4-SNAPSHOT builds JGit v4.5.3.201708160445-r Change-Id: I7cf2e48934195430b3945b6d74b092f93a3ccd36 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
commit
6858339c1e
|
@ -1,35 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<component id="org.eclipse.jgit.junit" version="2">
|
|
||||||
<resource path="src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java" type="org.eclipse.jgit.junit.LocalDiskRepositoryTestCase">
|
|
||||||
<filter comment="OK to use internal implementation in tests" id="643842064">
|
|
||||||
<message_arguments>
|
|
||||||
<message_argument value="FileRepository"/>
|
|
||||||
<message_argument value="LocalDiskRepositoryTestCase"/>
|
|
||||||
<message_argument value="createBareRepository()"/>
|
|
||||||
</message_arguments>
|
|
||||||
</filter>
|
|
||||||
<filter comment="OK to use internal implementation in tests" id="643842064">
|
|
||||||
<message_arguments>
|
|
||||||
<message_argument value="FileRepository"/>
|
|
||||||
<message_argument value="LocalDiskRepositoryTestCase"/>
|
|
||||||
<message_argument value="createRepository(boolean, boolean)"/>
|
|
||||||
</message_arguments>
|
|
||||||
</filter>
|
|
||||||
<filter comment="OK to use internal implementation in tests" id="643842064">
|
|
||||||
<message_arguments>
|
|
||||||
<message_argument value="FileRepository"/>
|
|
||||||
<message_argument value="LocalDiskRepositoryTestCase"/>
|
|
||||||
<message_argument value="createWorkRepository()"/>
|
|
||||||
</message_arguments>
|
|
||||||
</filter>
|
|
||||||
</resource>
|
|
||||||
<resource path="src/org/eclipse/jgit/junit/RepositoryTestCase.java" type="org.eclipse.jgit.junit.RepositoryTestCase">
|
|
||||||
<filter comment="OK to use internal implementation in tests" id="627060751">
|
|
||||||
<message_arguments>
|
|
||||||
<message_argument value="FileRepository"/>
|
|
||||||
<message_argument value="RepositoryTestCase"/>
|
|
||||||
<message_argument value="db"/>
|
|
||||||
</message_arguments>
|
|
||||||
</filter>
|
|
||||||
</resource>
|
|
||||||
</component>
|
|
|
@ -1,5 +1,32 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<component id="org.eclipse.jgit" version="2">
|
<component id="org.eclipse.jgit" version="2">
|
||||||
|
<resource path="src/org/eclipse/jgit/lib/ConfigConstants.java" type="org.eclipse.jgit.lib.ConfigConstants">
|
||||||
|
<filter id="336658481">
|
||||||
|
<message_arguments>
|
||||||
|
<message_argument value="org.eclipse.jgit.lib.ConfigConstants"/>
|
||||||
|
<message_argument value="CONFIG_KEY_IN_CORE_LIMIT"/>
|
||||||
|
</message_arguments>
|
||||||
|
</filter>
|
||||||
|
<filter id="336658481">
|
||||||
|
<message_arguments>
|
||||||
|
<message_argument value="org.eclipse.jgit.lib.ConfigConstants"/>
|
||||||
|
<message_argument value="CONFIG_KEY_SUPPORTSATOMICFILECREATION"/>
|
||||||
|
</message_arguments>
|
||||||
|
</filter>
|
||||||
|
<filter id="336658481">
|
||||||
|
<message_arguments>
|
||||||
|
<message_argument value="org.eclipse.jgit.lib.ConfigConstants"/>
|
||||||
|
<message_argument value="CONFIG_MERGE_SECTION"/>
|
||||||
|
</message_arguments>
|
||||||
|
</filter>
|
||||||
|
<filter id="1141899266">
|
||||||
|
<message_arguments>
|
||||||
|
<message_argument value="4.5"/>
|
||||||
|
<message_argument value="4.9"/>
|
||||||
|
<message_argument value="CONFIG_KEY_SUPPORTSATOMICFILECREATION"/>
|
||||||
|
</message_arguments>
|
||||||
|
</filter>
|
||||||
|
</resource>
|
||||||
<resource path="src/org/eclipse/jgit/lib/ReflogEntry.java" type="org.eclipse.jgit.lib.ReflogEntry">
|
<resource path="src/org/eclipse/jgit/lib/ReflogEntry.java" type="org.eclipse.jgit.lib.ReflogEntry">
|
||||||
<filter comment="adding enum constant does not break binary compatibility" id="403767336">
|
<filter comment="adding enum constant does not break binary compatibility" id="403767336">
|
||||||
<message_arguments>
|
<message_arguments>
|
||||||
|
@ -20,34 +47,6 @@
|
||||||
</message_arguments>
|
</message_arguments>
|
||||||
</filter>
|
</filter>
|
||||||
</resource>
|
</resource>
|
||||||
<resource path="src/org/eclipse/jgit/merge/MergeStrategy.java" type="org.eclipse.jgit.merge.MergeStrategy">
|
|
||||||
<filter comment="OSGi semantic versioning allows breaking implementors of an API in a minor version" id="336695337">
|
|
||||||
<message_arguments>
|
|
||||||
<message_argument value="org.eclipse.jgit.merge.MergeStrategy"/>
|
|
||||||
<message_argument value="newMerger(ObjectInserter, Config)"/>
|
|
||||||
</message_arguments>
|
|
||||||
</filter>
|
|
||||||
</resource>
|
|
||||||
<resource path="src/org/eclipse/jgit/merge/ResolveMerger.java" type="org.eclipse.jgit.merge.ResolveMerger">
|
|
||||||
<filter comment="OSGi semantic versioning allows breaking implementors of an API in a minor version" id="338792546">
|
|
||||||
<message_arguments>
|
|
||||||
<message_argument value="org.eclipse.jgit.merge.ResolveMerger"/>
|
|
||||||
<message_argument value="processEntry(CanonicalTreeParser, CanonicalTreeParser, CanonicalTreeParser, DirCacheBuildIterator, WorkingTreeIterator, boolean)"/>
|
|
||||||
</message_arguments>
|
|
||||||
</filter>
|
|
||||||
<filter id="1141899266">
|
|
||||||
<message_arguments>
|
|
||||||
<message_argument value="3.5"/>
|
|
||||||
<message_argument value="4.9"/>
|
|
||||||
<message_argument value="processEntry(CanonicalTreeParser, CanonicalTreeParser, CanonicalTreeParser, DirCacheBuildIterator, WorkingTreeIterator, boolean)"/>
|
|
||||||
</message_arguments>
|
|
||||||
</filter>
|
|
||||||
<filter id="1143996420">
|
|
||||||
<message_arguments>
|
|
||||||
<message_argument value="processEntry(CanonicalTreeParser, CanonicalTreeParser, CanonicalTreeParser, DirCacheBuildIterator, WorkingTreeIterator, boolean)"/>
|
|
||||||
</message_arguments>
|
|
||||||
</filter>
|
|
||||||
</resource>
|
|
||||||
<resource path="src/org/eclipse/jgit/transport/http/HttpConnection.java" type="org.eclipse.jgit.transport.http.HttpConnection">
|
<resource path="src/org/eclipse/jgit/transport/http/HttpConnection.java" type="org.eclipse.jgit.transport.http.HttpConnection">
|
||||||
<filter id="403767336">
|
<filter id="403767336">
|
||||||
<message_arguments>
|
<message_arguments>
|
||||||
|
@ -68,4 +67,20 @@
|
||||||
</message_arguments>
|
</message_arguments>
|
||||||
</filter>
|
</filter>
|
||||||
</resource>
|
</resource>
|
||||||
|
<resource path="src/org/eclipse/jgit/util/FS.java" type="org.eclipse.jgit.util.FS">
|
||||||
|
<filter id="1141899266">
|
||||||
|
<message_arguments>
|
||||||
|
<message_argument value="4.5"/>
|
||||||
|
<message_argument value="4.9"/>
|
||||||
|
<message_argument value="createNewFile(File)"/>
|
||||||
|
</message_arguments>
|
||||||
|
</filter>
|
||||||
|
<filter id="1141899266">
|
||||||
|
<message_arguments>
|
||||||
|
<message_argument value="4.5"/>
|
||||||
|
<message_argument value="4.9"/>
|
||||||
|
<message_argument value="supportsAtomicCreateNewFile()"/>
|
||||||
|
</message_arguments>
|
||||||
|
</filter>
|
||||||
|
</resource>
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -168,7 +168,7 @@ public LockFile(final File f) {
|
||||||
*/
|
*/
|
||||||
public boolean lock() throws IOException {
|
public boolean lock() throws IOException {
|
||||||
FileUtils.mkdirs(lck.getParentFile(), true);
|
FileUtils.mkdirs(lck.getParentFile(), true);
|
||||||
if (lck.createNewFile()) {
|
if (FS.DETECTED.createNewFile(lck)) {
|
||||||
haveLck = true;
|
haveLck = true;
|
||||||
try {
|
try {
|
||||||
os = new FileOutputStream(lck);
|
os = new FileOutputStream(lck);
|
||||||
|
|
|
@ -86,6 +86,7 @@
|
||||||
import org.eclipse.jgit.errors.ObjectWritingException;
|
import org.eclipse.jgit.errors.ObjectWritingException;
|
||||||
import org.eclipse.jgit.events.RefsChangedEvent;
|
import org.eclipse.jgit.events.RefsChangedEvent;
|
||||||
import org.eclipse.jgit.internal.JGitText;
|
import org.eclipse.jgit.internal.JGitText;
|
||||||
|
import org.eclipse.jgit.lib.ConfigConstants;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.ObjectIdRef;
|
import org.eclipse.jgit.lib.ObjectIdRef;
|
||||||
|
@ -901,14 +902,20 @@ else if (0 <= (idx = packed.find(dst.getName())))
|
||||||
}
|
}
|
||||||
|
|
||||||
private PackedRefList getPackedRefs() throws IOException {
|
private PackedRefList getPackedRefs() throws IOException {
|
||||||
|
boolean trustFolderStat = getRepository().getConfig().getBoolean(
|
||||||
|
ConfigConstants.CONFIG_CORE_SECTION,
|
||||||
|
ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT, true);
|
||||||
|
|
||||||
final PackedRefList curList = packedRefs.get();
|
final PackedRefList curList = packedRefs.get();
|
||||||
if (!curList.snapshot.isModified(packedRefsFile))
|
if (trustFolderStat && !curList.snapshot.isModified(packedRefsFile)) {
|
||||||
return curList;
|
return curList;
|
||||||
|
}
|
||||||
|
|
||||||
final PackedRefList newList = readPackedRefs();
|
final PackedRefList newList = readPackedRefs();
|
||||||
if (packedRefs.compareAndSet(curList, newList)
|
if (packedRefs.compareAndSet(curList, newList)
|
||||||
&& !curList.id.equals(newList.id))
|
&& !curList.id.equals(newList.id)) {
|
||||||
modCnt.incrementAndGet();
|
modCnt.incrementAndGet();
|
||||||
|
}
|
||||||
return newList;
|
return newList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -346,6 +346,13 @@ public class ConfigConstants {
|
||||||
*/
|
*/
|
||||||
public static final String CONFIG_KEY_TRUSTFOLDERSTAT = "trustfolderstat";
|
public static final String CONFIG_KEY_TRUSTFOLDERSTAT = "trustfolderstat";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "supportsAtomicFileCreation" key in the "core section"
|
||||||
|
*
|
||||||
|
* @since 4.5
|
||||||
|
*/
|
||||||
|
public static final String CONFIG_KEY_SUPPORTSATOMICFILECREATION = "supportsatomicfilecreation";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "noprefix" key in the "diff section"
|
* The "noprefix" key in the "diff section"
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
|
|
|
@ -235,6 +235,21 @@ protected FS(FS src) {
|
||||||
*/
|
*/
|
||||||
public abstract boolean supportsExecute();
|
public abstract boolean supportsExecute();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this file system support atomic file creation via
|
||||||
|
* java.io.File#createNewFile()? In certain environments (e.g. on NFS) it is
|
||||||
|
* not guaranteed that when two file system clients run createNewFile() in
|
||||||
|
* parallel only one will succeed. In such cases both clients may think they
|
||||||
|
* created a new file.
|
||||||
|
*
|
||||||
|
* @return true if this implementation support atomic creation of new
|
||||||
|
* Files by {@link File#createNewFile()}
|
||||||
|
* @since 4.5
|
||||||
|
*/
|
||||||
|
public boolean supportsAtomicCreateNewFile() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this operating system and JRE supports symbolic links. The
|
* Does this operating system and JRE supports symbolic links. The
|
||||||
* capability to handle symbolic links is detected at runtime.
|
* capability to handle symbolic links is detected at runtime.
|
||||||
|
@ -782,6 +797,22 @@ public void createSymLink(File path, String target) throws IOException {
|
||||||
FileUtils.createSymLink(path, target);
|
FileUtils.createSymLink(path, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new file. See {@link File#createNewFile()}. Subclasses of this
|
||||||
|
* class may take care to provide a safe implementation for this even if
|
||||||
|
* {@link #supportsAtomicCreateNewFile()} is <code>false</code>
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* the file to be created
|
||||||
|
* @return <code>true</code> if the file was created, <code>false</code> if
|
||||||
|
* the file already existed
|
||||||
|
* @throws IOException
|
||||||
|
* @since 4.5
|
||||||
|
*/
|
||||||
|
public boolean createNewFile(File path) throws IOException {
|
||||||
|
return path.createNewFile();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link FileUtils#relativizePath(String, String, String, boolean)}.
|
* See {@link FileUtils#relativizePath(String, String, String, boolean)}.
|
||||||
*
|
*
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.attribute.PosixFilePermission;
|
import java.nio.file.attribute.PosixFilePermission;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -58,8 +59,11 @@
|
||||||
|
|
||||||
import org.eclipse.jgit.api.errors.JGitInternalException;
|
import org.eclipse.jgit.api.errors.JGitInternalException;
|
||||||
import org.eclipse.jgit.errors.CommandFailedException;
|
import org.eclipse.jgit.errors.CommandFailedException;
|
||||||
|
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||||
|
import org.eclipse.jgit.lib.ConfigConstants;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
import org.eclipse.jgit.storage.file.FileBasedConfig;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -74,6 +78,10 @@ public class FS_POSIX extends FS {
|
||||||
private static final int DEFAULT_UMASK = 0022;
|
private static final int DEFAULT_UMASK = 0022;
|
||||||
private volatile int umask = -1;
|
private volatile int umask = -1;
|
||||||
|
|
||||||
|
private volatile boolean supportsUnixNLink = true;
|
||||||
|
|
||||||
|
private volatile Boolean supportsAtomicCreateNewFile;
|
||||||
|
|
||||||
/** Default constructor. */
|
/** Default constructor. */
|
||||||
protected FS_POSIX() {
|
protected FS_POSIX() {
|
||||||
}
|
}
|
||||||
|
@ -91,6 +99,34 @@ protected FS_POSIX(FS src) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("boxing")
|
||||||
|
private void determineAtomicFileCreationSupport() {
|
||||||
|
// @TODO: enhance SystemReader to support this without copying code
|
||||||
|
Boolean ret = getAtomicFileCreationSupportOption(
|
||||||
|
SystemReader.getInstance().openUserConfig(null, this));
|
||||||
|
if (ret == null && StringUtils.isEmptyOrNull(SystemReader.getInstance()
|
||||||
|
.getenv(Constants.GIT_CONFIG_NOSYSTEM_KEY))) {
|
||||||
|
ret = getAtomicFileCreationSupportOption(
|
||||||
|
SystemReader.getInstance().openSystemConfig(null, this));
|
||||||
|
}
|
||||||
|
supportsAtomicCreateNewFile = (ret == null) || ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean getAtomicFileCreationSupportOption(FileBasedConfig config) {
|
||||||
|
try {
|
||||||
|
config.load();
|
||||||
|
String value = config.getString(ConfigConstants.CONFIG_CORE_SECTION,
|
||||||
|
null,
|
||||||
|
ConfigConstants.CONFIG_KEY_SUPPORTSATOMICFILECREATION);
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Boolean.valueOf(StringUtils.toBoolean(value));
|
||||||
|
} catch (IOException | ConfigInvalidException e) {
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FS newInstance() {
|
public FS newInstance() {
|
||||||
return new FS_POSIX(this);
|
return new FS_POSIX(this);
|
||||||
|
@ -301,4 +337,56 @@ public File findHook(Repository repository, String hookName) {
|
||||||
return hookPath.toFile();
|
return hookPath.toFile();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsAtomicCreateNewFile() {
|
||||||
|
if (supportsAtomicCreateNewFile == null) {
|
||||||
|
determineAtomicFileCreationSupport();
|
||||||
|
}
|
||||||
|
return supportsAtomicCreateNewFile.booleanValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("boxing")
|
||||||
|
/**
|
||||||
|
* An implementation of the File#createNewFile() semantics which works also
|
||||||
|
* on NFS. If the config option
|
||||||
|
* {@code core.supportsAtomicCreateNewFile = true} (which is the default)
|
||||||
|
* then simply File#createNewFile() is called.
|
||||||
|
*
|
||||||
|
* But if {@code core.supportsAtomicCreateNewFile = false} then after
|
||||||
|
* successful creation of the lock file a hardlink to that lock file is
|
||||||
|
* created and the attribute nlink of the lock file is checked to be 2. If
|
||||||
|
* multiple clients manage to create the same lock file nlink would be
|
||||||
|
* greater than 2 showing the error.
|
||||||
|
*
|
||||||
|
* @see https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html
|
||||||
|
* @since 4.5
|
||||||
|
*/
|
||||||
|
public boolean createNewFile(File lock) throws IOException {
|
||||||
|
if (!lock.createNewFile()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (supportsAtomicCreateNewFile() || !supportsUnixNLink) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Path lockPath = lock.toPath();
|
||||||
|
Path link = Files.createLink(Paths.get(lock.getAbsolutePath() + ".lnk"), //$NON-NLS-1$
|
||||||
|
lockPath);
|
||||||
|
try {
|
||||||
|
Integer nlink = (Integer) (Files.getAttribute(lockPath,
|
||||||
|
"unix:nlink")); //$NON-NLS-1$
|
||||||
|
if (nlink != 2) {
|
||||||
|
LOG.warn("nlink of link to lock file {0} was not 2 but {1}", //$NON-NLS-1$
|
||||||
|
lock.getPath(), nlink);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (UnsupportedOperationException | IllegalArgumentException e) {
|
||||||
|
supportsUnixNLink = false;
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
Files.delete(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue