/*
 * 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.attribute.*;
import java.util.Map;
import java.util.Set;
import java.io.IOException;
import jdk.internal.misc.Unsafe;

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

Linux implementation of DosFileAttributeView for use on file systems such as ext3 that have extended attributes enabled and SAMBA configured to store DOS attributes.
/** * Linux implementation of DosFileAttributeView for use on file systems such * as ext3 that have extended attributes enabled and SAMBA configured to store * DOS attributes. */
class LinuxDosFileAttributeView extends UnixFileAttributeViews.Basic implements DosFileAttributeView { private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final String READONLY_NAME = "readonly"; private static final String ARCHIVE_NAME = "archive"; private static final String SYSTEM_NAME = "system"; private static final String HIDDEN_NAME = "hidden"; private static final String DOS_XATTR_NAME = "user.DOSATTRIB"; private static final byte[] DOS_XATTR_NAME_AS_BYTES = Util.toBytes(DOS_XATTR_NAME); private static final int DOS_XATTR_READONLY = 0x01; private static final int DOS_XATTR_HIDDEN = 0x02; private static final int DOS_XATTR_SYSTEM = 0x04; private static final int DOS_XATTR_ARCHIVE = 0x20; // the names of the DOS attributes (includes basic) private static final Set<String> dosAttributeNames = Util.newSet(basicAttributeNames, READONLY_NAME, ARCHIVE_NAME, SYSTEM_NAME, HIDDEN_NAME); LinuxDosFileAttributeView(UnixPath file, boolean followLinks) { super(file, followLinks); } @Override public String name() { return "dos"; } @Override public void setAttribute(String attribute, Object value) throws IOException { if (attribute.equals(READONLY_NAME)) { setReadOnly((Boolean)value); return; } if (attribute.equals(ARCHIVE_NAME)) { setArchive((Boolean)value); return; } if (attribute.equals(SYSTEM_NAME)) { setSystem((Boolean)value); return; } if (attribute.equals(HIDDEN_NAME)) { setHidden((Boolean)value); return; } super.setAttribute(attribute, value); } @Override public Map<String,Object> readAttributes(String[] attributes) throws IOException { AttributesBuilder builder = AttributesBuilder.create(dosAttributeNames, attributes); DosFileAttributes attrs = readAttributes(); addRequestedBasicAttributes(attrs, builder); if (builder.match(READONLY_NAME)) builder.add(READONLY_NAME, attrs.isReadOnly()); if (builder.match(ARCHIVE_NAME)) builder.add(ARCHIVE_NAME, attrs.isArchive()); if (builder.match(SYSTEM_NAME)) builder.add(SYSTEM_NAME, attrs.isSystem()); if (builder.match(HIDDEN_NAME)) builder.add(HIDDEN_NAME, attrs.isHidden()); return builder.unmodifiableMap(); } @Override public DosFileAttributes readAttributes() throws IOException { file.checkRead(); int fd = -1; try { fd = file.openForAttributeAccess(followLinks); final UnixFileAttributes attrs = UnixFileAttributes.get(fd); final int dosAttribute = getDosAttribute(fd); return new DosFileAttributes() { @Override public FileTime lastModifiedTime() { return attrs.lastModifiedTime(); } @Override public FileTime lastAccessTime() { return attrs.lastAccessTime(); } @Override public FileTime creationTime() { return attrs.creationTime(); } @Override public boolean isRegularFile() { return attrs.isRegularFile(); } @Override public boolean isDirectory() { return attrs.isDirectory(); } @Override public boolean isSymbolicLink() { return attrs.isSymbolicLink(); } @Override public boolean isOther() { return attrs.isOther(); } @Override public long size() { return attrs.size(); } @Override public Object fileKey() { return attrs.fileKey(); } @Override public boolean isReadOnly() { return (dosAttribute & DOS_XATTR_READONLY) != 0; } @Override public boolean isHidden() { return (dosAttribute & DOS_XATTR_HIDDEN) != 0; } @Override public boolean isArchive() { return (dosAttribute & DOS_XATTR_ARCHIVE) != 0; } @Override public boolean isSystem() { return (dosAttribute & DOS_XATTR_SYSTEM) != 0; } }; } catch (UnixException x) { x.rethrowAsIOException(file); return null; // keep compiler happy } finally { close(fd); } } @Override public void setReadOnly(boolean value) throws IOException { updateDosAttribute(DOS_XATTR_READONLY, value); } @Override public void setHidden(boolean value) throws IOException { updateDosAttribute(DOS_XATTR_HIDDEN, value); } @Override public void setArchive(boolean value) throws IOException { updateDosAttribute(DOS_XATTR_ARCHIVE, value); } @Override public void setSystem(boolean value) throws IOException { updateDosAttribute(DOS_XATTR_SYSTEM, value); }
Reads the value of the user.DOSATTRIB extended attribute
/** * Reads the value of the user.DOSATTRIB extended attribute */
private int getDosAttribute(int fd) throws UnixException { final int size = 24; NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); try { int len = LinuxNativeDispatcher .fgetxattr(fd, DOS_XATTR_NAME_AS_BYTES, buffer.address(), size); if (len > 0) { // ignore null terminator if (unsafe.getByte(buffer.address()+len-1) == 0) len--; // convert to String and parse byte[] buf = new byte[len]; unsafe.copyMemory(null, buffer.address(), buf, Unsafe.ARRAY_BYTE_BASE_OFFSET, len); String value = Util.toString(buf); // should be something like 0x20 if (value.length() >= 3 && value.startsWith("0x")) { try { return Integer.parseInt(value.substring(2), 16); } catch (NumberFormatException x) { // ignore } } } throw new UnixException("Value of " + DOS_XATTR_NAME + " attribute is invalid"); } catch (UnixException x) { // default value when attribute does not exist if (x.errno() == ENODATA) return 0; throw x; } finally { buffer.release(); } }
Updates the value of the user.DOSATTRIB extended attribute
/** * Updates the value of the user.DOSATTRIB extended attribute */
private void updateDosAttribute(int flag, boolean enable) throws IOException { file.checkWrite(); int fd = -1; try { fd = file.openForAttributeAccess(followLinks); int oldValue = getDosAttribute(fd); int newValue = oldValue; if (enable) { newValue |= flag; } else { newValue &= ~flag; } if (newValue != oldValue) { byte[] value = Util.toBytes("0x" + Integer.toHexString(newValue)); NativeBuffer buffer = NativeBuffers.asNativeBuffer(value); try { LinuxNativeDispatcher.fsetxattr(fd, DOS_XATTR_NAME_AS_BYTES, buffer.address(), value.length+1); } finally { buffer.release(); } } } catch (UnixException x) { x.rethrowAsIOException(file); } finally { close(fd); } } }