/*
 * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.nio.fs;

import java.nio.file.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.io.IOException;
import java.util.*;

import static sun.nio.fs.UnixNativeDispatcher.*;
import static sun.nio.fs.UnixConstants.*;
import static sun.nio.fs.SolarisConstants.*;

Solaris emulation of NamedAttributeView using extended attributes.
/** * Solaris emulation of NamedAttributeView using extended attributes. */
class SolarisUserDefinedFileAttributeView extends AbstractUserDefinedFileAttributeView { private static final byte[] HERE = { '.' }; private byte[] nameAsBytes(UnixPath file, String name) throws IOException { byte[] bytes = Util.toBytes(name); // "", "." and ".." not allowed if (bytes.length == 0 || bytes[0] == '.') { if (bytes.length <= 1 || (bytes.length == 2 && bytes[1] == '.')) { throw new FileSystemException(file.getPathForExceptionMessage(), null, "'" + name + "' is not a valid name"); } } return bytes; } private final UnixPath file; private final boolean followLinks; SolarisUserDefinedFileAttributeView(UnixPath file, boolean followLinks) { this.file = file; this.followLinks = followLinks; } @Override public List<String> list() throws IOException { if (System.getSecurityManager() != null) checkAccess(file.getPathForPermissionCheck(), true, false); int fd = -1; try { try { fd = file.openForAttributeAccess(followLinks); // open extended attribute directory int dfd = openat(fd, HERE, (O_RDONLY|O_XATTR), 0); long dp; try { dp = fdopendir(dfd); } catch (UnixException x) { close(dfd); throw x; } // read list of extended attributes List<String> list = new ArrayList<>(); try { byte[] name; while ((name = readdir(dp)) != null) { String s = Util.toString(name); if (!s.equals(".") && !s.equals("..")) list.add(s); } } finally { closedir(dp); } return Collections.unmodifiableList(list); } catch (UnixException x) { throw new FileSystemException(file.getPathForExceptionMessage(), null, "Unable to get list of extended attributes: " + x.getMessage()); } } finally { close(fd); } } @Override public int size(String name) throws IOException { if (System.getSecurityManager() != null) checkAccess(file.getPathForPermissionCheck(), true, false); int fd = -1; try { try { fd = file.openForAttributeAccess(followLinks); // open attribute file int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0); try { // read attribute's attributes UnixFileAttributes attrs = UnixFileAttributes.get(afd); long size = attrs.size(); if (size > Integer.MAX_VALUE) throw new ArithmeticException("Extended attribute value too large"); return (int)size; } finally { close(afd); } } catch (UnixException x) { throw new FileSystemException(file.getPathForExceptionMessage(), null, "Unable to get size of extended attribute '" + name + "': " + x.getMessage()); } } finally { close(fd); } } @Override public int read(String name, ByteBuffer dst) throws IOException { if (System.getSecurityManager() != null) checkAccess(file.getPathForPermissionCheck(), true, false); int fd = -1; try { try { fd = file.openForAttributeAccess(followLinks); // open attribute file int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0); // wrap with channel FileChannel fc = UnixChannelFactory.newFileChannel(afd, file.toString(), true, false); // read to EOF (nothing we can do if I/O error occurs) try { if (fc.size() > dst.remaining()) throw new IOException("Extended attribute file too large"); int total = 0; while (dst.hasRemaining()) { int n = fc.read(dst); if (n < 0) break; total += n; } return total; } finally { fc.close(); } } catch (UnixException x) { throw new FileSystemException(file.getPathForExceptionMessage(), null, "Unable to read extended attribute '" + name + "': " + x.getMessage()); } } finally { close(fd); } } @Override public int write(String name, ByteBuffer src) throws IOException { if (System.getSecurityManager() != null) checkAccess(file.getPathForPermissionCheck(), false, true); int fd = -1; try { try { fd = file.openForAttributeAccess(followLinks); // open/create attribute file int afd = openat(fd, nameAsBytes(file,name), (O_CREAT|O_WRONLY|O_TRUNC|O_XATTR), UnixFileModeAttribute.ALL_PERMISSIONS); // wrap with channel FileChannel fc = UnixChannelFactory.newFileChannel(afd, file.toString(), false, true); // write value (nothing we can do if I/O error occurs) try { int rem = src.remaining(); while (src.hasRemaining()) { fc.write(src); } return rem; } finally { fc.close(); } } catch (UnixException x) { throw new FileSystemException(file.getPathForExceptionMessage(), null, "Unable to write extended attribute '" + name + "': " + x.getMessage()); } } finally { close(fd); } } @Override public void delete(String name) throws IOException { if (System.getSecurityManager() != null) checkAccess(file.getPathForPermissionCheck(), false, true); int fd = -1; try { fd = file.openForAttributeAccess(followLinks); int dfd = openat(fd, HERE, (O_RDONLY|O_XATTR), 0); try { unlinkat(dfd, nameAsBytes(file,name), 0); } finally { close(dfd); } } catch (UnixException x) { throw new FileSystemException(file.getPathForExceptionMessage(), null, "Unable to delete extended attribute '" + name + "': " + x.getMessage()); } finally { close(fd); } }
Used by copyTo/moveTo to copy extended attributes from source to target.
Params:
  • ofd – file descriptor for source file
  • nfd – file descriptor for target file
/** * Used by copyTo/moveTo to copy extended attributes from source to target. * * @param ofd * file descriptor for source file * @param nfd * file descriptor for target file */
static void copyExtendedAttributes(int ofd, int nfd) { try { // open extended attribute directory int dfd = openat(ofd, HERE, (O_RDONLY|O_XATTR), 0); long dp = 0L; try { dp = fdopendir(dfd); } catch (UnixException x) { close(dfd); throw x; } // copy each extended attribute try { byte[] name; while ((name = readdir(dp)) != null) { // ignore "." and ".." if (name[0] == '.') { if (name.length == 1) continue; if (name.length == 2 && name[1] == '.') continue; } copyExtendedAttribute(ofd, name, nfd); } } finally { closedir(dp); } } catch (UnixException ignore) { } } private static void copyExtendedAttribute(int ofd, byte[] name, int nfd) throws UnixException { // open source attribute file int src = openat(ofd, name, (O_RDONLY|O_XATTR), 0); try { // create target attribute file int dst = openat(nfd, name, (O_CREAT|O_WRONLY|O_TRUNC|O_XATTR), UnixFileModeAttribute.ALL_PERMISSIONS); try { UnixCopyFile.transfer(dst, src, 0L); } finally { close(dst); } } finally { close(src); } } }