diff options
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/api')
3 files changed, 80 insertions, 33 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java index 583767af3f..58b339a237 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java @@ -22,6 +22,7 @@ import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.zip.InflaterInputStream; @@ -38,12 +39,14 @@ import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheCheckout; import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata; import org.eclipse.jgit.dircache.DirCacheIterator; +import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.CoreConfig.EolStreamType; import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.FileModeCache; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.ObjectStream; @@ -65,6 +68,7 @@ import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.jgit.util.StringUtils; +import org.eclipse.jgit.util.SystemReader; import org.eclipse.jgit.util.TemporaryBuffer; import org.eclipse.jgit.util.TemporaryBuffer.LocalFile; import org.eclipse.jgit.util.io.BinaryDeltaInputStream; @@ -72,6 +76,12 @@ import org.eclipse.jgit.util.io.BinaryHunkInputStream; import org.eclipse.jgit.util.io.EolStreamTypeUtil; import org.eclipse.jgit.util.sha1.SHA1; +import static org.eclipse.jgit.diff.DiffEntry.ChangeType.ADD; +import static org.eclipse.jgit.diff.DiffEntry.ChangeType.COPY; +import static org.eclipse.jgit.diff.DiffEntry.ChangeType.DELETE; +import static org.eclipse.jgit.diff.DiffEntry.ChangeType.MODIFY; +import static org.eclipse.jgit.diff.DiffEntry.ChangeType.RENAME; + /** * Apply a patch to files and/or to the index. * @@ -131,30 +141,34 @@ public class ApplyCommand extends GitCommand<ApplyResult> { throw new PatchFormatException(p.getErrors()); } Repository repository = getRepository(); + FileModeCache directoryCache = new FileModeCache(repo); DirCache cache = repository.readDirCache(); for (FileHeader fh : p.getFiles()) { ChangeType type = fh.getChangeType(); File f = null; + verifyExistence(fh, + new File(repo.getWorkTree(), fh.getOldPath()), + new File(repo.getWorkTree(), fh.getNewPath())); switch (type) { case ADD: - f = getFile(fh.getNewPath(), true); + f = getFile(fh.getNewPath(), true, directoryCache); apply(repository, fh.getNewPath(), cache, f, fh); break; case MODIFY: - f = getFile(fh.getOldPath(), false); + f = getFile(fh.getOldPath(), false, directoryCache); apply(repository, fh.getOldPath(), cache, f, fh); break; case DELETE: - f = getFile(fh.getOldPath(), false); + f = getFile(fh.getOldPath(), false, directoryCache); if (!f.delete()) throw new PatchApplyException(MessageFormat.format( JGitText.get().cannotDeleteFile, f)); break; case RENAME: - f = getFile(fh.getOldPath(), false); - File dest = getFile(fh.getNewPath(), false); + f = getFile(fh.getOldPath(), false, directoryCache); + File dest = getFile(fh.getNewPath(), false, directoryCache); try { - FileUtils.mkdirs(dest.getParentFile(), true); + directoryCache.safeCreateParentDirectory(fh.getNewPath(), dest.getParentFile(), false); FileUtils.rename(f, dest, StandardCopyOption.ATOMIC_MOVE); } catch (IOException e) { @@ -164,9 +178,9 @@ public class ApplyCommand extends GitCommand<ApplyResult> { apply(repository, fh.getOldPath(), cache, dest, fh); break; case COPY: - f = getFile(fh.getOldPath(), false); - File target = getFile(fh.getNewPath(), false); - FileUtils.mkdirs(target.getParentFile(), true); + f = getFile(fh.getOldPath(), false, directoryCache); + File target = getFile(fh.getNewPath(), false, directoryCache); + directoryCache.safeCreateParentDirectory(fh.getNewPath(), target.getParentFile(), false); Files.copy(f.toPath(), target.toPath()); apply(repository, fh.getOldPath(), cache, target, fh); } @@ -179,13 +193,40 @@ public class ApplyCommand extends GitCommand<ApplyResult> { return r; } - private File getFile(String path, boolean create) + private void verifyExistence(FileHeader fh, File src, File dest) + throws IOException, PatchApplyException { + boolean srcShouldExist = Arrays + .asList(new ChangeType[] { MODIFY, DELETE, RENAME, COPY }) + .contains(fh.getChangeType()); + boolean destShouldNotExist = Arrays + .asList(new ChangeType[] { ADD, RENAME, COPY }) + .contains(fh.getChangeType()); + if (srcShouldExist && !validGitPath(fh.getOldPath())) { + throw new PatchApplyException(MessageFormat.format( + JGitText.get().applyPatchSourceInvalid, fh.getOldPath())); + } + if (destShouldNotExist && !validGitPath(fh.getNewPath())) { + throw new PatchApplyException(MessageFormat.format( + JGitText.get().applyPatchDestInvalid, fh.getNewPath())); + } + } + + private boolean validGitPath(String path) { + try { + SystemReader.getInstance().checkPath(path); + return true; + } catch (CorruptObjectException e) { + return false; + } + } + + private File getFile(String path, boolean create, FileModeCache directoryCache) throws PatchApplyException { File f = new File(getRepository().getWorkTree(), path); if (create) { try { File parent = f.getParentFile(); - FileUtils.mkdirs(parent, true); + directoryCache.safeCreateParentDirectory(path, parent, false); FileUtils.createNewFile(f); } catch (IOException e) { throw new PatchApplyException(MessageFormat.format( diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java index 847ab0a9a8..8edae5a580 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> - * Copyright (C) 2011, 2020 Matthias Sohn <matthias.sohn@sap.com> and others + * Copyright (C) 2011, 2023 Matthias Sohn <matthias.sohn@sap.com> and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -28,6 +28,7 @@ import org.eclipse.jgit.api.errors.InvalidRefNameException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.RefAlreadyExistsException; import org.eclipse.jgit.api.errors.RefNotFoundException; +import org.eclipse.jgit.dircache.Checkout; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheCheckout; import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata; @@ -411,6 +412,7 @@ public class CheckoutCommand extends GitCommand<Ref> { protected CheckoutCommand checkoutPaths() throws IOException, RefNotFoundException { actuallyModifiedPaths = new HashSet<>(); + Checkout checkout = new Checkout(repo).setRecursiveDeletion(true); DirCache dc = repo.lockDirCache(); try (RevWalk revWalk = new RevWalk(repo); TreeWalk treeWalk = new TreeWalk(repo, @@ -419,10 +421,10 @@ public class CheckoutCommand extends GitCommand<Ref> { if (!checkoutAllPaths) treeWalk.setFilter(PathFilterGroup.createFromStrings(paths)); if (isCheckoutIndex()) - checkoutPathsFromIndex(treeWalk, dc); + checkoutPathsFromIndex(treeWalk, dc, checkout); else { RevCommit commit = revWalk.parseCommit(getStartPointObjectId()); - checkoutPathsFromCommit(treeWalk, dc, commit); + checkoutPathsFromCommit(treeWalk, dc, commit, checkout); } } finally { try { @@ -439,7 +441,8 @@ public class CheckoutCommand extends GitCommand<Ref> { return this; } - private void checkoutPathsFromIndex(TreeWalk treeWalk, DirCache dc) + private void checkoutPathsFromIndex(TreeWalk treeWalk, DirCache dc, + Checkout checkout) throws IOException { DirCacheIterator dci = new DirCacheIterator(dc); treeWalk.addTree(dci); @@ -465,8 +468,9 @@ public class CheckoutCommand extends GitCommand<Ref> { if (stage > DirCacheEntry.STAGE_0) { if (checkoutStage != null) { if (stage == checkoutStage.number) { - checkoutPath(ent, r, new CheckoutMetadata( - eolStreamType, filterCommand)); + checkoutPath(ent, r, checkout, path, + new CheckoutMetadata(eolStreamType, + filterCommand)); actuallyModifiedPaths.add(path); } } else { @@ -475,8 +479,9 @@ public class CheckoutCommand extends GitCommand<Ref> { throw new JGitInternalException(e.getMessage(), e); } } else { - checkoutPath(ent, r, new CheckoutMetadata(eolStreamType, - filterCommand)); + checkoutPath(ent, r, checkout, path, + new CheckoutMetadata(eolStreamType, + filterCommand)); actuallyModifiedPaths.add(path); } } @@ -488,7 +493,7 @@ public class CheckoutCommand extends GitCommand<Ref> { } private void checkoutPathsFromCommit(TreeWalk treeWalk, DirCache dc, - RevCommit commit) throws IOException { + RevCommit commit, Checkout checkout) throws IOException { treeWalk.addTree(commit.getTree()); final ObjectReader r = treeWalk.getObjectReader(); DirCacheEditor editor = dc.editor(); @@ -510,7 +515,7 @@ public class CheckoutCommand extends GitCommand<Ref> { } ent.setObjectId(blobId); ent.setFileMode(mode); - checkoutPath(ent, r, + checkoutPath(ent, r, checkout, path, new CheckoutMetadata(eolStreamType, filterCommand)); actuallyModifiedPaths.add(path); } @@ -520,10 +525,9 @@ public class CheckoutCommand extends GitCommand<Ref> { } private void checkoutPath(DirCacheEntry entry, ObjectReader reader, - CheckoutMetadata checkoutMetadata) { + Checkout checkout, String path, CheckoutMetadata checkoutMetadata) { try { - DirCacheCheckout.checkoutEntry(repo, entry, reader, true, - checkoutMetadata); + checkout.checkout(entry, checkoutMetadata, reader, path); } catch (IOException e) { throw new JGitInternalException(MessageFormat.format( JGitText.get().checkoutConflictWithFile, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java index 1004d3e50f..e4157286f1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2021 GitHub Inc. and others + * Copyright (C) 2012, 2023 GitHub Inc. and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -23,6 +23,7 @@ import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.api.errors.StashApplyFailureException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException; +import org.eclipse.jgit.dircache.Checkout; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.dircache.DirCacheCheckout; @@ -382,6 +383,7 @@ public class StashApplyCommand extends GitCommand<ObjectId> { private void resetUntracked(RevTree tree) throws CheckoutConflictException, IOException { Set<String> actuallyModifiedPaths = new HashSet<>(); + Checkout checkout = new Checkout(repo).setRecursiveDeletion(true); // TODO maybe NameConflictTreeWalk ? try (TreeWalk walk = new TreeWalk(repo)) { walk.addTree(tree); @@ -405,17 +407,17 @@ public class StashApplyCommand extends GitCommand<ObjectId> { FileTreeIterator fIter = walk .getTree(1, FileTreeIterator.class); + String gitPath = entry.getPathString(); if (fIter != null) { if (fIter.isModified(entry, true, reader)) { // file exists and is dirty - throw new CheckoutConflictException( - entry.getPathString()); + throw new CheckoutConflictException(gitPath); } } - checkoutPath(entry, reader, + checkoutPath(entry, gitPath, reader, checkout, new CheckoutMetadata(eolStreamType, null)); - actuallyModifiedPaths.add(entry.getPathString()); + actuallyModifiedPaths.add(gitPath); } } finally { if (!actuallyModifiedPaths.isEmpty()) { @@ -425,11 +427,11 @@ public class StashApplyCommand extends GitCommand<ObjectId> { } } - private void checkoutPath(DirCacheEntry entry, ObjectReader reader, - CheckoutMetadata checkoutMetadata) { + private void checkoutPath(DirCacheEntry entry, String gitPath, + ObjectReader reader, + Checkout checkout, CheckoutMetadata checkoutMetadata) { try { - DirCacheCheckout.checkoutEntry(repo, entry, reader, true, - checkoutMetadata); + checkout.checkout(entry, checkoutMetadata, reader, gitPath); } catch (IOException e) { throw new JGitInternalException(MessageFormat.format( JGitText.get().checkoutConflictWithFile, |