/** * Unlock this file and abort this change. * * <p>The temporary file (if created) is deleted before returning. */ public void unlock() { final LockFile tmp = myLock; if (tmp != null) { myLock = null; tmp.unlock(); } }
void writeTo(final OutputStream os) throws IOException { final MessageDigest foot = Constants.newMessageDigest(); final DigestOutputStream dos = new DigestOutputStream(os, foot); boolean extended = false; for (int i = 0; i < entryCnt; i++) extended |= sortedEntries[i].isExtended(); // Write the header. // final byte[] tmp = new byte[128]; System.arraycopy(SIG_DIRC, 0, tmp, 0, SIG_DIRC.length); NB.encodeInt32(tmp, 4, extended ? 3 : 2); NB.encodeInt32(tmp, 8, entryCnt); dos.write(tmp, 0, 12); // Write the individual file entries. final int smudge_s; final int smudge_ns; if (myLock != null) { // For new files we need to smudge the index entry // if they have been modified "now". Ideally we'd // want the timestamp when we're done writing the index, // so we use the current timestamp as a approximation. myLock.createCommitSnapshot(); snapshot = myLock.getCommitSnapshot(); smudge_s = (int) (snapshot.lastModified() / 1000); smudge_ns = ((int) (snapshot.lastModified() % 1000)) * 1000000; } else { // Used in unit tests only smudge_ns = 0; smudge_s = 0; } // Check if tree is non-null here since calling updateSmudgedEntries // will automatically build it via creating a DirCacheIterator final boolean writeTree = tree != null; if (repository != null && entryCnt > 0) updateSmudgedEntries(); for (int i = 0; i < entryCnt; i++) { final DirCacheEntry e = sortedEntries[i]; if (e.mightBeRacilyClean(smudge_s, smudge_ns)) e.smudgeRacilyClean(); e.write(dos); } if (writeTree) { final TemporaryBuffer bb = new TemporaryBuffer.LocalFile(); tree.write(tmp, bb); bb.close(); NB.encodeInt32(tmp, 0, EXT_TREE); NB.encodeInt32(tmp, 4, (int) bb.length()); dos.write(tmp, 0, 8); bb.writeTo(dos, null); } writeIndexChecksum = foot.digest(); os.write(writeIndexChecksum); os.close(); }
/** * Commit this change and release the lock. * * <p>If this method fails (returns false) the lock is still released. * * @return true if the commit was successful and the file contains the new data; false if the * commit failed and the file remains with the old data. * @throws IllegalStateException the lock is not held. */ public boolean commit() { final LockFile tmp = myLock; requireLocked(tmp); myLock = null; if (!tmp.commit()) return false; snapshot = tmp.getCommitSnapshot(); if (indexChangedListener != null && !Arrays.equals(readIndexChecksum, writeIndexChecksum)) indexChangedListener.onIndexChanged(new IndexChangedEvent()); return true; }
/** * Try to establish an update lock on the cache file. * * @return true if the lock is now held by the caller; false if it is held by someone else. * @throws IOException the output file could not be created. The caller does not hold the lock. */ public boolean lock() throws IOException { if (liveFile == null) throw new IOException(JGitText.get().dirCacheDoesNotHaveABackingFile); final LockFile tmp = new LockFile(liveFile, fs); if (tmp.lock()) { tmp.setNeedStatInformation(true); myLock = tmp; return true; } return false; }
/** * Write the entry records from memory to disk. * * <p>The cache must be locked first by calling {@link #lock()} and receiving true as the return * value. Applications are encouraged to lock the index, then invoke {@link #read()} to ensure the * in-memory data is current, prior to updating the in-memory entries. * * <p>Once written the lock is closed and must be either committed with {@link #commit()} or * rolled back with {@link #unlock()}. * * @throws IOException the output file could not be created. The caller no longer holds the lock. */ public void write() throws IOException { final LockFile tmp = myLock; requireLocked(tmp); try { writeTo(new SafeBufferedOutputStream(tmp.getOutputStream())); } catch (IOException err) { tmp.unlock(); throw err; } catch (RuntimeException err) { tmp.unlock(); throw err; } catch (Error err) { tmp.unlock(); throw err; } }
/** * Save the configuration as a Git text style configuration file. * * <p><b>Warning:</b> Although this method uses the traditional Git file locking approach to * protect against concurrent writes of the configuration file, it does not ensure that the file * has not been modified since the last read, which means updates performed by other objects * accessing the same backing file may be lost. * * @throws IOException the file could not be written. */ public void save() throws IOException { final byte[] out; final String text = toText(); if (utf8Bom) { final ByteArrayOutputStream bos = new ByteArrayOutputStream(); bos.write(0xEF); bos.write(0xBB); bos.write(0xBF); bos.write(text.getBytes(RawParseUtils.UTF8_CHARSET.name())); out = bos.toByteArray(); } else { out = Constants.encode(text); } final LockFile lf = new LockFile(getFile(), fs); if (!lf.lock()) throw new LockFailedException(getFile()); try { lf.setNeedSnapshot(true); lf.write(out); if (!lf.commit()) throw new IOException(MessageFormat.format(JGitText.get().cannotCommitWriteTo, getFile())); } finally { lf.unlock(); } snapshot = lf.getCommitSnapshot(); hash = hash(out); // notify the listeners fireConfigChangedEvent(); }