Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/windows/classes/sun/nio/fs/WindowsFileCopy.java
41139 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.nio.file.*;
29
import java.io.IOException;
30
import java.util.concurrent.ExecutionException;
31
32
import static sun.nio.fs.WindowsNativeDispatcher.*;
33
import static sun.nio.fs.WindowsConstants.*;
34
35
/**
36
* Utility methods for copying and moving files.
37
*/
38
39
class WindowsFileCopy {
40
private WindowsFileCopy() {
41
}
42
43
/**
44
* Copy file from source to target
45
*/
46
static void copy(final WindowsPath source,
47
final WindowsPath target,
48
CopyOption... options)
49
throws IOException
50
{
51
// map options
52
boolean replaceExisting = false;
53
boolean copyAttributes = false;
54
boolean followLinks = true;
55
boolean interruptible = false;
56
for (CopyOption option: options) {
57
if (option == StandardCopyOption.REPLACE_EXISTING) {
58
replaceExisting = true;
59
continue;
60
}
61
if (option == LinkOption.NOFOLLOW_LINKS) {
62
followLinks = false;
63
continue;
64
}
65
if (option == StandardCopyOption.COPY_ATTRIBUTES) {
66
copyAttributes = true;
67
continue;
68
}
69
if (ExtendedOptions.INTERRUPTIBLE.matches(option)) {
70
interruptible = true;
71
continue;
72
}
73
if (option == null)
74
throw new NullPointerException();
75
throw new UnsupportedOperationException("Unsupported copy option");
76
}
77
78
// check permissions. If the source file is a symbolic link then
79
// later we must also check LinkPermission
80
@SuppressWarnings("removal")
81
SecurityManager sm = System.getSecurityManager();
82
if (sm != null) {
83
source.checkRead();
84
target.checkWrite();
85
}
86
87
// get attributes of source file
88
// attempt to get attributes of target file
89
// if both files are the same there is nothing to do
90
// if target exists and !replace then throw exception
91
92
WindowsFileAttributes sourceAttrs = null;
93
WindowsFileAttributes targetAttrs = null;
94
95
long sourceHandle = 0L;
96
try {
97
sourceHandle = source.openForReadAttributeAccess(followLinks);
98
} catch (WindowsException x) {
99
x.rethrowAsIOException(source);
100
}
101
try {
102
// source attributes
103
try {
104
sourceAttrs = WindowsFileAttributes.readAttributes(sourceHandle);
105
} catch (WindowsException x) {
106
x.rethrowAsIOException(source);
107
}
108
109
// open target (don't follow links)
110
long targetHandle = 0L;
111
try {
112
targetHandle = target.openForReadAttributeAccess(false);
113
try {
114
targetAttrs = WindowsFileAttributes.readAttributes(targetHandle);
115
116
// if both files are the same then nothing to do
117
if (WindowsFileAttributes.isSameFile(sourceAttrs, targetAttrs)) {
118
return;
119
}
120
121
// can't replace file
122
if (!replaceExisting) {
123
throw new FileAlreadyExistsException(
124
target.getPathForExceptionMessage());
125
}
126
127
} finally {
128
CloseHandle(targetHandle);
129
}
130
} catch (WindowsException x) {
131
// ignore
132
}
133
134
} finally {
135
CloseHandle(sourceHandle);
136
}
137
138
// if source file is a symbolic link then we must check for LinkPermission
139
if (sm != null && sourceAttrs.isSymbolicLink()) {
140
sm.checkPermission(new LinkPermission("symbolic"));
141
}
142
143
// if source is a Unix domain socket, we don't want to copy it for various
144
// reasons including consistency with Unix
145
if (sourceAttrs.isUnixDomainSocket()) {
146
throw new IOException("Can not copy socket file");
147
}
148
149
final String sourcePath = asWin32Path(source);
150
final String targetPath = asWin32Path(target);
151
152
// if target exists then delete it.
153
if (targetAttrs != null) {
154
try {
155
if (targetAttrs.isDirectory() || targetAttrs.isDirectoryLink()) {
156
RemoveDirectory(targetPath);
157
} else {
158
DeleteFile(targetPath);
159
}
160
} catch (WindowsException x) {
161
if (targetAttrs.isDirectory()) {
162
// ERROR_ALREADY_EXISTS is returned when attempting to delete
163
// non-empty directory on SAMBA servers.
164
if (x.lastError() == ERROR_DIR_NOT_EMPTY ||
165
x.lastError() == ERROR_ALREADY_EXISTS)
166
{
167
throw new DirectoryNotEmptyException(
168
target.getPathForExceptionMessage());
169
}
170
}
171
x.rethrowAsIOException(target);
172
}
173
}
174
175
// Use CopyFileEx if the file is not a directory or junction
176
if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink()) {
177
final int flags = (!followLinks) ? COPY_FILE_COPY_SYMLINK : 0;
178
179
if (interruptible) {
180
// interruptible copy
181
Cancellable copyTask = new Cancellable() {
182
@Override
183
public int cancelValue() {
184
return 1; // TRUE
185
}
186
@Override
187
public void implRun() throws IOException {
188
try {
189
CopyFileEx(sourcePath, targetPath, flags,
190
addressToPollForCancel());
191
} catch (WindowsException x) {
192
x.rethrowAsIOException(source, target);
193
}
194
}
195
};
196
try {
197
Cancellable.runInterruptibly(copyTask);
198
} catch (ExecutionException e) {
199
Throwable t = e.getCause();
200
if (t instanceof IOException)
201
throw (IOException)t;
202
throw new IOException(t);
203
}
204
} else {
205
// non-interruptible copy
206
try {
207
CopyFileEx(sourcePath, targetPath, flags, 0L);
208
} catch (WindowsException x) {
209
x.rethrowAsIOException(source, target);
210
}
211
}
212
if (copyAttributes) {
213
// CopyFileEx does not copy security attributes
214
try {
215
copySecurityAttributes(source, target, followLinks);
216
} catch (IOException x) {
217
// ignore
218
}
219
}
220
return;
221
}
222
223
// copy directory or directory junction
224
try {
225
if (sourceAttrs.isDirectory()) {
226
CreateDirectory(targetPath, 0L);
227
} else {
228
String linkTarget = WindowsLinkSupport.readLink(source);
229
int flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
230
CreateSymbolicLink(targetPath,
231
WindowsPath.addPrefixIfNeeded(linkTarget),
232
flags);
233
}
234
} catch (WindowsException x) {
235
x.rethrowAsIOException(target);
236
}
237
if (copyAttributes) {
238
// copy DOS/timestamps attributes
239
WindowsFileAttributeViews.Dos view =
240
WindowsFileAttributeViews.createDosView(target, false);
241
try {
242
view.setAttributes(sourceAttrs);
243
} catch (IOException x) {
244
if (sourceAttrs.isDirectory()) {
245
try {
246
RemoveDirectory(targetPath);
247
} catch (WindowsException ignore) { }
248
}
249
}
250
251
// copy security attributes. If this fail it doesn't cause the move
252
// to fail.
253
try {
254
copySecurityAttributes(source, target, followLinks);
255
} catch (IOException ignore) { }
256
}
257
}
258
259
// throw a DirectoryNotEmpty exception if not empty
260
static void ensureEmptyDir(WindowsPath dir) throws IOException {
261
try (WindowsDirectoryStream dirStream =
262
new WindowsDirectoryStream(dir, (e) -> true)) {
263
if (dirStream.iterator().hasNext()) {
264
throw new DirectoryNotEmptyException(
265
dir.getPathForExceptionMessage());
266
}
267
}
268
}
269
270
/**
271
* Move file from source to target
272
*/
273
static void move(WindowsPath source, WindowsPath target, CopyOption... options)
274
throws IOException
275
{
276
// map options
277
boolean atomicMove = false;
278
boolean replaceExisting = false;
279
for (CopyOption option: options) {
280
if (option == StandardCopyOption.ATOMIC_MOVE) {
281
atomicMove = true;
282
continue;
283
}
284
if (option == StandardCopyOption.REPLACE_EXISTING) {
285
replaceExisting = true;
286
continue;
287
}
288
if (option == LinkOption.NOFOLLOW_LINKS) {
289
// ignore
290
continue;
291
}
292
if (option == null) throw new NullPointerException();
293
throw new UnsupportedOperationException("Unsupported copy option");
294
}
295
296
@SuppressWarnings("removal")
297
SecurityManager sm = System.getSecurityManager();
298
if (sm != null) {
299
source.checkWrite();
300
target.checkWrite();
301
}
302
303
final String sourcePath = asWin32Path(source);
304
final String targetPath = asWin32Path(target);
305
306
// atomic case
307
if (atomicMove) {
308
try {
309
MoveFileEx(sourcePath, targetPath, MOVEFILE_REPLACE_EXISTING);
310
} catch (WindowsException x) {
311
if (x.lastError() == ERROR_NOT_SAME_DEVICE) {
312
throw new AtomicMoveNotSupportedException(
313
source.getPathForExceptionMessage(),
314
target.getPathForExceptionMessage(),
315
x.errorString());
316
}
317
x.rethrowAsIOException(source, target);
318
}
319
return;
320
}
321
322
// get attributes of source file
323
// attempt to get attributes of target file
324
// if both files are the same there is nothing to do
325
// if target exists and !replace then throw exception
326
327
WindowsFileAttributes sourceAttrs = null;
328
WindowsFileAttributes targetAttrs = null;
329
330
long sourceHandle = 0L;
331
try {
332
sourceHandle = source.openForReadAttributeAccess(false);
333
} catch (WindowsException x) {
334
x.rethrowAsIOException(source);
335
}
336
try {
337
// source attributes
338
try {
339
sourceAttrs = WindowsFileAttributes.readAttributes(sourceHandle);
340
} catch (WindowsException x) {
341
x.rethrowAsIOException(source);
342
}
343
344
// open target (don't follow links)
345
long targetHandle = 0L;
346
try {
347
targetHandle = target.openForReadAttributeAccess(false);
348
try {
349
targetAttrs = WindowsFileAttributes.readAttributes(targetHandle);
350
351
// if both files are the same then nothing to do
352
if (WindowsFileAttributes.isSameFile(sourceAttrs, targetAttrs)) {
353
return;
354
}
355
356
// can't replace file
357
if (!replaceExisting) {
358
throw new FileAlreadyExistsException(
359
target.getPathForExceptionMessage());
360
}
361
362
} finally {
363
CloseHandle(targetHandle);
364
}
365
} catch (WindowsException x) {
366
// ignore
367
}
368
369
} finally {
370
CloseHandle(sourceHandle);
371
}
372
373
// if target exists then delete it.
374
if (targetAttrs != null) {
375
try {
376
if (targetAttrs.isDirectory() || targetAttrs.isDirectoryLink()) {
377
RemoveDirectory(targetPath);
378
} else {
379
DeleteFile(targetPath);
380
}
381
} catch (WindowsException x) {
382
if (targetAttrs.isDirectory()) {
383
// ERROR_ALREADY_EXISTS is returned when attempting to delete
384
// non-empty directory on SAMBA servers.
385
if (x.lastError() == ERROR_DIR_NOT_EMPTY ||
386
x.lastError() == ERROR_ALREADY_EXISTS)
387
{
388
throw new DirectoryNotEmptyException(
389
target.getPathForExceptionMessage());
390
}
391
}
392
x.rethrowAsIOException(target);
393
}
394
}
395
396
// first try MoveFileEx (no options). If target is on same volume then
397
// all attributes (including security attributes) are preserved.
398
try {
399
MoveFileEx(sourcePath, targetPath, 0);
400
return;
401
} catch (WindowsException x) {
402
if (x.lastError() != ERROR_NOT_SAME_DEVICE)
403
x.rethrowAsIOException(source, target);
404
}
405
406
// target is on different volume so use MoveFileEx with copy option
407
if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink()) {
408
try {
409
MoveFileEx(sourcePath, targetPath, MOVEFILE_COPY_ALLOWED);
410
} catch (WindowsException x) {
411
x.rethrowAsIOException(source, target);
412
}
413
// MoveFileEx does not copy security attributes when moving
414
// across volumes.
415
try {
416
copySecurityAttributes(source, target, false);
417
} catch (IOException x) {
418
// ignore
419
}
420
return;
421
}
422
423
// moving directory or directory-link to another file system
424
assert sourceAttrs.isDirectory() || sourceAttrs.isDirectoryLink();
425
426
// create new directory or directory junction
427
try {
428
if (sourceAttrs.isDirectory()) {
429
ensureEmptyDir(source);
430
CreateDirectory(targetPath, 0L);
431
} else {
432
String linkTarget = WindowsLinkSupport.readLink(source);
433
CreateSymbolicLink(targetPath,
434
WindowsPath.addPrefixIfNeeded(linkTarget),
435
SYMBOLIC_LINK_FLAG_DIRECTORY);
436
}
437
} catch (WindowsException x) {
438
x.rethrowAsIOException(target);
439
}
440
441
// copy timestamps/DOS attributes
442
WindowsFileAttributeViews.Dos view =
443
WindowsFileAttributeViews.createDosView(target, false);
444
try {
445
view.setAttributes(sourceAttrs);
446
} catch (IOException x) {
447
// rollback
448
try {
449
RemoveDirectory(targetPath);
450
} catch (WindowsException ignore) { }
451
throw x;
452
}
453
454
// copy security attributes. If this fails it doesn't cause the move
455
// to fail.
456
try {
457
copySecurityAttributes(source, target, false);
458
} catch (IOException ignore) { }
459
460
// delete source
461
try {
462
RemoveDirectory(sourcePath);
463
} catch (WindowsException x) {
464
// rollback
465
try {
466
RemoveDirectory(targetPath);
467
} catch (WindowsException ignore) { }
468
// ERROR_ALREADY_EXISTS is returned when attempting to delete
469
// non-empty directory on SAMBA servers.
470
if (x.lastError() == ERROR_DIR_NOT_EMPTY ||
471
x.lastError() == ERROR_ALREADY_EXISTS)
472
{
473
throw new DirectoryNotEmptyException(
474
target.getPathForExceptionMessage());
475
}
476
x.rethrowAsIOException(source);
477
}
478
}
479
480
481
private static String asWin32Path(WindowsPath path) throws IOException {
482
try {
483
return path.getPathForWin32Calls();
484
} catch (WindowsException x) {
485
x.rethrowAsIOException(path);
486
return null;
487
}
488
}
489
490
/**
491
* Copy DACL/owner/group from source to target
492
*/
493
private static void copySecurityAttributes(WindowsPath source,
494
WindowsPath target,
495
boolean followLinks)
496
throws IOException
497
{
498
String path = WindowsLinkSupport.getFinalPath(source, followLinks);
499
500
// may need SeRestorePrivilege to set file owner
501
WindowsSecurity.Privilege priv =
502
WindowsSecurity.enablePrivilege("SeRestorePrivilege");
503
try {
504
int request = (DACL_SECURITY_INFORMATION |
505
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION);
506
NativeBuffer buffer =
507
WindowsAclFileAttributeView.getFileSecurity(path, request);
508
try {
509
try {
510
SetFileSecurity(target.getPathForWin32Calls(), request,
511
buffer.address());
512
} catch (WindowsException x) {
513
x.rethrowAsIOException(target);
514
}
515
} finally {
516
buffer.release();
517
}
518
} finally {
519
priv.drop();
520
}
521
}
522
}
523
524