RFR: 8073061: (fs) Files.copy(foo, bar, REPLACE_EXISTING) deletes bar even if foo is not readable [v5]

Alan Bateman alanb at openjdk.org
Fri Sep 15 16:42:47 UTC 2023


On Fri, 15 Sep 2023 16:25:02 GMT, Brian Burkhalter <bpb at openjdk.org> wrote:

>> src/java.base/share/classes/java/nio/file/CopyMoveHelper.java line 138:
>> 
>>> 136: 
>>> 137:             Files.deleteIfExists(target);
>>> 138:         } else if (Files.exists(target))
>> 
>> Looking at again and I think this can be dropped from the cross provider case. Files.copy(InputStream, Path) can optionally replace the target so this only need a delete of the target the the source is a directory. So something like this might be simpler:
>> 
>> 
>> @@ -69,6 +71,14 @@ static CopyOptions parse(CopyOption... options) {
>>              }
>>              return result;
>>          }
>> +
>> +        CopyOption[] replaceExitingOrEmpty() {
>> +            if (replaceExisting) {
>> +                return new CopyOption[] { StandardCopyOption.REPLACE_EXISTING };
>> +            } else {
>> +                return new CopyOption[0];
>> +            }
>> +        }
>>      }
>>  
>>      /**
>> @@ -129,18 +139,14 @@ static void copyToForeignTarget(Path source, Path target,
>>          if (sourceAttrs.isSymbolicLink())
>>              throw new IOException("Copying of symbolic links not supported");
>>  
>> -        // delete target if it exists and REPLACE_EXISTING is specified
>> -        if (opts.replaceExisting) {
>> -            Files.deleteIfExists(target);
>> -        } else if (Files.exists(target))
>> -            throw new FileAlreadyExistsException(target.toString());
>> -
>>          // create directory or copy file
>>          if (sourceAttrs.isDirectory()) {
>> +            if (opts.replaceExisting)
>> +                Files.deleteIfExists(target);
>>              Files.createDirectory(target);
>>          } else {
>>              try (InputStream in = Files.newInputStream(source)) {
>> -                Files.copy(in, target);
>> +                Files.copy(in, target, opts.replaceExitingOrEmpty());
>>              }
>>          }
>
> This change looks reasonable, but it causes `CopyAndMove` to fail at line 777 in
> 
> * Test: copy regular file, target exists
> 
> due to an exception in `Files.copy`:
> 
> try (InputStream in = Files.newInputStream(source)) {
>     Files.copy(in, target, opts.replaceExistingOrEmpty());
> }
> 
> The new method `replaceExistingOrEmpty` returns a zero-length array as `copyAttributes` is `false`.

There may be a typo, it should be an empty array when replaceExisting (not copyAttributes) is false. The main point is that copy from an input stream to a file already supports REPLACE_EXISTING option.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/15501#discussion_r1327547600


More information about the nio-dev mailing list