Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/classes/sun/nio/fs/WindowsUserDefinedFileAttributeView.java
32288 views
/*1* Copyright (c) 2008, 2011, 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 sun.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// enumerates the file streams by reading the stream headers using94// BackupRead95private List<String> listUsingBackupRead() throws IOException {96long handle = -1L;97try {98int flags = FILE_FLAG_BACKUP_SEMANTICS;99if (!followLinks && file.getFileSystem().supportsLinks())100flags |= FILE_FLAG_OPEN_REPARSE_POINT;101102handle = CreateFile(file.getPathForWin32Calls(),103GENERIC_READ,104FILE_SHARE_READ, // no write as we depend on file size105OPEN_EXISTING,106flags);107} catch (WindowsException x) {108x.rethrowAsIOException(file);109}110111// buffer to read stream header and stream name.112final int BUFFER_SIZE = 4096;113NativeBuffer buffer = null;114115// result with names of alternative data streams116final List<String> list = new ArrayList<>();117118try {119buffer = NativeBuffers.getNativeBuffer(BUFFER_SIZE);120long address = buffer.address();121122/**123* typedef struct _WIN32_STREAM_ID {124* DWORD dwStreamId;125* DWORD dwStreamAttributes;126* LARGE_INTEGER Size;127* DWORD dwStreamNameSize;128* WCHAR cStreamName[ANYSIZE_ARRAY];129* } WIN32_STREAM_ID;130*/131final int SIZEOF_STREAM_HEADER = 20;132final int OFFSETOF_STREAM_ID = 0;133final int OFFSETOF_STREAM_SIZE = 8;134final int OFFSETOF_STREAM_NAME_SIZE = 16;135136long context = 0L;137try {138for (;;) {139// read stream header140BackupResult result = BackupRead(handle, address,141SIZEOF_STREAM_HEADER, false, context);142context = result.context();143if (result.bytesTransferred() == 0)144break;145146int streamId = unsafe.getInt(address + OFFSETOF_STREAM_ID);147long streamSize = unsafe.getLong(address + OFFSETOF_STREAM_SIZE);148int nameSize = unsafe.getInt(address + OFFSETOF_STREAM_NAME_SIZE);149150// read stream name151if (nameSize > 0) {152result = BackupRead(handle, address, nameSize, false, context);153if (result.bytesTransferred() != nameSize)154break;155}156157// check for alternative data stream158if (streamId == BACKUP_ALTERNATE_DATA) {159char[] nameAsArray = new char[nameSize/2];160unsafe.copyMemory(null, address, nameAsArray,161Unsafe.ARRAY_CHAR_BASE_OFFSET, nameSize);162163String[] segs = new String(nameAsArray).split(":");164if (segs.length == 3)165list.add(segs[1]);166}167168// sparse blocks not currently handled as documentation169// is not sufficient on how the spase block can be skipped.170if (streamId == BACKUP_SPARSE_BLOCK) {171throw new IOException("Spare blocks not handled");172}173174// seek to end of stream175if (streamSize > 0L) {176BackupSeek(handle, streamSize, context);177}178}179} catch (WindowsException x) {180// failed to read or seek181throw new IOException(x.errorString());182} finally {183// release context184if (context != 0L) {185try {186BackupRead(handle, 0L, 0, true, context);187} catch (WindowsException ignore) { }188}189}190} finally {191if (buffer != null)192buffer.release();193CloseHandle(handle);194}195return Collections.unmodifiableList(list);196}197198@Override199public List<String> list() throws IOException {200if (System.getSecurityManager() != null)201checkAccess(file.getPathForPermissionCheck(), true, false);202// use stream APIs on Windwos Server 2003 and newer203if (file.getFileSystem().supportsStreamEnumeration()) {204return listUsingStreamEnumeration();205} else {206return listUsingBackupRead();207}208}209210@Override211public int size(String name) throws IOException {212if (System.getSecurityManager() != null)213checkAccess(file.getPathForPermissionCheck(), true, false);214215// wrap with channel216FileChannel fc = null;217try {218Set<OpenOption> opts = new HashSet<>();219opts.add(READ);220if (!followLinks)221opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);222fc = WindowsChannelFactory223.newFileChannel(join(file, name), null, opts, 0L);224} catch (WindowsException x) {225x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));226}227try {228long size = fc.size();229if (size > Integer.MAX_VALUE)230throw new ArithmeticException("Stream too large");231return (int)size;232} finally {233fc.close();234}235}236237@Override238public int read(String name, ByteBuffer dst) throws IOException {239if (System.getSecurityManager() != null)240checkAccess(file.getPathForPermissionCheck(), true, false);241242// wrap with channel243FileChannel fc = null;244try {245Set<OpenOption> opts = new HashSet<>();246opts.add(READ);247if (!followLinks)248opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);249fc = WindowsChannelFactory250.newFileChannel(join(file, name), null, opts, 0L);251} catch (WindowsException x) {252x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));253}254255// read to EOF (nothing we can do if I/O error occurs)256try {257if (fc.size() > dst.remaining())258throw new IOException("Stream too large");259int total = 0;260while (dst.hasRemaining()) {261int n = fc.read(dst);262if (n < 0)263break;264total += n;265}266return total;267} finally {268fc.close();269}270}271272@Override273public int write(String name, ByteBuffer src) throws IOException {274if (System.getSecurityManager() != null)275checkAccess(file.getPathForPermissionCheck(), false, true);276277/**278* Creating a named stream will cause the unnamed stream to be created279* if it doesn't already exist. To avoid this we open the unnamed stream280* for reading and hope it isn't deleted/moved while we create or281* replace the named stream. Opening the file without sharing options282* may cause sharing violations with other programs that are accessing283* the unnamed stream.284*/285long handle = -1L;286try {287int flags = FILE_FLAG_BACKUP_SEMANTICS;288if (!followLinks)289flags |= FILE_FLAG_OPEN_REPARSE_POINT;290291handle = CreateFile(file.getPathForWin32Calls(),292GENERIC_READ,293(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),294OPEN_EXISTING,295flags);296} catch (WindowsException x) {297x.rethrowAsIOException(file);298}299try {300Set<OpenOption> opts = new HashSet<>();301if (!followLinks)302opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);303opts.add(CREATE);304opts.add(WRITE);305opts.add(StandardOpenOption.TRUNCATE_EXISTING);306FileChannel named = null;307try {308named = WindowsChannelFactory309.newFileChannel(join(file, name), null, opts, 0L);310} catch (WindowsException x) {311x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));312}313// write value (nothing we can do if I/O error occurs)314try {315int rem = src.remaining();316while (src.hasRemaining()) {317named.write(src);318}319return rem;320} finally {321named.close();322}323} finally {324CloseHandle(handle);325}326}327328@Override329public void delete(String name) throws IOException {330if (System.getSecurityManager() != null)331checkAccess(file.getPathForPermissionCheck(), false, true);332333String path = WindowsLinkSupport.getFinalPath(file, followLinks);334String toDelete = join(path, name);335try {336DeleteFile(toDelete);337} catch (WindowsException x) {338x.rethrowAsIOException(toDelete);339}340}341}342343344