1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.transport.file;
20
21 import java.io.IOException;
22 import java.io.UncheckedIOException;
23 import java.nio.ByteBuffer;
24 import java.nio.channels.FileChannel;
25 import java.nio.file.FileSystem;
26 import java.nio.file.Files;
27 import java.nio.file.Path;
28
29 import org.eclipse.aether.spi.connector.transport.AbstractTransporter;
30 import org.eclipse.aether.spi.connector.transport.GetTask;
31 import org.eclipse.aether.spi.connector.transport.PeekTask;
32 import org.eclipse.aether.spi.connector.transport.PutTask;
33 import org.eclipse.aether.spi.connector.transport.TransportTask;
34
35 import static java.util.Objects.requireNonNull;
36
37
38
39
40
41 final class FileTransporter extends AbstractTransporter {
42
43
44
45
46
47
48
49
50
51
52
53
54
55 enum WriteOp {
56 COPY,
57 SYMLINK,
58 HARDLINK;
59 }
60
61 private final FileSystem fileSystem;
62 private final boolean closeFileSystem;
63 private final boolean writableFileSystem;
64 private final Path basePath;
65 private final WriteOp writeOp;
66
67 FileTransporter(
68 FileSystem fileSystem,
69 boolean closeFileSystem,
70 boolean writableFileSystem,
71 Path basePath,
72 WriteOp writeOp) {
73 this.fileSystem = requireNonNull(fileSystem);
74 this.closeFileSystem = closeFileSystem;
75 this.writableFileSystem = writableFileSystem;
76 this.basePath = requireNonNull(basePath);
77 this.writeOp = requireNonNull(writeOp);
78
79
80 if (basePath.getFileSystem() != fileSystem) {
81 throw new IllegalArgumentException("basePath must originate from the fileSystem");
82 }
83 }
84
85 Path getBasePath() {
86 return basePath;
87 }
88
89 @Override
90 public int classify(Throwable error) {
91 if (error instanceof ResourceNotFoundException) {
92 return ERROR_NOT_FOUND;
93 }
94 return ERROR_OTHER;
95 }
96
97 private WriteOp effectiveFileOp(WriteOp wanted, GetTask task) {
98 if (task.getDataPath() != null) {
99 return wanted;
100 }
101
102 return WriteOp.COPY;
103 }
104
105 @Override
106 protected void implPeek(PeekTask task) throws Exception {
107 getPath(task, true);
108 }
109
110 @Override
111 protected void implGet(GetTask task) throws Exception {
112 Path path = getPath(task, true);
113 long size = Files.size(path);
114 WriteOp effective = effectiveFileOp(writeOp, task);
115 switch (effective) {
116 case COPY:
117 utilGet(task, Files.newInputStream(path), true, size, false);
118 break;
119 case SYMLINK:
120 case HARDLINK:
121 Files.deleteIfExists(task.getDataPath());
122 task.getListener().transportStarted(0L, size);
123 if (effective == WriteOp.HARDLINK) {
124 Files.createLink(task.getDataPath(), path);
125 } else {
126 Files.createSymbolicLink(task.getDataPath(), path);
127 }
128 if (size > 0) {
129 try (FileChannel fc = FileChannel.open(path)) {
130 try {
131 task.getListener().transportProgressed(fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()));
132 } catch (UnsupportedOperationException e) {
133
134 ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 32);
135 while (fc.read(byteBuffer) != -1) {
136 byteBuffer.flip();
137 task.getListener().transportProgressed(byteBuffer);
138 byteBuffer.clear();
139 }
140 }
141 }
142 }
143 break;
144 default:
145 throw new IllegalStateException("Unknown fileOp " + writeOp);
146 }
147 }
148
149 @Override
150 protected void implPut(PutTask task) throws Exception {
151 if (!writableFileSystem) {
152 throw new UnsupportedOperationException("Read only FileSystem");
153 }
154 Path path = getPath(task, false);
155 Files.createDirectories(path.getParent());
156 try {
157 utilPut(task, Files.newOutputStream(path), true);
158 } catch (Exception e) {
159 Files.deleteIfExists(path);
160 throw e;
161 }
162 }
163
164 private Path getPath(TransportTask task, boolean required) throws Exception {
165 String path = task.getLocation().getPath();
166 if (path.contains("../")) {
167 throw new IllegalArgumentException("illegal resource path: " + path);
168 }
169 Path file = basePath.resolve(path);
170 if (required && !Files.isRegularFile(file)) {
171 throw new ResourceNotFoundException("Could not locate " + file);
172 }
173 return file;
174 }
175
176 @Override
177 protected void implClose() {
178 if (closeFileSystem) {
179 try {
180 fileSystem.close();
181 } catch (IOException e) {
182 throw new UncheckedIOException(e);
183 }
184 }
185 }
186 }