• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

raphw / byte-buddy / #893

02 Jul 2026 12:35PM UTC coverage: 83.715% (+0.005%) from 83.71%
#893

push

raphw
[release] Release new version

29394 of 35112 relevant lines covered (83.71%)

0.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.36
/byte-buddy-dep/src/main/java/net/bytebuddy/utility/FileSystem.java
1
/*
2
 * Copyright 2014 - Present Rafael Winterhalter
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package net.bytebuddy.utility;
17

18
import net.bytebuddy.build.AccessControllerPlugin;
19
import net.bytebuddy.build.CachedReturnPlugin;
20
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
21
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
22
import net.bytebuddy.utility.dispatcher.JavaDispatcher;
23

24
import java.io.File;
25
import java.io.FileInputStream;
26
import java.io.FileOutputStream;
27
import java.io.IOException;
28
import java.io.InputStream;
29
import java.io.OutputStream;
30
import java.security.PrivilegedAction;
31

32
/**
33
 * A dispatcher to interact with the file system. If NIO2 is available, the API is used. Otherwise, byte streams are used.
34
 */
35
public abstract class FileSystem {
1✔
36

37
    /**
38
     * Returns the {@link FileSystem} instance to use.
39
     *
40
     * @return The {@link FileSystem} instance to use.
41
     */
42
    @CachedReturnPlugin.Enhance("INSTANCE")
43
    public static FileSystem getInstance() {
44
        try {
45
            Class.forName("java.nio.file.Files", false, ClassLoadingStrategy.BOOTSTRAP_LOADER);
1✔
46
            return new ForNio2CapableVm();
1✔
47
        } catch (ClassNotFoundException ignored) {
×
48
            return new ForLegacyVm();
1✔
49
        }
50
    }
51

52
    /**
53
     * Validates that a {@code /}-separated entry name does not escape the root directory it is resolved against
54
     * when it is written to a folder or extracted from an archive. This guards against a path traversal from a
55
     * type name that contains traversal segments, for example from a crafted {@code this_class} constant pool entry.
56
     *
57
     * @param name The entry name to validate, using {@code /} as a separator.
58
     * @return The supplied entry name.
59
     */
60
    public static String validated(String name) {
61
        int depth = 0;
1✔
62
        for (String segment : name.split("/")) {
1✔
63
            if (segment.equals("..")) {
1✔
64
                if (depth == 0) {
1✔
65
                    throw new IllegalArgumentException(name + " is not a valid entry within a contained root directory");
1✔
66
                }
67
                depth -= 1;
1✔
68
            } else if (!segment.equals(".") && segment.length() != 0) {
1✔
69
                depth += 1;
1✔
70
            }
71
        }
72
        return name;
1✔
73
    }
74

75
    /**
76
     * Validates that a target file is contained within a folder once both paths are canonicalized. This guards
77
     * against a path traversal from a type or entry name that contains traversal segments when a file is written
78
     * to the file system.
79
     *
80
     * @param folder The folder that the target file must be contained within.
81
     * @param target The target file to validate.
82
     * @return The supplied target file.
83
     * @throws IOException If the canonical path of either file cannot be resolved.
84
     */
85
    public static File validated(File folder, File target) throws IOException {
86
        String basePath = folder.getCanonicalPath(), targetPath = target.getCanonicalPath(), prefix = basePath;
1✔
87
        if (!prefix.endsWith(File.separator)) {
1✔
88
            prefix += File.separatorChar;
1✔
89
        }
90
        if (!targetPath.equals(basePath) && !targetPath.startsWith(prefix)) {
1✔
91
            throw new IllegalArgumentException(target + " is not a subdirectory of " + folder);
1✔
92
        }
93
        return target;
1✔
94
    }
95

96
    /**
97
     * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
98
     *
99
     * @param action The action to execute from a privileged context.
100
     * @param <T>    The type of the action's resolved value.
101
     * @return The action's resolved value.
102
     */
103
    @AccessControllerPlugin.Enhance
104
    private static <T> T doPrivileged(PrivilegedAction<T> action) {
105
        return action.run();
×
106
    }
107

108
    /**
109
     * Copies a file.
110
     *
111
     * @param source The source file.
112
     * @param target The target file.
113
     * @throws IOException If an I/O exception occurs.
114
     */
115
    public abstract void copy(File source, File target) throws IOException;
116

117
    /**
118
     * Links a file as a hard-link. If linking is not supported, a copy is made.
119
     *
120
     * @param source The source file.
121
     * @param target The target file.
122
     * @throws IOException If an I/O exception occurs.
123
     */
124
    public void link(File source, File target) throws IOException {
125
        copy(source, target);
×
126
    }
×
127

128
    /**
129
     * Moves a file.
130
     *
131
     * @param source The source file.
132
     * @param target The target file.
133
     * @throws IOException If an I/O exception occurs.
134
     */
135
    public abstract void move(File source, File target) throws IOException;
136

137
    /**
138
     * A file system representation for a VM that does not support NIO2.
139
     */
140
    @HashCodeAndEqualsPlugin.Enhance
141
    protected static class ForLegacyVm extends FileSystem {
×
142

143
        @Override
144
        public void copy(File source, File target) throws IOException {
145
            InputStream inputStream = new FileInputStream(source);
×
146
            try {
147
                OutputStream outputStream = new FileOutputStream(target);
×
148
                try {
149
                    byte[] buffer = new byte[1024];
×
150
                    int length;
151
                    while ((length = inputStream.read(buffer)) != -1) {
×
152
                        outputStream.write(buffer, 0, length);
×
153
                    }
154
                } finally {
155
                    outputStream.close();
×
156
                }
157
            } finally {
158
                inputStream.close();
×
159
            }
160
        }
×
161

162
        @Override
163
        public void move(File source, File target) throws IOException {
164
            InputStream inputStream = new FileInputStream(source);
×
165
            try {
166
                OutputStream outputStream = new FileOutputStream(target);
×
167
                try {
168
                    byte[] buffer = new byte[1024];
×
169
                    int length;
170
                    while ((length = inputStream.read(buffer)) != -1) {
×
171
                        outputStream.write(buffer, 0, length);
×
172
                    }
173
                } finally {
174
                    outputStream.close();
×
175
                }
176
            } finally {
177
                inputStream.close();
×
178
            }
179
            if (!source.delete()) {
×
180
                source.deleteOnExit();
×
181
            }
182
        }
×
183
    }
184

185
    /**
186
     * A file system representation for a VM that does support NIO2.
187
     */
188
    @HashCodeAndEqualsPlugin.Enhance
189
    protected static class ForNio2CapableVm extends FileSystem {
1✔
190

191
        /**
192
         * A dispatcher to resolve a {@link File} to a {@code java.nio.file.Path}.
193
         */
194
        private static final Dispatcher DISPATCHER = doPrivileged(JavaDispatcher.of(Dispatcher.class));
1✔
195

196
        /**
197
         * A dispatcher to resolve a dispatcher for {@code java.nio.file.Files}.
198
         */
199
        private static final Files FILES = doPrivileged(JavaDispatcher.of(Files.class));
1✔
200

201
        /**
202
         * A dispatcher to interact with {@code java.nio.file.StandardCopyOption}.
203
         */
204
        private static final StandardCopyOption STANDARD_COPY_OPTION = doPrivileged(JavaDispatcher.of(StandardCopyOption.class));
1✔
205

206
        @Override
207
        public void copy(File source, File target) throws IOException {
208
            Object[] option = STANDARD_COPY_OPTION.toArray(1);
1✔
209
            option[0] = STANDARD_COPY_OPTION.valueOf("REPLACE_EXISTING");
1✔
210
            FILES.copy(DISPATCHER.toPath(source), DISPATCHER.toPath(target), option);
1✔
211
        }
1✔
212

213
        @Override
214
        public void link(File source, File target) throws IOException {
215
            FILES.createLink(FILES.deleteIfExists(DISPATCHER.toPath(target)), DISPATCHER.toPath(source));
×
216
        }
×
217

218
        @Override
219
        public void move(File source, File target) throws IOException {
220
            Object[] option = STANDARD_COPY_OPTION.toArray(1);
1✔
221
            option[0] = STANDARD_COPY_OPTION.valueOf("REPLACE_EXISTING");
1✔
222
            FILES.move(DISPATCHER.toPath(source), DISPATCHER.toPath(target), option);
1✔
223
        }
1✔
224

225
        /**
226
         * A dispatcher to resolve a {@link File} to a {@code java.nio.file.Path}.
227
         */
228
        @JavaDispatcher.Proxied("java.io.File")
229
        protected interface Dispatcher {
230

231
            /**
232
             * Resolves a {@link File} to a {@code java.nio.file.Path}.
233
             *
234
             * @param value The file to convert.
235
             * @return The transformed {@code java.nio.file.Path}.
236
             * @throws IOException If an I/O exception occurs.
237
             */
238
            Object toPath(File value) throws IOException;
239
        }
240

241
        /**
242
         * A dispatcher to access the {@code java.nio.file.Files} API.
243
         */
244
        @JavaDispatcher.Proxied("java.nio.file.Files")
245
        protected interface Files {
246

247
            /**
248
             * Copies a file.
249
             *
250
             * @param source The source {@code java.nio.file.Path}.
251
             * @param target The target {@code java.nio.file.Path}.
252
             * @param option An array of copy options.
253
             * @return The copied file.
254
             * @throws IOException If an I/O exception occurs.
255
             */
256
            @JavaDispatcher.IsStatic
257
            Object copy(@JavaDispatcher.Proxied("java.nio.file.Path") Object source,
258
                        @JavaDispatcher.Proxied("java.nio.file.Path") Object target,
259
                        @JavaDispatcher.Proxied("java.nio.file.CopyOption") Object[] option) throws IOException;
260

261
            /**
262
             * Links a file.
263
             *
264
             * @param source The source {@code java.nio.file.Path}.
265
             * @param target The target {@code java.nio.file.Path}.
266
             * @return The copied file.
267
             * @throws IOException If an I/O exception occurs.
268
             */
269
            @JavaDispatcher.IsStatic
270
            Object createLink(@JavaDispatcher.Proxied("java.nio.file.Path") Object source,
271
                              @JavaDispatcher.Proxied("java.nio.file.Path") Object target) throws IOException;
272

273
            /**
274
             * Moves a file.
275
             *
276
             * @param source The source {@code java.nio.file.Path}.
277
             * @param target The target {@code java.nio.file.Path}.
278
             * @param option An array of copy options.
279
             * @return The moved file.
280
             * @throws IOException If an I/O exception occurs.
281
             */
282
            @JavaDispatcher.IsStatic
283
            Object move(@JavaDispatcher.Proxied("java.nio.file.Path") Object source,
284
                        @JavaDispatcher.Proxied("java.nio.file.Path") Object target,
285
                        @JavaDispatcher.Proxied("java.nio.file.CopyOption") Object[] option) throws IOException;
286

287
            /**
288
             * Deletes a file if it exists.
289
             *
290
             * @param file The {@code java.nio.file.Path} to delete if it exists.
291
             * @return The supplied file.
292
             * @throws IOException If an I/O exception occurs.
293
             */
294
            @JavaDispatcher.IsStatic
295
            Object deleteIfExists(@JavaDispatcher.Proxied("java.nio.file.Path") Object file) throws IOException;
296
        }
297

298
        /**
299
         * A dispatcher to interact with {@code java.nio.file.StandardCopyOption}.
300
         */
301
        @JavaDispatcher.Proxied("java.nio.file.StandardCopyOption")
302
        protected interface StandardCopyOption {
303

304
            /**
305
             * Creates an array of type {@code java.nio.file.StandardCopyOption}.
306
             *
307
             * @param size The array's size.
308
             * @return An array of type {@code java.nio.file.StandardCopyOption}.
309
             */
310
            @JavaDispatcher.Container
311
            Object[] toArray(int size);
312

313
            /**
314
             * Resolve an enumeration for {@code java.nio.file.StandardCopyOption}.
315
             *
316
             * @param name The enumeration name.
317
             * @return The enumeration value.
318
             */
319
            @JavaDispatcher.IsStatic
320
            Object valueOf(String name);
321
        }
322
    }
323
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc