jdk/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java
changeset 2057 3acf8e5e2ca0
child 3065 452aaa2899fc
equal deleted inserted replaced
2056:115e09b7a004 2057:3acf8e5e2ca0
       
     1 /*
       
     2  * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.nio.fs;
       
    27 
       
    28 import java.nio.file.attribute.*;
       
    29 import java.util.*;
       
    30 import java.util.concurrent.TimeUnit;
       
    31 import java.io.IOException;
       
    32 import sun.misc.Unsafe;
       
    33 
       
    34 import static sun.nio.fs.UnixNativeDispatcher.*;
       
    35 import static sun.nio.fs.UnixConstants.*;
       
    36 
       
    37 /**
       
    38  * Linux implementation of DosFileAttributeView for use on file systems such
       
    39  * as ext3 that have extended attributes enabled and SAMBA configured to store
       
    40  * DOS attributes.
       
    41  */
       
    42 
       
    43 class LinuxDosFileAttributeView
       
    44     extends UnixFileAttributeViews.Basic implements DosFileAttributeView
       
    45 {
       
    46     private static final Unsafe unsafe = Unsafe.getUnsafe();
       
    47 
       
    48     private static final String READONLY_NAME = "readonly";
       
    49     private static final String ARCHIVE_NAME = "archive";
       
    50     private static final String SYSTEM_NAME = "system";
       
    51     private static final String HIDDEN_NAME = "hidden";
       
    52 
       
    53     private static final String DOS_XATTR_NAME = "user.DOSATTRIB";
       
    54     private static final byte[] DOS_XATTR_NAME_AS_BYTES = DOS_XATTR_NAME.getBytes();
       
    55 
       
    56     private static final int DOS_XATTR_READONLY = 0x01;
       
    57     private static final int DOS_XATTR_HIDDEN   = 0x02;
       
    58     private static final int DOS_XATTR_SYSTEM   = 0x04;
       
    59     private static final int DOS_XATTR_ARCHIVE  = 0x20;
       
    60 
       
    61     LinuxDosFileAttributeView(UnixPath file, boolean followLinks) {
       
    62         super(file, followLinks);
       
    63     }
       
    64 
       
    65     @Override
       
    66     public String name() {
       
    67         return "dos";
       
    68     }
       
    69 
       
    70     @Override
       
    71     public Object getAttribute(String attribute) throws IOException {
       
    72         if (attribute.equals(READONLY_NAME))
       
    73             return readAttributes().isReadOnly();
       
    74         if (attribute.equals(ARCHIVE_NAME))
       
    75             return readAttributes().isArchive();
       
    76         if (attribute.equals(SYSTEM_NAME))
       
    77             return readAttributes().isSystem();
       
    78         if (attribute.equals(HIDDEN_NAME))
       
    79             return readAttributes().isHidden();
       
    80         return super.getAttribute(attribute);
       
    81     }
       
    82 
       
    83     @Override
       
    84     public void setAttribute(String attribute, Object value)
       
    85         throws IOException
       
    86     {
       
    87         if (attribute.equals(READONLY_NAME)) {
       
    88             setReadOnly((Boolean)value);
       
    89             return;
       
    90         }
       
    91         if (attribute.equals(ARCHIVE_NAME)) {
       
    92             setArchive((Boolean)value);
       
    93             return;
       
    94         }
       
    95         if (attribute.equals(SYSTEM_NAME)) {
       
    96             setSystem((Boolean)value);
       
    97             return;
       
    98         }
       
    99         if (attribute.equals(HIDDEN_NAME)) {
       
   100             setHidden((Boolean)value);
       
   101             return;
       
   102         }
       
   103         super.setAttribute(attribute, value);
       
   104     }
       
   105 
       
   106     @Override
       
   107     public Map<String,?> readAttributes(String first, String[] rest)
       
   108         throws IOException
       
   109     {
       
   110         AttributesBuilder builder = AttributesBuilder.create(first, rest);
       
   111         DosFileAttributes attrs = readAttributes();
       
   112         addBasicAttributesToBuilder(attrs, builder);
       
   113         if (builder.match(READONLY_NAME))
       
   114             builder.add(READONLY_NAME, attrs.isReadOnly());
       
   115         if (builder.match(ARCHIVE_NAME))
       
   116             builder.add(ARCHIVE_NAME, attrs.isArchive());
       
   117         if (builder.match(SYSTEM_NAME))
       
   118             builder.add(SYSTEM_NAME, attrs.isSystem());
       
   119         if (builder.match(HIDDEN_NAME))
       
   120             builder.add(HIDDEN_NAME, attrs.isHidden());
       
   121         return builder.unmodifiableMap();
       
   122     }
       
   123 
       
   124     @Override
       
   125     public DosFileAttributes readAttributes() throws IOException {
       
   126         file.checkRead();
       
   127 
       
   128         int fd = file.openForAttributeAccess(followLinks);
       
   129         try {
       
   130              final UnixFileAttributes attrs = UnixFileAttributes.get(fd);
       
   131              final int dosAttribute = getDosAttribute(fd);
       
   132 
       
   133              return new DosFileAttributes() {
       
   134                 @Override
       
   135                 public long lastModifiedTime() {
       
   136                     return attrs.lastModifiedTime();
       
   137                 }
       
   138                 @Override
       
   139                 public long lastAccessTime() {
       
   140                     return attrs.lastAccessTime();
       
   141                 }
       
   142                 @Override
       
   143                 public long creationTime() {
       
   144                     return attrs.creationTime();
       
   145                 }
       
   146                 @Override
       
   147                 public TimeUnit resolution() {
       
   148                     return attrs.resolution();
       
   149                 }
       
   150                 @Override
       
   151                 public boolean isRegularFile() {
       
   152                     return attrs.isRegularFile();
       
   153                 }
       
   154                 @Override
       
   155                 public boolean isDirectory() {
       
   156                     return attrs.isDirectory();
       
   157                 }
       
   158                 @Override
       
   159                 public boolean isSymbolicLink() {
       
   160                     return attrs.isSymbolicLink();
       
   161                 }
       
   162                 @Override
       
   163                 public boolean isOther() {
       
   164                     return attrs.isOther();
       
   165                 }
       
   166                 @Override
       
   167                 public long size() {
       
   168                     return attrs.size();
       
   169                 }
       
   170                 @Override
       
   171                 public int linkCount() {
       
   172                     return attrs.linkCount();
       
   173                 }
       
   174                 @Override
       
   175                 public Object fileKey() {
       
   176                     return attrs.fileKey();
       
   177                 }
       
   178                 @Override
       
   179                 public boolean isReadOnly() {
       
   180                     return (dosAttribute & DOS_XATTR_READONLY) != 0;
       
   181                 }
       
   182                 @Override
       
   183                 public boolean isHidden() {
       
   184                     return (dosAttribute & DOS_XATTR_HIDDEN) != 0;
       
   185                 }
       
   186                 @Override
       
   187                 public boolean isArchive() {
       
   188                     return (dosAttribute & DOS_XATTR_ARCHIVE) != 0;
       
   189                 }
       
   190                 @Override
       
   191                 public boolean isSystem() {
       
   192                     return (dosAttribute & DOS_XATTR_SYSTEM) != 0;
       
   193                 }
       
   194              };
       
   195 
       
   196         } catch (UnixException x) {
       
   197             x.rethrowAsIOException(file);
       
   198             return null;    // keep compiler happy
       
   199         } finally {
       
   200             close(fd);
       
   201         }
       
   202     }
       
   203 
       
   204     @Override
       
   205     public void setReadOnly(boolean value) throws IOException {
       
   206         updateDosAttribute(DOS_XATTR_READONLY, value);
       
   207     }
       
   208 
       
   209     @Override
       
   210     public void setHidden(boolean value) throws IOException {
       
   211         updateDosAttribute(DOS_XATTR_HIDDEN, value);
       
   212     }
       
   213 
       
   214     @Override
       
   215     public void setArchive(boolean value) throws IOException {
       
   216         updateDosAttribute(DOS_XATTR_ARCHIVE, value);
       
   217     }
       
   218 
       
   219     @Override
       
   220     public void setSystem(boolean value) throws IOException {
       
   221         updateDosAttribute(DOS_XATTR_SYSTEM, value);
       
   222     }
       
   223 
       
   224     /**
       
   225      * Reads the value of the user.DOSATTRIB extended attribute
       
   226      */
       
   227     private int getDosAttribute(int fd) throws UnixException {
       
   228         final int size = 24;
       
   229 
       
   230         NativeBuffer buffer = NativeBuffers.getNativeBuffer(size);
       
   231         try {
       
   232             int len = LinuxNativeDispatcher
       
   233                 .fgetxattr(fd, DOS_XATTR_NAME_AS_BYTES, buffer.address(), size);
       
   234 
       
   235             if (len > 0) {
       
   236                 // ignore null terminator
       
   237                 if (unsafe.getByte(buffer.address()+len-1) == 0)
       
   238                     len--;
       
   239 
       
   240                 // convert to String and parse
       
   241                 byte[] buf = new byte[len];
       
   242                 unsafe.copyMemory(null, buffer.address(), buf,
       
   243                     Unsafe.ARRAY_BYTE_BASE_OFFSET, len);
       
   244                 String value = new String(buf); // platform encoding
       
   245 
       
   246                 // should be something like 0x20
       
   247                 if (value.length() >= 3 && value.startsWith("0x")) {
       
   248                     try {
       
   249                         return Integer.parseInt(value.substring(2), 16);
       
   250                     } catch (NumberFormatException x) {
       
   251                         // ignore
       
   252                     }
       
   253                 }
       
   254             }
       
   255             throw new UnixException("Value of " + DOS_XATTR_NAME + " attribute is invalid");
       
   256         } catch (UnixException x) {
       
   257             // default value when attribute does not exist
       
   258             if (x.errno() == ENODATA)
       
   259                 return 0;
       
   260             throw x;
       
   261         } finally {
       
   262             buffer.release();
       
   263         }
       
   264     }
       
   265 
       
   266     /**
       
   267      * Updates the value of the user.DOSATTRIB extended attribute
       
   268      */
       
   269     private void updateDosAttribute(int flag, boolean enable) throws IOException {
       
   270         file.checkWrite();
       
   271 
       
   272         int fd = file.openForAttributeAccess(followLinks);
       
   273         try {
       
   274             int oldValue = getDosAttribute(fd);
       
   275             int newValue = oldValue;
       
   276             if (enable) {
       
   277                 newValue |= flag;
       
   278             } else {
       
   279                 newValue &= ~flag;
       
   280             }
       
   281             if (newValue != oldValue) {
       
   282                 byte[] value = ("0x" + Integer.toHexString(newValue)).getBytes();
       
   283                 NativeBuffer buffer = NativeBuffers.asNativeBuffer(value);
       
   284                 try {
       
   285                     LinuxNativeDispatcher.fsetxattr(fd, DOS_XATTR_NAME_AS_BYTES,
       
   286                         buffer.address(), value.length+1);
       
   287                 } finally {
       
   288                     buffer.release();
       
   289                 }
       
   290             }
       
   291         } catch (UnixException x) {
       
   292             x.rethrowAsIOException(file);
       
   293         } finally {
       
   294             close(fd);
       
   295         }
       
   296     }
       
   297 }