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