Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/unix/classes/sun/nio/fs/UnixCopyFile.java
41137 views
1
/*
2
* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.nio.fs;
27
28
import java.io.IOException;
29
import java.nio.file.AtomicMoveNotSupportedException;
30
import java.nio.file.CopyOption;
31
import java.nio.file.DirectoryNotEmptyException;
32
import java.nio.file.FileAlreadyExistsException;
33
import java.nio.file.LinkOption;
34
import java.nio.file.LinkPermission;
35
import java.nio.file.StandardCopyOption;
36
import java.util.concurrent.ExecutionException;
37
import java.util.concurrent.TimeUnit;
38
39
import static sun.nio.fs.UnixNativeDispatcher.*;
40
import static sun.nio.fs.UnixConstants.*;
41
42
43
/**
44
* Unix implementation of Path#copyTo and Path#moveTo methods.
45
*/
46
47
class UnixCopyFile {
48
private UnixCopyFile() { }
49
50
// The flags that control how a file is copied or moved
51
private static class Flags {
52
boolean replaceExisting;
53
boolean atomicMove;
54
boolean followLinks;
55
boolean interruptible;
56
57
// the attributes to copy
58
boolean copyBasicAttributes;
59
boolean copyPosixAttributes;
60
boolean copyNonPosixAttributes;
61
62
// flags that indicate if we should fail if attributes cannot be copied
63
boolean failIfUnableToCopyBasic;
64
boolean failIfUnableToCopyPosix;
65
boolean failIfUnableToCopyNonPosix;
66
67
static Flags fromCopyOptions(CopyOption... options) {
68
Flags flags = new Flags();
69
flags.followLinks = true;
70
for (CopyOption option: options) {
71
if (option == StandardCopyOption.REPLACE_EXISTING) {
72
flags.replaceExisting = true;
73
continue;
74
}
75
if (option == LinkOption.NOFOLLOW_LINKS) {
76
flags.followLinks = false;
77
continue;
78
}
79
if (option == StandardCopyOption.COPY_ATTRIBUTES) {
80
// copy all attributes but only fail if basic attributes
81
// cannot be copied
82
flags.copyBasicAttributes = true;
83
flags.copyPosixAttributes = true;
84
flags.copyNonPosixAttributes = true;
85
flags.failIfUnableToCopyBasic = true;
86
continue;
87
}
88
if (ExtendedOptions.INTERRUPTIBLE.matches(option)) {
89
flags.interruptible = true;
90
continue;
91
}
92
if (option == null)
93
throw new NullPointerException();
94
throw new UnsupportedOperationException("Unsupported copy option");
95
}
96
return flags;
97
}
98
99
static Flags fromMoveOptions(CopyOption... options) {
100
Flags flags = new Flags();
101
for (CopyOption option: options) {
102
if (option == StandardCopyOption.ATOMIC_MOVE) {
103
flags.atomicMove = true;
104
continue;
105
}
106
if (option == StandardCopyOption.REPLACE_EXISTING) {
107
flags.replaceExisting = true;
108
continue;
109
}
110
if (option == LinkOption.NOFOLLOW_LINKS) {
111
// ignore
112
continue;
113
}
114
if (option == null)
115
throw new NullPointerException();
116
throw new UnsupportedOperationException("Unsupported copy option");
117
}
118
119
// a move requires that all attributes be copied but only fail if
120
// the basic attributes cannot be copied
121
flags.copyBasicAttributes = true;
122
flags.copyPosixAttributes = true;
123
flags.copyNonPosixAttributes = true;
124
flags.failIfUnableToCopyBasic = true;
125
return flags;
126
}
127
}
128
129
// copy directory from source to target
130
private static void copyDirectory(UnixPath source,
131
UnixFileAttributes attrs,
132
UnixPath target,
133
Flags flags)
134
throws IOException
135
{
136
try {
137
mkdir(target, attrs.mode());
138
} catch (UnixException x) {
139
x.rethrowAsIOException(target);
140
}
141
142
// no attributes to copy
143
if (!flags.copyBasicAttributes &&
144
!flags.copyPosixAttributes &&
145
!flags.copyNonPosixAttributes) return;
146
147
// open target directory if possible (this can fail when copying a
148
// directory for which we don't have read access).
149
int dfd = -1;
150
try {
151
dfd = open(target, O_RDONLY, 0);
152
} catch (UnixException x) {
153
// access to target directory required to copy named attributes
154
if (flags.copyNonPosixAttributes && flags.failIfUnableToCopyNonPosix) {
155
try { rmdir(target); } catch (UnixException ignore) { }
156
x.rethrowAsIOException(target);
157
}
158
}
159
160
boolean done = false;
161
try {
162
// copy owner/group/permissions
163
if (flags.copyPosixAttributes){
164
try {
165
if (dfd >= 0) {
166
fchown(dfd, attrs.uid(), attrs.gid());
167
fchmod(dfd, attrs.mode());
168
} else {
169
chown(target, attrs.uid(), attrs.gid());
170
chmod(target, attrs.mode());
171
}
172
} catch (UnixException x) {
173
// unable to set owner/group
174
if (flags.failIfUnableToCopyPosix)
175
x.rethrowAsIOException(target);
176
}
177
}
178
// copy other attributes
179
if (flags.copyNonPosixAttributes && (dfd >= 0)) {
180
int sfd = -1;
181
try {
182
sfd = open(source, O_RDONLY, 0);
183
} catch (UnixException x) {
184
if (flags.failIfUnableToCopyNonPosix)
185
x.rethrowAsIOException(source);
186
}
187
if (sfd >= 0) {
188
source.getFileSystem().copyNonPosixAttributes(sfd, dfd);
189
close(sfd);
190
}
191
}
192
// copy time stamps last
193
if (flags.copyBasicAttributes) {
194
try {
195
if (dfd >= 0 && futimesSupported()) {
196
futimes(dfd,
197
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
198
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
199
} else {
200
utimes(target,
201
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
202
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
203
}
204
} catch (UnixException x) {
205
// unable to set times
206
if (flags.failIfUnableToCopyBasic)
207
x.rethrowAsIOException(target);
208
}
209
}
210
done = true;
211
} finally {
212
if (dfd >= 0)
213
close(dfd);
214
if (!done) {
215
// rollback
216
try { rmdir(target); } catch (UnixException ignore) { }
217
}
218
}
219
}
220
221
// copy regular file from source to target
222
private static void copyFile(UnixPath source,
223
UnixFileAttributes attrs,
224
UnixPath target,
225
Flags flags,
226
long addressToPollForCancel)
227
throws IOException
228
{
229
int fi = -1;
230
try {
231
fi = open(source, O_RDONLY, 0);
232
} catch (UnixException x) {
233
x.rethrowAsIOException(source);
234
}
235
236
try {
237
// open new file
238
int fo = -1;
239
try {
240
fo = open(target,
241
(O_WRONLY |
242
O_CREAT |
243
O_EXCL),
244
attrs.mode());
245
} catch (UnixException x) {
246
x.rethrowAsIOException(target);
247
}
248
249
// set to true when file and attributes copied
250
boolean complete = false;
251
try {
252
// transfer bytes to target file
253
try {
254
transfer(fo, fi, addressToPollForCancel);
255
} catch (UnixException x) {
256
x.rethrowAsIOException(source, target);
257
}
258
// copy owner/permissions
259
if (flags.copyPosixAttributes) {
260
try {
261
fchown(fo, attrs.uid(), attrs.gid());
262
fchmod(fo, attrs.mode());
263
} catch (UnixException x) {
264
if (flags.failIfUnableToCopyPosix)
265
x.rethrowAsIOException(target);
266
}
267
}
268
// copy non POSIX attributes (depends on file system)
269
if (flags.copyNonPosixAttributes) {
270
source.getFileSystem().copyNonPosixAttributes(fi, fo);
271
}
272
// copy time attributes
273
if (flags.copyBasicAttributes) {
274
try {
275
if (futimesSupported()) {
276
futimes(fo,
277
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
278
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
279
} else {
280
utimes(target,
281
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
282
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
283
}
284
} catch (UnixException x) {
285
if (flags.failIfUnableToCopyBasic)
286
x.rethrowAsIOException(target);
287
}
288
}
289
complete = true;
290
} finally {
291
close(fo);
292
293
// copy of file or attributes failed so rollback
294
if (!complete) {
295
try {
296
unlink(target);
297
} catch (UnixException ignore) { }
298
}
299
}
300
} finally {
301
close(fi);
302
}
303
}
304
305
// copy symbolic link from source to target
306
private static void copyLink(UnixPath source,
307
UnixFileAttributes attrs,
308
UnixPath target,
309
Flags flags)
310
throws IOException
311
{
312
byte[] linktarget = null;
313
try {
314
linktarget = readlink(source);
315
} catch (UnixException x) {
316
x.rethrowAsIOException(source);
317
}
318
try {
319
symlink(linktarget, target);
320
321
if (flags.copyPosixAttributes) {
322
try {
323
lchown(target, attrs.uid(), attrs.gid());
324
} catch (UnixException x) {
325
// ignore since link attributes not required to be copied
326
}
327
}
328
} catch (UnixException x) {
329
x.rethrowAsIOException(target);
330
}
331
}
332
333
// copy special file from source to target
334
private static void copySpecial(UnixPath source,
335
UnixFileAttributes attrs,
336
UnixPath target,
337
Flags flags)
338
throws IOException
339
{
340
try {
341
mknod(target, attrs.mode(), attrs.rdev());
342
} catch (UnixException x) {
343
x.rethrowAsIOException(target);
344
}
345
boolean done = false;
346
try {
347
if (flags.copyPosixAttributes) {
348
try {
349
chown(target, attrs.uid(), attrs.gid());
350
chmod(target, attrs.mode());
351
} catch (UnixException x) {
352
if (flags.failIfUnableToCopyPosix)
353
x.rethrowAsIOException(target);
354
}
355
}
356
if (flags.copyBasicAttributes) {
357
try {
358
utimes(target,
359
attrs.lastAccessTime().to(TimeUnit.MICROSECONDS),
360
attrs.lastModifiedTime().to(TimeUnit.MICROSECONDS));
361
} catch (UnixException x) {
362
if (flags.failIfUnableToCopyBasic)
363
x.rethrowAsIOException(target);
364
}
365
}
366
done = true;
367
} finally {
368
if (!done) {
369
try { unlink(target); } catch (UnixException ignore) { }
370
}
371
}
372
}
373
374
// throw a DirectoryNotEmpty exception if appropriate
375
static void ensureEmptyDir(UnixPath dir) throws IOException {
376
try {
377
long ptr = opendir(dir);
378
try (UnixDirectoryStream stream =
379
new UnixDirectoryStream(dir, ptr, e -> true)) {
380
if (stream.iterator().hasNext()) {
381
throw new DirectoryNotEmptyException(
382
dir.getPathForExceptionMessage());
383
}
384
}
385
} catch (UnixException e) {
386
e.rethrowAsIOException(dir);
387
}
388
}
389
390
// move file from source to target
391
static void move(UnixPath source, UnixPath target, CopyOption... options)
392
throws IOException
393
{
394
// permission check
395
@SuppressWarnings("removal")
396
SecurityManager sm = System.getSecurityManager();
397
if (sm != null) {
398
source.checkWrite();
399
target.checkWrite();
400
}
401
402
// translate options into flags
403
Flags flags = Flags.fromMoveOptions(options);
404
405
// handle atomic rename case
406
if (flags.atomicMove) {
407
try {
408
rename(source, target);
409
} catch (UnixException x) {
410
if (x.errno() == EXDEV) {
411
throw new AtomicMoveNotSupportedException(
412
source.getPathForExceptionMessage(),
413
target.getPathForExceptionMessage(),
414
x.errorString());
415
}
416
x.rethrowAsIOException(source, target);
417
}
418
return;
419
}
420
421
// move using rename or copy+delete
422
UnixFileAttributes sourceAttrs = null;
423
UnixFileAttributes targetAttrs = null;
424
425
// get attributes of source file (don't follow links)
426
try {
427
sourceAttrs = UnixFileAttributes.get(source, false);
428
} catch (UnixException x) {
429
x.rethrowAsIOException(source);
430
}
431
432
// get attributes of target file (don't follow links)
433
try {
434
targetAttrs = UnixFileAttributes.get(target, false);
435
} catch (UnixException x) {
436
// ignore
437
}
438
boolean targetExists = (targetAttrs != null);
439
440
// if the target exists:
441
// 1. check if source and target are the same file
442
// 2. throw exception if REPLACE_EXISTING option is not set
443
// 3. delete target if REPLACE_EXISTING option set
444
if (targetExists) {
445
if (sourceAttrs.isSameFile(targetAttrs))
446
return; // nothing to do as files are identical
447
if (!flags.replaceExisting) {
448
throw new FileAlreadyExistsException(
449
target.getPathForExceptionMessage());
450
}
451
452
// attempt to delete target
453
try {
454
if (targetAttrs.isDirectory()) {
455
rmdir(target);
456
} else {
457
unlink(target);
458
}
459
} catch (UnixException x) {
460
// target is non-empty directory that can't be replaced.
461
if (targetAttrs.isDirectory() &&
462
(x.errno() == EEXIST || x.errno() == ENOTEMPTY))
463
{
464
throw new DirectoryNotEmptyException(
465
target.getPathForExceptionMessage());
466
}
467
x.rethrowAsIOException(target);
468
}
469
}
470
471
// first try rename
472
try {
473
rename(source, target);
474
return;
475
} catch (UnixException x) {
476
if (x.errno() != EXDEV && x.errno() != EISDIR) {
477
x.rethrowAsIOException(source, target);
478
}
479
}
480
481
// copy source to target
482
if (sourceAttrs.isDirectory()) {
483
ensureEmptyDir(source);
484
copyDirectory(source, sourceAttrs, target, flags);
485
} else {
486
if (sourceAttrs.isSymbolicLink()) {
487
copyLink(source, sourceAttrs, target, flags);
488
} else {
489
if (sourceAttrs.isDevice()) {
490
copySpecial(source, sourceAttrs, target, flags);
491
} else {
492
copyFile(source, sourceAttrs, target, flags, 0L);
493
}
494
}
495
}
496
497
// delete source
498
try {
499
if (sourceAttrs.isDirectory()) {
500
rmdir(source);
501
} else {
502
unlink(source);
503
}
504
} catch (UnixException x) {
505
// file was copied but unable to unlink the source file so attempt
506
// to remove the target and throw a reasonable exception
507
try {
508
if (sourceAttrs.isDirectory()) {
509
rmdir(target);
510
} else {
511
unlink(target);
512
}
513
} catch (UnixException ignore) { }
514
515
if (sourceAttrs.isDirectory() &&
516
(x.errno() == EEXIST || x.errno() == ENOTEMPTY))
517
{
518
throw new DirectoryNotEmptyException(
519
source.getPathForExceptionMessage());
520
}
521
x.rethrowAsIOException(source);
522
}
523
}
524
525
// copy file from source to target
526
static void copy(final UnixPath source,
527
final UnixPath target,
528
CopyOption... options) throws IOException
529
{
530
// permission checks
531
@SuppressWarnings("removal")
532
SecurityManager sm = System.getSecurityManager();
533
if (sm != null) {
534
source.checkRead();
535
target.checkWrite();
536
}
537
538
// translate options into flags
539
final Flags flags = Flags.fromCopyOptions(options);
540
541
UnixFileAttributes sourceAttrs = null;
542
UnixFileAttributes targetAttrs = null;
543
544
// get attributes of source file
545
try {
546
sourceAttrs = UnixFileAttributes.get(source, flags.followLinks);
547
} catch (UnixException x) {
548
x.rethrowAsIOException(source);
549
}
550
551
// if source file is symbolic link then we must check LinkPermission
552
if (sm != null && sourceAttrs.isSymbolicLink()) {
553
sm.checkPermission(new LinkPermission("symbolic"));
554
}
555
556
// get attributes of target file (don't follow links)
557
try {
558
targetAttrs = UnixFileAttributes.get(target, false);
559
} catch (UnixException x) {
560
// ignore
561
}
562
boolean targetExists = (targetAttrs != null);
563
564
// if the target exists:
565
// 1. check if source and target are the same file
566
// 2. throw exception if REPLACE_EXISTING option is not set
567
// 3. try to unlink the target
568
if (targetExists) {
569
if (sourceAttrs.isSameFile(targetAttrs))
570
return; // nothing to do as files are identical
571
if (!flags.replaceExisting)
572
throw new FileAlreadyExistsException(
573
target.getPathForExceptionMessage());
574
try {
575
if (targetAttrs.isDirectory()) {
576
rmdir(target);
577
} else {
578
unlink(target);
579
}
580
} catch (UnixException x) {
581
// target is non-empty directory that can't be replaced.
582
if (targetAttrs.isDirectory() &&
583
(x.errno() == EEXIST || x.errno() == ENOTEMPTY))
584
{
585
throw new DirectoryNotEmptyException(
586
target.getPathForExceptionMessage());
587
}
588
x.rethrowAsIOException(target);
589
}
590
}
591
592
// do the copy
593
if (sourceAttrs.isDirectory()) {
594
copyDirectory(source, sourceAttrs, target, flags);
595
return;
596
}
597
if (sourceAttrs.isSymbolicLink()) {
598
copyLink(source, sourceAttrs, target, flags);
599
return;
600
}
601
if (!flags.interruptible) {
602
// non-interruptible file copy
603
copyFile(source, sourceAttrs, target, flags, 0L);
604
return;
605
}
606
607
// interruptible file copy
608
final UnixFileAttributes attrsToCopy = sourceAttrs;
609
Cancellable copyTask = new Cancellable() {
610
@Override public void implRun() throws IOException {
611
copyFile(source, attrsToCopy, target, flags,
612
addressToPollForCancel());
613
}
614
};
615
try {
616
Cancellable.runInterruptibly(copyTask);
617
} catch (ExecutionException e) {
618
Throwable t = e.getCause();
619
if (t instanceof IOException)
620
throw (IOException)t;
621
throw new IOException(t);
622
}
623
}
624
625
// -- native methods --
626
627
static native void transfer(int dst, int src, long addressToPollForCancel)
628
throws UnixException;
629
630
static {
631
jdk.internal.loader.BootLoader.loadLibrary("nio");
632
}
633
634
}
635
636