]> source.dussan.org Git - jgit.git/commitdiff
Fix concurrent read / write issue in LockFile on Windows 72/1172/5
authorJens Baumgart <jens.baumgart@sap.com>
Mon, 26 Jul 2010 08:18:47 +0000 (10:18 +0200)
committerShawn O. Pearce <spearce@spearce.org>
Tue, 27 Jul 2010 17:00:47 +0000 (10:00 -0700)
LockFile.commit fails if another thread concurrently reads
the base file. The problem is fixed by retrying the rename
operation if it fails.

Change-Id: I6bb76ea7f2e6e90e3ddc45f9dd4d69bd1b6fa1eb
Bug: 308506
Signed-off-by: Jens Baumgart <jens.baumgart@sap.com>
25 files changed:
org.eclipse.jgit.iplog/src/org/eclipse/jgit/iplog/IpLogMeta.java
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/eclipse/Iplog.java
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/eclipse/Ipzilla.java
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/RefUpdateTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/RepositorySetupWorkDirTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/T0003_Basic.java
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileRepository.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/LockFile.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/PackLock.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/RefDirectory.java
org.eclipse.jgit/src/org/eclipse/jgit/storage/file/RefDirectoryUpdate.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/IndexPack.java
org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java

index 2799a4a30b96efbb60038b79ca18b0ac232bb49c..372469da0424b24eb44cca0b98ff4c4c591198e6 100644 (file)
@@ -61,6 +61,7 @@ import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.storage.file.LockFile;
+import org.eclipse.jgit.util.FS;
 
 /**
  * Manages the {@code .eclipse_iplog} file in a project.
@@ -167,6 +168,9 @@ public class IpLogMeta {
         *
         * @param file
         *            local file to update with current CQ records.
+        * @param fs
+        *            the file system abstraction which will be necessary to perform
+        *            certain file system operations.
         * @param base
         *            base https:// URL of the IPzilla server.
         * @param username
@@ -181,16 +185,16 @@ public class IpLogMeta {
         *             the local file cannot be read, as it is not a valid
         *             configuration file format.
         */
-       public void syncCQs(File file, URL base, String username, String password)
-                       throws IOException, ConfigInvalidException {
+       public void syncCQs(File file, FS fs, URL base, String username,
+                       String password) throws IOException, ConfigInvalidException {
                if (!file.getParentFile().exists())
                        file.getParentFile().mkdirs();
 
-               LockFile lf = new LockFile(file);
+               LockFile lf = new LockFile(file, fs);
                if (!lf.lock())
                        throw new IOException(MessageFormat.format(IpLogText.get().cannotLock, file));
                try {
-                       FileBasedConfig cfg = new FileBasedConfig(file);
+                       FileBasedConfig cfg = new FileBasedConfig(file, fs);
                        cfg.load();
                        loadFrom(cfg);
 
index 2b82d82d74a4c0d9f284487450b50aaddebf9549..47956e5127486afad8d187b4309b3aab9b1ccb96 100644 (file)
@@ -69,6 +69,7 @@ import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.storage.file.FileRepository;
 import org.eclipse.jgit.storage.file.WindowCache;
 import org.eclipse.jgit.storage.file.WindowCacheConfig;
+import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.SystemReader;
 
@@ -128,7 +129,7 @@ public abstract class LocalDiskRepositoryTestCase extends TestCase {
 
                mockSystemReader = new MockSystemReader();
                mockSystemReader.userGitConfig = new FileBasedConfig(new File(trash,
-                               "usergitconfig"));
+                               "usergitconfig"), FS.DETECTED);
                ceilTestDirectories(getCeilings());
                SystemReader.setInstance(mockSystemReader);
 
index eb08417bc876a477395f8060a62aa628abe96a30..5c2e77f6737d391544a7de917c8da6eeb0fac074 100644 (file)
@@ -67,7 +67,7 @@ public class MockSystemReader extends SystemReader {
                init(Constants.GIT_AUTHOR_EMAIL_KEY);
                init(Constants.GIT_COMMITTER_NAME_KEY);
                init(Constants.GIT_COMMITTER_EMAIL_KEY);
-               userGitConfig = new FileBasedConfig(null) {
+               userGitConfig = new FileBasedConfig(null, null) {
                        @Override
                        public void load() throws IOException, ConfigInvalidException {
                                // Do nothing
index 3c582712577bbe2d8a1628bf1af240e567fb7d99..afe1c0bc63e1aa7e1e578e7e4eb0c7fa1b6cbf34 100644 (file)
@@ -654,7 +654,7 @@ public class TestRepository<R extends Repository> {
 
        private void writeFile(final File p, final byte[] bin) throws IOException,
                        ObjectWritingException {
-               final LockFile lck = new LockFile(p);
+               final LockFile lck = new LockFile(p, db.getFS());
                if (!lck.lock())
                        throw new ObjectWritingException("Can't write " + p);
                try {
index 5b75c1b5c5d3eb5936974011c39bc2b12fe89a7d..b8e2a8f6fac5866326576371df26db3f7ec0c41c 100644 (file)
@@ -227,7 +227,7 @@ class RebuildCommitGraph extends TextBuiltin {
                final ObjectId id = db.resolve(Constants.HEAD);
                if (!ObjectId.isId(head) && id != null) {
                        final LockFile lf;
-                       lf = new LockFile(new File(db.getDirectory(), Constants.HEAD));
+                       lf = new LockFile(new File(db.getDirectory(), Constants.HEAD), db.getFS());
                        if (!lf.lock())
                                throw new IOException(MessageFormat.format(CLIText.get().cannotLock, Constants.HEAD));
                        lf.write(id);
@@ -254,7 +254,7 @@ class RebuildCommitGraph extends TextBuiltin {
                        protected void writeFile(final String name, final byte[] content)
                                        throws IOException {
                                final File file = new File(db.getDirectory(), name);
-                               final LockFile lck = new LockFile(file);
+                               final LockFile lck = new LockFile(file, db.getFS());
                                if (!lck.lock())
                                        throw new ObjectWritingException(MessageFormat.format(CLIText.get().cantWrite, file));
                                try {
index a99e0abca2e38edd39fe6c9f654d1123531bb602..84859a805cdc06431ad0fc024c24e8e55e0246d3 100644 (file)
@@ -98,7 +98,7 @@ class Iplog extends TextBuiltin {
                if (output != null) {
                        if (!output.getParentFile().exists())
                                output.getParentFile().mkdirs();
-                       LockFile lf = new LockFile(output);
+                       LockFile lf = new LockFile(output, db.getFS());
                        if (!lf.lock())
                                throw die(MessageFormat.format(CLIText.get().cannotLock, output));
                        try {
index b563f079101414593a00241ec143fc3f6da36597..6653209a65fb41a8c1045036bd0af30fad5094c6 100644 (file)
@@ -94,6 +94,6 @@ class Ipzilla extends TextBuiltin {
                        output = new File(db.getWorkTree(), IpLogMeta.IPLOG_CONFIG_FILE);
 
                IpLogMeta meta = new IpLogMeta();
-               meta.syncCQs(output, ipzilla, username, password);
+               meta.syncCQs(output, db.getFS(), ipzilla, username, password);
        }
 }
index 01981600dd01fc5ec7ab33d8ee1bc0b77b0a088f..712698200e3aac657b810c054e411dabf175e398 100644 (file)
@@ -103,7 +103,7 @@ public class AbstractTreeIteratorHandler extends
                if (new File(name).isFile()) {
                        final DirCache dirc;
                        try {
-                               dirc = DirCache.read(new File(name));
+                               dirc = DirCache.read(new File(name), FS.DETECTED);
                        } catch (IOException e) {
                                throw new CmdLineException(MessageFormat.format(CLIText.get().notAnIndexFile, name), e);
                        }
index c3ac952a11d7650416c8249b87eaedb2d9498fdb..b6e4e42c7e1b9854b0b9dbfa3cc286d91ad26945 100644 (file)
@@ -63,7 +63,7 @@ public class DirCacheBasicTest extends RepositoryTestCase {
                final File idx = new File(db.getDirectory(), "tmp_index");
                assertFalse(idx.exists());
 
-               final DirCache dc = DirCache.read(idx);
+               final DirCache dc = DirCache.read(idx, db.getFS());
                assertNotNull(dc);
                assertEquals(0, dc.getEntryCount());
        }
@@ -91,7 +91,7 @@ public class DirCacheBasicTest extends RepositoryTestCase {
                assertFalse(idx.exists());
                assertFalse(lck.exists());
 
-               final DirCache dc = DirCache.lock(idx);
+               final DirCache dc = DirCache.lock(idx, db.getFS());
                assertNotNull(dc);
                assertFalse(idx.exists());
                assertTrue(lck.exists());
index fa5fea8633fc6092453e1e32485f9051926329af..f37d04004950b21268e1048002c96b6074aeba8d 100644 (file)
@@ -58,6 +58,7 @@ import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.JGitTestUtil;
 
 public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
@@ -65,7 +66,7 @@ public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
 
        public void testReadIndex_LsFiles() throws Exception {
                final Map<String, CGitIndexRecord> ls = readLsFiles();
-               final DirCache dc = new DirCache(index);
+               final DirCache dc = new DirCache(index, FS.DETECTED);
                assertEquals(0, dc.getEntryCount());
                dc.read();
                assertEquals(ls.size(), dc.getEntryCount());
@@ -79,7 +80,7 @@ public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
        public void testTreeWalk_LsFiles() throws Exception {
                final Repository db = createBareRepository();
                final Map<String, CGitIndexRecord> ls = readLsFiles();
-               final DirCache dc = new DirCache(index);
+               final DirCache dc = new DirCache(index, db.getFS());
                assertEquals(0, dc.getEntryCount());
                dc.read();
                assertEquals(ls.size(), dc.getEntryCount());
@@ -102,14 +103,16 @@ public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
        }
 
        public void testUnsupportedOptionalExtension() throws Exception {
-               final DirCache dc = new DirCache(pathOf("gitgit.index.ZZZZ"));
+               final DirCache dc = new DirCache(pathOf("gitgit.index.ZZZZ"),
+                               FS.DETECTED);
                dc.read();
                assertEquals(1, dc.getEntryCount());
                assertEquals("A", dc.getEntry(0).getPathString());
        }
 
        public void testUnsupportedRequiredExtension() throws Exception {
-               final DirCache dc = new DirCache(pathOf("gitgit.index.aaaa"));
+               final DirCache dc = new DirCache(pathOf("gitgit.index.aaaa"),
+                               FS.DETECTED);
                try {
                        dc.read();
                        fail("Cache loaded an unsupported extension");
@@ -120,7 +123,8 @@ public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
        }
 
        public void testCorruptChecksumAtFooter() throws Exception {
-               final DirCache dc = new DirCache(pathOf("gitgit.index.badchecksum"));
+               final DirCache dc = new DirCache(pathOf("gitgit.index.badchecksum"),
+                               FS.DETECTED);
                try {
                        dc.read();
                        fail("Cache loaded despite corrupt checksum");
@@ -143,7 +147,7 @@ public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
        public void testReadIndex_DirCacheTree() throws Exception {
                final Map<String, CGitIndexRecord> cList = readLsFiles();
                final Map<String, CGitLsTreeRecord> cTree = readLsTree();
-               final DirCache dc = new DirCache(index);
+               final DirCache dc = new DirCache(index, FS.DETECTED);
                assertEquals(0, dc.getEntryCount());
                dc.read();
                assertEquals(cList.size(), dc.getEntryCount());
index 875c2e96f5a7f6e76f82b527e0efd3d7f06d458b..871700898feba01eeb82129bc99e5503391be8d2 100644 (file)
@@ -555,13 +555,15 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase {
                ObjectId pid = db.resolve("refs/heads/master^");
                RefUpdate updateRef = db.updateRef("refs/heads/master");
                updateRef.setNewObjectId(pid);
-               LockFile lockFile1 = new LockFile(new File(db.getDirectory(),"refs/heads/master"));
+               LockFile lockFile1 = new LockFile(new File(db.getDirectory(),
+                               "refs/heads/master"), db.getFS());
                try {
                        assertTrue(lockFile1.lock()); // precondition to test
                        Result update = updateRef.update();
                        assertEquals(Result.LOCK_FAILURE, update);
                        assertEquals(opid, db.resolve("refs/heads/master"));
-                       LockFile lockFile2 = new LockFile(new File(db.getDirectory(),"refs/heads/master"));
+                       LockFile lockFile2 = new LockFile(new File(db.getDirectory(),"refs/heads/master"),
+                                       db.getFS());
                        assertFalse(lockFile2.lock()); // was locked, still is
                } finally {
                        lockFile1.unlock();
@@ -699,7 +701,8 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase {
                                "logs/" + fromName).exists());
 
                // "someone" has branch X locked
-               LockFile lockFile = new LockFile(new File(db.getDirectory(), toLock));
+               LockFile lockFile = new LockFile(new File(db.getDirectory(), toLock),
+                               db.getFS());
                try {
                        assertTrue(lockFile.lock());
 
index 4f6d5b3bd6034da5fb5334372eb959e248873ee2..d28dd399b00573b146b204d80f4ed8fe9b1b7030 100644 (file)
@@ -53,6 +53,7 @@ import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.FS;
 
 /**
  * Tests for setting up the working directory when creating a Repository
@@ -191,7 +192,8 @@ public class RepositorySetupWorkDirTest extends LocalDiskRepositoryTestCase {
 
        private FileBasedConfig configFor(File gitDir) throws IOException,
                        ConfigInvalidException {
-               FileBasedConfig cfg = new FileBasedConfig(new File(gitDir, "config"));
+               File configPath = new File(gitDir, "config");
+               FileBasedConfig cfg = new FileBasedConfig(configPath, FS.DETECTED);
                cfg.load();
                return cfg;
        }
index 477b0dfb502e030b025a74d43453f5607b8a6b59..ecabedd965077237529839d55e15c9a73dbeebea 100644 (file)
@@ -315,7 +315,7 @@ public class T0003_Basic extends SampleDataRepositoryTestCase {
        public void test006_ReadUglyConfig() throws IOException,
                        ConfigInvalidException {
                final File cfg = new File(db.getDirectory(), "config");
-               final FileBasedConfig c = new FileBasedConfig(cfg);
+               final FileBasedConfig c = new FileBasedConfig(cfg, db.getFS());
                final FileWriter pw = new FileWriter(cfg);
                final String configStr = "  [core];comment\n\tfilemode = yes\n"
                                + "[user]\n"
index cc10fad2b4102c765037b7acd0be6fd886c29b7a..60238c3d8bddd4c4f6ca32a7ea441fb484524c40 100644 (file)
@@ -67,6 +67,7 @@ import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.storage.file.LockFile;
+import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.MutableInteger;
 import org.eclipse.jgit.util.NB;
@@ -129,7 +130,7 @@ public class DirCache {
         *         memory).
         */
        public static DirCache newInCore() {
-               return new DirCache(null);
+               return new DirCache(null, null);
        }
 
        /**
@@ -141,6 +142,9 @@ public class DirCache {
         *
         * @param indexLocation
         *            location of the index file on disk.
+        * @param fs
+        *            the file system abstraction which will be necessary to perform
+        *            certain file system operations.
         * @return a cache representing the contents of the specified index file (if
         *         it exists) or an empty cache if the file does not exist.
         * @throws IOException
@@ -149,9 +153,9 @@ public class DirCache {
         *             the index file is using a format or extension that this
         *             library does not support.
         */
-       public static DirCache read(final File indexLocation)
+       public static DirCache read(final File indexLocation, final FS fs)
                        throws CorruptObjectException, IOException {
-               final DirCache c = new DirCache(indexLocation);
+               final DirCache c = new DirCache(indexLocation, fs);
                c.read();
                return c;
        }
@@ -161,11 +165,14 @@ public class DirCache {
         * <p>
         * The new index will be locked and then read before it is returned to the
         * caller. Read failures are reported as exceptions and therefore prevent
-        * the method from returning a partially populated index.  On read failure,
+        * the method from returning a partially populated index. On read failure,
         * the lock is released.
         *
         * @param indexLocation
         *            location of the index file on disk.
+        * @param fs
+        *            the file system abstraction which will be necessary to perform
+        *            certain file system operations.
         * @return a cache representing the contents of the specified index file (if
         *         it exists) or an empty cache if the file does not exist.
         * @throws IOException
@@ -175,9 +182,9 @@ public class DirCache {
         *             the index file is using a format or extension that this
         *             library does not support.
         */
-       public static DirCache lock(final File indexLocation)
+       public static DirCache lock(final File indexLocation, final FS fs)
                        throws CorruptObjectException, IOException {
-               final DirCache c = new DirCache(indexLocation);
+               final DirCache c = new DirCache(indexLocation, fs);
                if (!c.lock())
                        throw new IOException(MessageFormat.format(JGitText.get().cannotLock, indexLocation));
 
@@ -215,6 +222,9 @@ public class DirCache {
        /** Our active lock (if we hold it); null if we don't have it locked. */
        private LockFile myLock;
 
+       /** file system abstraction **/
+       private final FS fs;
+
        /**
         * Create a new in-core index representation.
         * <p>
@@ -223,9 +233,13 @@ public class DirCache {
         *
         * @param indexLocation
         *            location of the index file on disk.
+        * @param fs
+        *            the file system abstraction which will be necessary to perform
+        *            certain file system operations.
         */
-       public DirCache(final File indexLocation) {
+       public DirCache(final File indexLocation, final FS fs) {
                liveFile = indexLocation;
+               this.fs = fs;
                clear();
        }
 
@@ -429,7 +443,7 @@ public class DirCache {
        public boolean lock() throws IOException {
                if (liveFile == null)
                        throw new IOException(JGitText.get().dirCacheDoesNotHaveABackingFile);
-               final LockFile tmp = new LockFile(liveFile);
+               final LockFile tmp = new LockFile(liveFile, fs);
                if (tmp.lock()) {
                        tmp.setNeedStatInformation(true);
                        myLock = tmp;
index 92edb0325c36a148bbd029fa2c0449ba3bfd9ba7..410c85fd8b81b534eb649d908991231b92252c20 100644 (file)
@@ -555,7 +555,7 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
                        // repository and not inherited from other files.
                        //
                        File path = safeFS().resolve(getGitDir(), "config");
-                       FileBasedConfig cfg = new FileBasedConfig(path);
+                       FileBasedConfig cfg = new FileBasedConfig(path, safeFS());
                        try {
                                cfg.load();
                        } catch (ConfigInvalidException err) {
index a39af8657773e06dbd70637ed71f49bb190e333b..4be1e69d3392afea1b90632bbeb0cdab6f70a1ac 100644 (file)
@@ -930,7 +930,7 @@ public abstract class Repository {
         */
        public DirCache readDirCache() throws NoWorkTreeException,
                        CorruptObjectException, IOException {
-               return DirCache.read(getIndexFile());
+               return DirCache.read(getIndexFile(), getFS());
        }
 
        /**
@@ -954,7 +954,7 @@ public abstract class Repository {
         */
        public DirCache lockDirCache() throws NoWorkTreeException,
                        CorruptObjectException, IOException {
-               return DirCache.lock(getIndexFile());
+               return DirCache.lock(getIndexFile(), getFS());
        }
 
        static byte[] gitInternalSlash(byte[] bytes) {
index 4cbb848118a39289f8630bb95babc41e1a979b2b..8ffbe80cc27ac7a013a53afca1e3f22298f9f2e9 100644 (file)
@@ -59,6 +59,7 @@ import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.RawParseUtils;
 
@@ -68,15 +69,19 @@ import org.eclipse.jgit.util.RawParseUtils;
 public class FileBasedConfig extends StoredConfig {
        private final File configFile;
        private volatile long lastModified;
+       private final FS fs;
 
        /**
         * Create a configuration with no default fallback.
         *
         * @param cfgLocation
         *            the location of the configuration file on the file system
+        * @param fs
+        *            the file system abstraction which will be necessary to perform
+        *            certain file system operations.
         */
-       public FileBasedConfig(File cfgLocation) {
-               this(null, cfgLocation);
+       public FileBasedConfig(File cfgLocation, FS fs) {
+               this(null, cfgLocation, fs);
        }
 
        /**
@@ -86,10 +91,14 @@ public class FileBasedConfig extends StoredConfig {
         *            the base configuration file
         * @param cfgLocation
         *            the location of the configuration file on the file system
+        * @param fs
+        *            the file system abstraction which will be necessary to perform
+        *            certain file system operations.
         */
-       public FileBasedConfig(Config base, File cfgLocation) {
+       public FileBasedConfig(Config base, File cfgLocation, FS fs) {
                super(base);
                configFile = cfgLocation;
+               this.fs = fs;
        }
 
        /** @return location of the configuration file on disk */
@@ -138,7 +147,7 @@ public class FileBasedConfig extends StoredConfig {
         */
        public void save() throws IOException {
                final byte[] out = Constants.encode(toText());
-               final LockFile lf = new LockFile(getFile());
+               final LockFile lf = new LockFile(getFile(), fs);
                if (!lf.lock())
                        throw new IOException(MessageFormat.format(JGitText.get().cannotLockFile, getFile()));
                try {
index 15aafbdaebd989b556159a0bd0b2349e26fe1112..69cce71cf0819ebf64f916f1d79bb5dd9f1c53ad 100644 (file)
@@ -136,7 +136,9 @@ public class FileRepository extends Repository {
                super(options);
 
                userConfig = SystemReader.getInstance().openUserConfig(getFS());
-               repoConfig = new FileBasedConfig(userConfig, getFS().resolve(getDirectory(), "config"));
+               repoConfig = new FileBasedConfig(userConfig, //
+                               getFS().resolve(getDirectory(), "config"), //
+                               getFS());
 
                loadUserConfig();
                loadRepoConfig();
index ad89a2484789cd9973ae5b5dd4c4492b06a4bbfe..e8bc3e2cfdd2e94391e7a1e13f690cb09bf2f551 100644 (file)
@@ -59,6 +59,7 @@ import java.text.MessageFormat;
 import org.eclipse.jgit.JGitText;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.util.FS;
 
 /**
  * Git style file locking and replacement.
@@ -94,15 +95,21 @@ public class LockFile {
 
        private long commitLastModified;
 
+       private final FS fs;
+
        /**
         * Create a new lock for any file.
         *
         * @param f
         *            the file that will be locked.
+        * @param fs
+        *            the file system abstraction which will be necessary to perform
+        *            certain file system operations.
         */
-       public LockFile(final File f) {
+       public LockFile(final File f, FS fs) {
                ref = f;
                lck = new File(ref.getParentFile(), ref.getName() + SUFFIX);
+               this.fs = fs;
        }
 
        /**
@@ -393,13 +400,32 @@ public class LockFile {
                saveStatInformation();
                if (lck.renameTo(ref))
                        return true;
-               if (!ref.exists() || ref.delete())
+               if (!ref.exists() || deleteRef())
                        if (lck.renameTo(ref))
                                return true;
                unlock();
                return false;
        }
 
+       private boolean deleteRef() {
+               if (!fs.retryFailedLockFileCommit())
+                       return ref.delete();
+
+               // File deletion fails on windows if another thread is
+               // concurrently reading the same file. So try a few times.
+               //
+               for (int attempts = 0; attempts < 10; attempts++) {
+                       if (ref.delete())
+                               return true;
+                       try {
+                               Thread.sleep(100);
+                       } catch (InterruptedException e) {
+                               return false;
+                       }
+               }
+               return false;
+       }
+
        private void saveStatInformation() {
                if (needStatInformation)
                        commitLastModified = lck.lastModified();
index be250114c25398c860e315f743030fbdcbc799cb..dd08dfbac2df26e36c863f6203215f8d99a7aaed 100644 (file)
@@ -47,21 +47,26 @@ import java.io.File;
 import java.io.IOException;
 
 import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.util.FS;
 
 /** Keeps track of a {@link PackFile}'s associated <code>.keep</code> file. */
 public class PackLock {
        private final File keepFile;
+       private final FS fs;
 
        /**
         * Create a new lock for a pack file.
         *
         * @param packFile
         *            location of the <code>pack-*.pack</code> file.
+        * @param fs
+        *            the filesystem abstraction used by the repository.
         */
-       public PackLock(final File packFile) {
+       public PackLock(final File packFile, final FS fs) {
                final File p = packFile.getParentFile();
                final String n = packFile.getName();
                keepFile = new File(p, n.substring(0, n.length() - 5) + ".keep");
+               this.fs = fs;
        }
 
        /**
@@ -78,7 +83,7 @@ public class PackLock {
                        return false;
                if (!msg.endsWith("\n"))
                        msg += "\n";
-               final LockFile lf = new LockFile(keepFile);
+               final LockFile lf = new LockFile(keepFile, fs);
                if (!lf.lock())
                        return false;
                lf.write(Constants.encode(msg));
index 68b0270df9a742e4fb7521d889009190d28f91ce..b22b14a91091ddf670df61dcea5de7d0a7157bf4 100644 (file)
@@ -512,7 +512,8 @@ public class RefDirectory extends RefDatabase {
                // we don't miss an edit made externally.
                final PackedRefList packed = getPackedRefs();
                if (packed.contains(name)) {
-                       LockFile lck = new LockFile(packedRefsFile);
+                       LockFile lck = new LockFile(packedRefsFile,
+                                       update.getRepository().getFS());
                        if (!lck.lock())
                                throw new IOException(MessageFormat.format(
                                        JGitText.get().cannotLockFile, packedRefsFile));
index 8d35ec34f63ca7f1df3fea7a888170c864eb5717..a9f054837bcd52ac44c235cf1fbf56312cdfe593 100644 (file)
@@ -79,7 +79,7 @@ class RefDirectoryUpdate extends RefUpdate {
                if (deref)
                        dst = dst.getLeaf();
                String name = dst.getName();
-               lock = new LockFile(database.fileFor(name));
+               lock = new LockFile(database.fileFor(name), getRepository().getFS());
                if (lock.lock()) {
                        dst = database.getRef(name);
                        setOldObjectId(dst != null ? dst.getObjectId() : null);
index ca68858059e9bed26aa40c39da0e76916813717f..f747616749ea36cf0e4ad5816efae329f92a3dee 100644 (file)
@@ -279,7 +279,8 @@ class FetchProcess {
                File meta = transport.local.getDirectory();
                if (meta == null)
                        return;
-               final LockFile lock = new LockFile(new File(meta, "FETCH_HEAD"));
+               final LockFile lock = new LockFile(new File(meta, "FETCH_HEAD"),
+                               transport.local.getFS());
                try {
                        if (lock.lock()) {
                                final Writer w = new OutputStreamWriter(lock.getOutputStream());
index 25b499b32e4779a322e7edfaf5484f22f3c79e97..2daa105c53929fdc1fa0985b0788b5d81df128c0 100644 (file)
@@ -1101,7 +1101,7 @@ public class IndexPack {
                final File packDir = new File(repo.getObjectsDirectory(), "pack");
                final File finalPack = new File(packDir, "pack-" + name + ".pack");
                final File finalIdx = new File(packDir, "pack-" + name + ".idx");
-               final PackLock keep = new PackLock(finalPack);
+               final PackLock keep = new PackLock(finalPack, repo.getFS());
 
                if (!packDir.exists() && !packDir.mkdir() && !packDir.exists()) {
                        // The objects/pack directory isn't present, and we are unable
index f4382eb18632c7d7da1c3fcfebb2f6f744f0fbac..475c871c3c5ce45764581f4bc838544459bdc953 100644 (file)
@@ -74,7 +74,7 @@ public abstract class SystemReader {
 
                public FileBasedConfig openUserConfig(FS fs) {
                        final File home = fs.userHome();
-                       return new FileBasedConfig(new File(home, ".gitconfig"));
+                       return new FileBasedConfig(new File(home, ".gitconfig"), fs);
                }
 
                public String getHostname() {