1/* 2 * Copyright (c) 2008, 2015, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package sun.nio.fs; 27 28import java.nio.file.attribute.*; 29import java.util.Map; 30import java.util.Set; 31import java.io.IOException; 32import jdk.internal.misc.Unsafe; 33 34import static sun.nio.fs.UnixNativeDispatcher.*; 35import 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 43class 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 = Util.toBytes(DOS_XATTR_NAME); 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 // the names of the DOS attributes (includes basic) 62 private static final Set<String> dosAttributeNames = 63 Util.newSet(basicAttributeNames, READONLY_NAME, ARCHIVE_NAME, SYSTEM_NAME, HIDDEN_NAME); 64 65 LinuxDosFileAttributeView(UnixPath file, boolean followLinks) { 66 super(file, followLinks); 67 } 68 69 @Override 70 public String name() { 71 return "dos"; 72 } 73 74 @Override 75 public void setAttribute(String attribute, Object value) 76 throws IOException 77 { 78 if (attribute.equals(READONLY_NAME)) { 79 setReadOnly((Boolean)value); 80 return; 81 } 82 if (attribute.equals(ARCHIVE_NAME)) { 83 setArchive((Boolean)value); 84 return; 85 } 86 if (attribute.equals(SYSTEM_NAME)) { 87 setSystem((Boolean)value); 88 return; 89 } 90 if (attribute.equals(HIDDEN_NAME)) { 91 setHidden((Boolean)value); 92 return; 93 } 94 super.setAttribute(attribute, value); 95 } 96 97 @Override 98 public Map<String,Object> readAttributes(String[] attributes) 99 throws IOException 100 { 101 AttributesBuilder builder = 102 AttributesBuilder.create(dosAttributeNames, attributes); 103 DosFileAttributes attrs = readAttributes(); 104 addRequestedBasicAttributes(attrs, builder); 105 if (builder.match(READONLY_NAME)) 106 builder.add(READONLY_NAME, attrs.isReadOnly()); 107 if (builder.match(ARCHIVE_NAME)) 108 builder.add(ARCHIVE_NAME, attrs.isArchive()); 109 if (builder.match(SYSTEM_NAME)) 110 builder.add(SYSTEM_NAME, attrs.isSystem()); 111 if (builder.match(HIDDEN_NAME)) 112 builder.add(HIDDEN_NAME, attrs.isHidden()); 113 return builder.unmodifiableMap(); 114 } 115 116 @Override 117 public DosFileAttributes readAttributes() throws IOException { 118 file.checkRead(); 119 120 int fd = -1; 121 try { 122 fd = file.openForAttributeAccess(followLinks); 123 final UnixFileAttributes attrs = UnixFileAttributes.get(fd); 124 final int dosAttribute = getDosAttribute(fd); 125 126 return new DosFileAttributes() { 127 @Override 128 public FileTime lastModifiedTime() { 129 return attrs.lastModifiedTime(); 130 } 131 @Override 132 public FileTime lastAccessTime() { 133 return attrs.lastAccessTime(); 134 } 135 @Override 136 public FileTime creationTime() { 137 return attrs.creationTime(); 138 } 139 @Override 140 public boolean isRegularFile() { 141 return attrs.isRegularFile(); 142 } 143 @Override 144 public boolean isDirectory() { 145 return attrs.isDirectory(); 146 } 147 @Override 148 public boolean isSymbolicLink() { 149 return attrs.isSymbolicLink(); 150 } 151 @Override 152 public boolean isOther() { 153 return attrs.isOther(); 154 } 155 @Override 156 public long size() { 157 return attrs.size(); 158 } 159 @Override 160 public Object fileKey() { 161 return attrs.fileKey(); 162 } 163 @Override 164 public boolean isReadOnly() { 165 return (dosAttribute & DOS_XATTR_READONLY) != 0; 166 } 167 @Override 168 public boolean isHidden() { 169 return (dosAttribute & DOS_XATTR_HIDDEN) != 0; 170 } 171 @Override 172 public boolean isArchive() { 173 return (dosAttribute & DOS_XATTR_ARCHIVE) != 0; 174 } 175 @Override 176 public boolean isSystem() { 177 return (dosAttribute & DOS_XATTR_SYSTEM) != 0; 178 } 179 }; 180 181 } catch (UnixException x) { 182 x.rethrowAsIOException(file); 183 return null; // keep compiler happy 184 } finally { 185 close(fd); 186 } 187 } 188 189 @Override 190 public void setReadOnly(boolean value) throws IOException { 191 updateDosAttribute(DOS_XATTR_READONLY, value); 192 } 193 194 @Override 195 public void setHidden(boolean value) throws IOException { 196 updateDosAttribute(DOS_XATTR_HIDDEN, value); 197 } 198 199 @Override 200 public void setArchive(boolean value) throws IOException { 201 updateDosAttribute(DOS_XATTR_ARCHIVE, value); 202 } 203 204 @Override 205 public void setSystem(boolean value) throws IOException { 206 updateDosAttribute(DOS_XATTR_SYSTEM, value); 207 } 208 209 /** 210 * Reads the value of the user.DOSATTRIB extended attribute 211 */ 212 private int getDosAttribute(int fd) throws UnixException { 213 final int size = 24; 214 215 NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); 216 try { 217 int len = LinuxNativeDispatcher 218 .fgetxattr(fd, DOS_XATTR_NAME_AS_BYTES, buffer.address(), size); 219 220 if (len > 0) { 221 // ignore null terminator 222 if (unsafe.getByte(buffer.address()+len-1) == 0) 223 len--; 224 225 // convert to String and parse 226 byte[] buf = new byte[len]; 227 unsafe.copyMemory(null, buffer.address(), buf, 228 Unsafe.ARRAY_BYTE_BASE_OFFSET, len); 229 String value = Util.toString(buf); 230 231 // should be something like 0x20 232 if (value.length() >= 3 && value.startsWith("0x")) { 233 try { 234 return Integer.parseInt(value.substring(2), 16); 235 } catch (NumberFormatException x) { 236 // ignore 237 } 238 } 239 } 240 throw new UnixException("Value of " + DOS_XATTR_NAME + " attribute is invalid"); 241 } catch (UnixException x) { 242 // default value when attribute does not exist 243 if (x.errno() == ENODATA) 244 return 0; 245 throw x; 246 } finally { 247 buffer.release(); 248 } 249 } 250 251 /** 252 * Updates the value of the user.DOSATTRIB extended attribute 253 */ 254 private void updateDosAttribute(int flag, boolean enable) throws IOException { 255 file.checkWrite(); 256 257 int fd = -1; 258 try { 259 fd = file.openForAttributeAccess(followLinks); 260 int oldValue = getDosAttribute(fd); 261 int newValue = oldValue; 262 if (enable) { 263 newValue |= flag; 264 } else { 265 newValue &= ~flag; 266 } 267 if (newValue != oldValue) { 268 byte[] value = Util.toBytes("0x" + Integer.toHexString(newValue)); 269 NativeBuffer buffer = NativeBuffers.asNativeBuffer(value); 270 try { 271 LinuxNativeDispatcher.fsetxattr(fd, DOS_XATTR_NAME_AS_BYTES, 272 buffer.address(), value.length+1); 273 } finally { 274 buffer.release(); 275 } 276 } 277 } catch (UnixException x) { 278 x.rethrowAsIOException(file); 279 } finally { 280 close(fd); 281 } 282 } 283} 284