Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java
32288 views
/*1* Copyright (c) 2008, 2013, 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 java.nio.ByteBuffer;29import java.io.IOException;30import java.util.*;31import sun.misc.Unsafe;3233import static sun.nio.fs.UnixConstants.*;34import static sun.nio.fs.LinuxNativeDispatcher.*;3536/**37* Linux implementation of UserDefinedFileAttributeView using extended attributes.38*/3940class LinuxUserDefinedFileAttributeView41extends AbstractUserDefinedFileAttributeView42{43private static final Unsafe unsafe = Unsafe.getUnsafe();4445// namespace for extended user attributes46private static final String USER_NAMESPACE = "user.";4748// maximum bytes in extended attribute name (includes namespace)49private static final int XATTR_NAME_MAX = 255;5051private byte[] nameAsBytes(UnixPath file, String name) throws IOException {52if (name == null)53throw new NullPointerException("'name' is null");54name = USER_NAMESPACE + name;55byte[] bytes = Util.toBytes(name);56if (bytes.length > XATTR_NAME_MAX) {57throw new FileSystemException(file.getPathForExceptionMessage(),58null, "'" + name + "' is too big");59}60return bytes;61}6263// Parses buffer as array of NULL-terminated C strings.64private List<String> asList(long address, int size) {65List<String> list = new ArrayList<>();66int start = 0;67int pos = 0;68while (pos < size) {69if (unsafe.getByte(address + pos) == 0) {70int len = pos - start;71byte[] value = new byte[len];72unsafe.copyMemory(null, address+start, value,73Unsafe.ARRAY_BYTE_BASE_OFFSET, len);74String s = Util.toString(value);75if (s.startsWith(USER_NAMESPACE)) {76s = s.substring(USER_NAMESPACE.length());77list.add(s);78}79start = pos + 1;80}81pos++;82}83return list;84}8586private final UnixPath file;87private final boolean followLinks;8889LinuxUserDefinedFileAttributeView(UnixPath file, boolean followLinks) {90this.file = file;91this.followLinks = followLinks;92}9394@Override95public List<String> list() throws IOException {96if (System.getSecurityManager() != null)97checkAccess(file.getPathForPermissionCheck(), true, false);9899int fd = file.openForAttributeAccess(followLinks);100NativeBuffer buffer = null;101try {102int size = 1024;103buffer = NativeBuffers.getNativeBuffer(size);104for (;;) {105try {106int n = flistxattr(fd, buffer.address(), size);107List<String> list = asList(buffer.address(), n);108return Collections.unmodifiableList(list);109} catch (UnixException x) {110// allocate larger buffer if required111if (x.errno() == ERANGE && size < 32*1024) {112buffer.release();113size *= 2;114buffer = null;115buffer = NativeBuffers.getNativeBuffer(size);116continue;117}118throw new FileSystemException(file.getPathForExceptionMessage(),119null, "Unable to get list of extended attributes: " +120x.getMessage());121}122}123} finally {124if (buffer != null)125buffer.release();126close(fd);127}128}129130@Override131public int size(String name) throws IOException {132if (System.getSecurityManager() != null)133checkAccess(file.getPathForPermissionCheck(), true, false);134135int fd = file.openForAttributeAccess(followLinks);136try {137// fgetxattr returns size if called with size==0138return fgetxattr(fd, nameAsBytes(file,name), 0L, 0);139} catch (UnixException x) {140throw new FileSystemException(file.getPathForExceptionMessage(),141null, "Unable to get size of extended attribute '" + name +142"': " + x.getMessage());143} finally {144close(fd);145}146}147148@Override149public int read(String name, ByteBuffer dst) throws IOException {150if (System.getSecurityManager() != null)151checkAccess(file.getPathForPermissionCheck(), true, false);152153if (dst.isReadOnly())154throw new IllegalArgumentException("Read-only buffer");155int pos = dst.position();156int lim = dst.limit();157assert (pos <= lim);158int rem = (pos <= lim ? lim - pos : 0);159160NativeBuffer nb;161long address;162if (dst instanceof sun.nio.ch.DirectBuffer) {163nb = null;164address = ((sun.nio.ch.DirectBuffer)dst).address() + pos;165} else {166// substitute with native buffer167nb = NativeBuffers.getNativeBuffer(rem);168address = nb.address();169}170171int fd = file.openForAttributeAccess(followLinks);172try {173try {174int n = fgetxattr(fd, nameAsBytes(file,name), address, rem);175176// if remaining is zero then fgetxattr returns the size177if (rem == 0) {178if (n > 0)179throw new UnixException(ERANGE);180return 0;181}182183// copy from buffer into backing array if necessary184if (nb != null) {185int off = dst.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET;186unsafe.copyMemory(null, address, dst.array(), off, n);187}188dst.position(pos + n);189return n;190} catch (UnixException x) {191String msg = (x.errno() == ERANGE) ?192"Insufficient space in buffer" : x.getMessage();193throw new FileSystemException(file.getPathForExceptionMessage(),194null, "Error reading extended attribute '" + name + "': " + msg);195} finally {196close(fd);197}198} finally {199if (nb != null)200nb.release();201}202}203204@Override205public int write(String name, ByteBuffer src) throws IOException {206if (System.getSecurityManager() != null)207checkAccess(file.getPathForPermissionCheck(), false, true);208209int pos = src.position();210int lim = src.limit();211assert (pos <= lim);212int rem = (pos <= lim ? lim - pos : 0);213214NativeBuffer nb;215long address;216if (src instanceof sun.nio.ch.DirectBuffer) {217nb = null;218address = ((sun.nio.ch.DirectBuffer)src).address() + pos;219} else {220// substitute with native buffer221nb = NativeBuffers.getNativeBuffer(rem);222address = nb.address();223224if (src.hasArray()) {225// copy from backing array into buffer226int off = src.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET;227unsafe.copyMemory(src.array(), off, null, address, rem);228} else {229// backing array not accessible so transfer via temporary array230byte[] tmp = new byte[rem];231src.get(tmp);232src.position(pos); // reset position as write may fail233unsafe.copyMemory(tmp, Unsafe.ARRAY_BYTE_BASE_OFFSET, null,234address, rem);235}236}237238int fd = file.openForAttributeAccess(followLinks);239try {240try {241fsetxattr(fd, nameAsBytes(file,name), address, rem);242src.position(pos + rem);243return rem;244} catch (UnixException x) {245throw new FileSystemException(file.getPathForExceptionMessage(),246null, "Error writing extended attribute '" + name + "': " +247x.getMessage());248} finally {249close(fd);250}251} finally {252if (nb != null)253nb.release();254}255}256257@Override258public void delete(String name) throws IOException {259if (System.getSecurityManager() != null)260checkAccess(file.getPathForPermissionCheck(), false, true);261262int fd = file.openForAttributeAccess(followLinks);263try {264fremovexattr(fd, nameAsBytes(file,name));265} catch (UnixException x) {266throw new FileSystemException(file.getPathForExceptionMessage(),267null, "Unable to delete extended attribute '" + name + "': " + x.getMessage());268} finally {269close(fd);270}271}272273/**274* Used by copyTo/moveTo to copy extended attributes from source to target.275*276* @param ofd277* file descriptor for source file278* @param nfd279* file descriptor for target file280*/281static void copyExtendedAttributes(int ofd, int nfd) {282NativeBuffer buffer = null;283try {284285// call flistxattr to get list of extended attributes.286int size = 1024;287buffer = NativeBuffers.getNativeBuffer(size);288for (;;) {289try {290size = flistxattr(ofd, buffer.address(), size);291break;292} catch (UnixException x) {293// allocate larger buffer if required294if (x.errno() == ERANGE && size < 32*1024) {295buffer.release();296size *= 2;297buffer = null;298buffer = NativeBuffers.getNativeBuffer(size);299continue;300}301302// unable to get list of attributes303return;304}305}306307// parse buffer as array of NULL-terminated C strings.308long address = buffer.address();309int start = 0;310int pos = 0;311while (pos < size) {312if (unsafe.getByte(address + pos) == 0) {313// extract attribute name and copy attribute to target.314// FIXME: We can avoid needless copying by using address+pos315// as the address of the name.316int len = pos - start;317byte[] name = new byte[len];318unsafe.copyMemory(null, address+start, name,319Unsafe.ARRAY_BYTE_BASE_OFFSET, len);320try {321copyExtendedAttribute(ofd, name, nfd);322} catch (UnixException ignore) {323// ignore324}325start = pos + 1;326}327pos++;328}329330} finally {331if (buffer != null)332buffer.release();333}334}335336private static void copyExtendedAttribute(int ofd, byte[] name, int nfd)337throws UnixException338{339int size = fgetxattr(ofd, name, 0L, 0);340NativeBuffer buffer = NativeBuffers.getNativeBuffer(size);341try {342long address = buffer.address();343size = fgetxattr(ofd, name, address, size);344fsetxattr(nfd, name, address, size);345} finally {346buffer.release();347}348}349}350351352