|
36 | 36 | import java.io.OutputStream; |
37 | 37 | import java.io.Serializable; |
38 | 38 | import java.net.URL; |
39 | | -import java.nio.charset.Charset; |
40 | 39 | import java.nio.charset.StandardCharsets; |
41 | 40 | import java.nio.file.LinkOption; |
42 | 41 | import java.nio.file.OpenOption; |
|
47 | 46 | import java.util.Collection; |
48 | 47 | import java.util.Comparator; |
49 | 48 | import java.util.GregorianCalendar; |
50 | | -import java.util.LinkedHashMap; |
51 | 49 | import java.util.List; |
52 | 50 | import java.util.Locale; |
53 | 51 | import java.util.Map; |
54 | | -import java.util.Objects; |
55 | 52 | import java.util.StringTokenizer; |
56 | 53 | import java.util.logging.Level; |
57 | 54 | import java.util.logging.Logger; |
58 | 55 | import java.util.regex.Pattern; |
59 | | -import java.util.stream.Collectors; |
60 | | -import java.util.stream.Stream; |
61 | | -import java.util.zip.ZipEntry; |
62 | | -import java.util.zip.ZipOutputStream; |
63 | 56 | import jenkins.model.Jenkins; |
64 | 57 | import jenkins.security.MasterToSlaveCallable; |
65 | 58 | import jenkins.security.ResourceDomainConfiguration; |
66 | 59 | import jenkins.security.ResourceDomainRootAction; |
67 | 60 | import jenkins.util.SystemProperties; |
68 | 61 | import jenkins.util.VirtualFile; |
69 | | -import org.apache.commons.io.IOUtils; |
70 | 62 | import org.kohsuke.accmod.Restricted; |
71 | 63 | import org.kohsuke.accmod.restrictions.NoExternalUse; |
72 | 64 | import org.kohsuke.stapler.HttpResponse; |
@@ -439,57 +431,6 @@ private boolean hasTmpDir(VirtualFile baseFile, String base, OpenOption[] openOp |
439 | 431 | return FilePath.isIgnoreTmpDirs(openOptions) && TMPDIR_PATTERN.matcher(base).matches(); |
440 | 432 | } |
441 | 433 |
|
442 | | - private List<List<Path>> keepReadabilityOnlyOnDescendants(VirtualFile root, boolean patternUsed, List<List<Path>> pathFragmentsList) { |
443 | | - Stream<List<Path>> pathFragmentsStream = pathFragmentsList.stream().map((List<Path> pathFragments) -> { |
444 | | - List<Path> mappedFragments = new ArrayList<>(pathFragments.size()); |
445 | | - String relativePath = ""; |
446 | | - for (int i = 0; i < pathFragments.size(); i++) { |
447 | | - Path current = pathFragments.get(i); |
448 | | - if (i == 0) { |
449 | | - relativePath = current.title; |
450 | | - } else { |
451 | | - relativePath += "/" + current.title; |
452 | | - } |
453 | | - |
454 | | - if (!current.isReadable) { |
455 | | - if (patternUsed) { |
456 | | - // we do not want to leak information about existence of folders / files satisfying the pattern inside that folder |
457 | | - return null; |
458 | | - } |
459 | | - mappedFragments.add(current); |
460 | | - return mappedFragments; |
461 | | - } else { |
462 | | - if (isDescendant(root, relativePath)) { |
463 | | - mappedFragments.add(current); |
464 | | - } else { |
465 | | - if (patternUsed) { |
466 | | - // we do not want to leak information about existence of folders / files satisfying the pattern inside that folder |
467 | | - return null; |
468 | | - } |
469 | | - mappedFragments.add(Path.createNotReadableVersionOf(current)); |
470 | | - return mappedFragments; |
471 | | - } |
472 | | - } |
473 | | - } |
474 | | - return mappedFragments; |
475 | | - }); |
476 | | - |
477 | | - if (patternUsed) { |
478 | | - pathFragmentsStream = pathFragmentsStream.filter(Objects::nonNull); |
479 | | - } |
480 | | - |
481 | | - return pathFragmentsStream.collect(Collectors.toList()); |
482 | | - } |
483 | | - |
484 | | - private boolean isDescendant(VirtualFile root, String relativePath) { |
485 | | - try { |
486 | | - return ALLOW_SYMLINK_ESCAPE || !root.supportIsDescendant() || root.isDescendant(relativePath); |
487 | | - } |
488 | | - catch (IOException e) { |
489 | | - return false; |
490 | | - } |
491 | | - } |
492 | | - |
493 | 434 | private String getPath(StaplerRequest2 req) { |
494 | 435 | String path = req.getRestOfPath(); |
495 | 436 | if (path.isEmpty()) |
@@ -519,71 +460,6 @@ private static String createBackRef(int times) { |
519 | 460 | return "../".repeat(times); |
520 | 461 | } |
521 | 462 |
|
522 | | - private static void zip(StaplerResponse2 rsp, VirtualFile root, VirtualFile dir, String glob) throws IOException, InterruptedException { |
523 | | - OutputStream outputStream = rsp.getOutputStream(); |
524 | | - // TODO JENKINS-20663 make encoding overridable via query parameter |
525 | | - try (ZipOutputStream zos = new ZipOutputStream(outputStream, Charset.defaultCharset())) { |
526 | | - // TODO consider using run(Callable) here |
527 | | - |
528 | | - if (glob.isEmpty()) { |
529 | | - if (!root.supportsQuickRecursiveListing()) { |
530 | | - // avoid slow listing when the Glob can do a quicker job |
531 | | - glob = "**"; |
532 | | - } |
533 | | - } |
534 | | - |
535 | | - if (glob.isEmpty()) { |
536 | | - Map<String, VirtualFile> nameToVirtualFiles = collectRecursivelyAllLegalChildren(dir); |
537 | | - sendZipUsingMap(zos, dir, nameToVirtualFiles); |
538 | | - } else { |
539 | | - Collection<String> listOfFile = dir.list(glob, null, /* TODO what is the user expectation? */true); |
540 | | - sendZipUsingListOfNames(zos, dir, listOfFile); |
541 | | - } |
542 | | - } |
543 | | - } |
544 | | - |
545 | | - private static void sendZipUsingMap(ZipOutputStream zos, VirtualFile dir, Map<String, VirtualFile> nameToVirtualFiles) throws IOException { |
546 | | - for (Map.Entry<String, VirtualFile> entry : nameToVirtualFiles.entrySet()) { |
547 | | - String n = entry.getKey(); |
548 | | - |
549 | | - // JENKINS-19947: traditional behavior is to prepend the directory name |
550 | | - String relativePath = dir.getName() + '/' + n; |
551 | | - |
552 | | - VirtualFile f = entry.getValue(); |
553 | | - sendOneZipEntry(zos, f, relativePath); |
554 | | - } |
555 | | - } |
556 | | - |
557 | | - private static void sendZipUsingListOfNames(ZipOutputStream zos, VirtualFile dir, Collection<String> listOfFileNames) throws IOException { |
558 | | - for (String relativePath : listOfFileNames) { |
559 | | - VirtualFile f = dir.child(relativePath); |
560 | | - sendOneZipEntry(zos, f, relativePath); |
561 | | - } |
562 | | - } |
563 | | - |
564 | | - private static void sendOneZipEntry(ZipOutputStream zos, VirtualFile vf, String relativePath) throws IOException { |
565 | | - // In ZIP archives "All slashes MUST be forward slashes" (http://pkware.com/documents/casestudies/APPNOTE.TXT) |
566 | | - // TODO On Linux file names can contain backslashes which should not treated as file separators. |
567 | | - // Unfortunately, only the file separator char of the controller is known (File.separatorChar) |
568 | | - // but not the file separator char of the (maybe remote) "dir". |
569 | | - ZipEntry e = new ZipEntry(relativePath.replace('\\', '/')); |
570 | | - |
571 | | - e.setTime(vf.lastModified()); |
572 | | - zos.putNextEntry(e); |
573 | | - try (InputStream in = vf.open()) { |
574 | | - IOUtils.copy(in, zos); |
575 | | - } |
576 | | - finally { |
577 | | - zos.closeEntry(); |
578 | | - } |
579 | | - } |
580 | | - |
581 | | - private static Map<String, VirtualFile> collectRecursivelyAllLegalChildren(VirtualFile dir) throws IOException { |
582 | | - Map<String, VirtualFile> nameToFiles = new LinkedHashMap<>(); |
583 | | - collectRecursivelyAllLegalChildren(dir, "", nameToFiles); |
584 | | - return nameToFiles; |
585 | | - } |
586 | | - |
587 | 463 | private static void collectRecursivelyAllLegalChildren(VirtualFile currentDir, String currentPrefix, Map<String, VirtualFile> nameToFiles) throws IOException { |
588 | 464 | if (currentDir.isFile()) { |
589 | 465 | if (currentDir.isDescendant("")) { |
|
0 commit comments