Path: blob/master/src/java.base/windows/classes/sun/nio/fs/WindowsUserDefinedFileAttributeView.java
41139 views
/*1* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.fs;2627import java.nio.file.*;28import static java.nio.file.StandardOpenOption.*;29import java.nio.ByteBuffer;30import java.nio.channels.FileChannel;31import java.io.IOException;32import java.util.*;33import jdk.internal.misc.Unsafe;3435import static sun.nio.fs.WindowsNativeDispatcher.*;36import static sun.nio.fs.WindowsConstants.*;3738/**39* Windows emulation of NamedAttributeView using Alternative Data Streams40*/4142class WindowsUserDefinedFileAttributeView43extends AbstractUserDefinedFileAttributeView44{45private static final Unsafe unsafe = Unsafe.getUnsafe();4647// syntax to address named streams48private String join(String file, String name) {49if (name == null)50throw new NullPointerException("'name' is null");51return file + ":" + name;52}53private String join(WindowsPath file, String name) throws WindowsException {54return join(file.getPathForWin32Calls(), name);55}5657private final WindowsPath file;58private final boolean followLinks;5960WindowsUserDefinedFileAttributeView(WindowsPath file, boolean followLinks) {61this.file = file;62this.followLinks = followLinks;63}6465// enumerates the file streams using FindFirstStream/FindNextStream APIs.66private List<String> listUsingStreamEnumeration() throws IOException {67List<String> list = new ArrayList<>();68try {69FirstStream first = FindFirstStream(file.getPathForWin32Calls());70if (first != null) {71long handle = first.handle();72try {73// first stream is always ::$DATA for files74String name = first.name();75if (!name.equals("::$DATA")) {76String[] segs = name.split(":");77list.add(segs[1]);78}79while ((name = FindNextStream(handle)) != null) {80String[] segs = name.split(":");81list.add(segs[1]);82}83} finally {84FindClose(handle);85}86}87} catch (WindowsException x) {88x.rethrowAsIOException(file);89}90return Collections.unmodifiableList(list);91}9293@SuppressWarnings("removal")94@Override95public List<String> list() throws IOException {96if (System.getSecurityManager() != null)97checkAccess(file.getPathForPermissionCheck(), true, false);98return listUsingStreamEnumeration();99}100101@SuppressWarnings("removal")102@Override103public int size(String name) throws IOException {104if (System.getSecurityManager() != null)105checkAccess(file.getPathForPermissionCheck(), true, false);106107// wrap with channel108FileChannel fc = null;109try {110Set<OpenOption> opts = new HashSet<>();111opts.add(READ);112if (!followLinks)113opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);114fc = WindowsChannelFactory115.newFileChannel(join(file, name), null, opts, 0L);116} catch (WindowsException x) {117x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));118}119try {120long size = fc.size();121if (size > Integer.MAX_VALUE)122throw new ArithmeticException("Stream too large");123return (int)size;124} finally {125fc.close();126}127}128129@SuppressWarnings("removal")130@Override131public int read(String name, ByteBuffer dst) throws IOException {132if (System.getSecurityManager() != null)133checkAccess(file.getPathForPermissionCheck(), true, false);134135// wrap with channel136FileChannel fc = null;137try {138Set<OpenOption> opts = new HashSet<>();139opts.add(READ);140if (!followLinks)141opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);142fc = WindowsChannelFactory143.newFileChannel(join(file, name), null, opts, 0L);144} catch (WindowsException x) {145x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));146}147148// read to EOF (nothing we can do if I/O error occurs)149try {150if (fc.size() > dst.remaining())151throw new IOException("Stream too large");152int total = 0;153while (dst.hasRemaining()) {154int n = fc.read(dst);155if (n < 0)156break;157total += n;158}159return total;160} finally {161fc.close();162}163}164165@SuppressWarnings("removal")166@Override167public int write(String name, ByteBuffer src) throws IOException {168if (System.getSecurityManager() != null)169checkAccess(file.getPathForPermissionCheck(), false, true);170171/**172* Creating a named stream will cause the unnamed stream to be created173* if it doesn't already exist. To avoid this we open the unnamed stream174* for reading and hope it isn't deleted/moved while we create or175* replace the named stream. Opening the file without sharing options176* may cause sharing violations with other programs that are accessing177* the unnamed stream.178*/179long handle = -1L;180try {181int flags = FILE_FLAG_BACKUP_SEMANTICS;182if (!followLinks)183flags |= FILE_FLAG_OPEN_REPARSE_POINT;184185handle = CreateFile(file.getPathForWin32Calls(),186GENERIC_READ,187(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),188OPEN_EXISTING,189flags);190} catch (WindowsException x) {191x.rethrowAsIOException(file);192}193try {194Set<OpenOption> opts = new HashSet<>();195if (!followLinks)196opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);197opts.add(CREATE);198opts.add(WRITE);199opts.add(StandardOpenOption.TRUNCATE_EXISTING);200FileChannel named = null;201try {202named = WindowsChannelFactory203.newFileChannel(join(file, name), null, opts, 0L);204} catch (WindowsException x) {205x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));206}207// write value (nothing we can do if I/O error occurs)208try {209int rem = src.remaining();210while (src.hasRemaining()) {211named.write(src);212}213return rem;214} finally {215named.close();216}217} finally {218CloseHandle(handle);219}220}221222@SuppressWarnings("removal")223@Override224public void delete(String name) throws IOException {225if (System.getSecurityManager() != null)226checkAccess(file.getPathForPermissionCheck(), false, true);227228String path = WindowsLinkSupport.getFinalPath(file, followLinks);229String toDelete = join(path, name);230try {231DeleteFile(toDelete);232} catch (WindowsException x) {233x.rethrowAsIOException(toDelete);234}235}236}237238239