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 26 package sun.nio.fs; 27 28 import java.nio.file.*; 29 import java.nio.ByteBuffer; 30 import java.nio.channels.FileChannel; 31 import java.io.IOException; 32 import java.util.*; 33 34 import static sun.nio.fs.UnixNativeDispatcher.*; 35 import static sun.nio.fs.UnixConstants.*; 36 import static sun.nio.fs.SolarisConstants.*; 37 38 /** 39 * Solaris emulation of NamedAttributeView using extended attributes. 40 */ 41 42 class SolarisUserDefinedFileAttributeView 43 extends AbstractUserDefinedFileAttributeView 44 { 45 private static final byte[] HERE = { '.' }; 46 47 private byte[] nameAsBytes(UnixPath file, String name) throws IOException { 48 byte[] bytes = Util.toBytes(name); 49 // "", "." and ".." not allowed 50 if (bytes.length == 0 || bytes[0] == '.') { 51 if (bytes.length <= 1 || 52 (bytes.length == 2 && bytes[1] == '.')) 53 { 54 throw new FileSystemException(file.getPathForExceptionMessage(), 55 null, "'" + name + "' is not a valid name"); 56 } 57 } 58 return bytes; 59 } 60 61 private final UnixPath file; 62 private final boolean followLinks; 63 64 SolarisUserDefinedFileAttributeView(UnixPath file, boolean followLinks) { 65 this.file = file; 66 this.followLinks = followLinks; 67 } 68 69 @Override 70 public List<String> list() throws IOException { 71 if (System.getSecurityManager() != null) 72 checkAccess(file.getPathForPermissionCheck(), true, false); 73 74 int fd = -1; 75 try { 76 try { 77 fd = file.openForAttributeAccess(followLinks); 78 79 // open extended attribute directory 80 int dfd = openat(fd, HERE, (O_RDONLY|O_XATTR), 0); 81 long dp; 82 try { 83 dp = fdopendir(dfd); 84 } catch (UnixException x) { 85 close(dfd); 86 throw x; 87 } 88 89 // read list of extended attributes 90 List<String> list = new ArrayList<>(); 91 try { 92 byte[] name; 93 while ((name = readdir(dp)) != null) { 94 String s = Util.toString(name); 95 if (!s.equals(".") && !s.equals("..")) 96 list.add(s); 97 } 98 } finally { 99 closedir(dp); 100 } 101 return Collections.unmodifiableList(list); 102 } catch (UnixException x) { 103 throw new FileSystemException(file.getPathForExceptionMessage(), 104 null, "Unable to get list of extended attributes: " + 105 x.getMessage()); 106 } 107 } finally { 108 close(fd); 109 } 110 } 111 112 @Override 113 public int size(String name) throws IOException { 114 if (System.getSecurityManager() != null) 115 checkAccess(file.getPathForPermissionCheck(), true, false); 116 117 int fd = -1; 118 try { 119 try { 120 fd = file.openForAttributeAccess(followLinks); 121 122 // open attribute file 123 int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0); 124 try { 125 // read attribute's attributes 126 UnixFileAttributes attrs = UnixFileAttributes.get(afd); 127 long size = attrs.size(); 128 if (size > Integer.MAX_VALUE) 129 throw new ArithmeticException("Extended attribute value too large"); 130 return (int)size; 131 } finally { 132 close(afd); 133 } 134 } catch (UnixException x) { 135 throw new FileSystemException(file.getPathForExceptionMessage(), 136 null, "Unable to get size of extended attribute '" + name + 137 "': " + x.getMessage()); 138 } 139 } finally { 140 close(fd); 141 } 142 } 143 144 @Override 145 public int read(String name, ByteBuffer dst) throws IOException { 146 if (System.getSecurityManager() != null) 147 checkAccess(file.getPathForPermissionCheck(), true, false); 148 149 int fd = -1; 150 try { 151 try { 152 fd = file.openForAttributeAccess(followLinks); 153 154 // open attribute file 155 int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0); 156 157 // wrap with channel 158 FileChannel fc = UnixChannelFactory.newFileChannel(afd, file.toString(), true, false); 159 160 // read to EOF (nothing we can do if I/O error occurs) 161 try { 162 if (fc.size() > dst.remaining()) 163 throw new IOException("Extended attribute file too large"); 164 int total = 0; 165 while (dst.hasRemaining()) { 166 int n = fc.read(dst); 167 if (n < 0) 168 break; 169 total += n; 170 } 171 return total; 172 } finally { 173 fc.close(); 174 } 175 } catch (UnixException x) { 176 throw new FileSystemException(file.getPathForExceptionMessage(), 177 null, "Unable to read extended attribute '" + name + 178 "': " + x.getMessage()); 179 } 180 } finally { 181 close(fd); 182 } 183 } 184 185 @Override 186 public int write(String name, ByteBuffer src) throws IOException { 187 if (System.getSecurityManager() != null) 188 checkAccess(file.getPathForPermissionCheck(), false, true); 189 190 int fd = -1; 191 try { 192 try { 193 fd = file.openForAttributeAccess(followLinks); 194 195 // open/create attribute file 196 int afd = openat(fd, nameAsBytes(file,name), 197 (O_CREAT|O_WRONLY|O_TRUNC|O_XATTR), 198 UnixFileModeAttribute.ALL_PERMISSIONS); 199 200 // wrap with channel 201 FileChannel fc = UnixChannelFactory.newFileChannel(afd, file.toString(), false, true); 202 203 // write value (nothing we can do if I/O error occurs) 204 try { 205 int rem = src.remaining(); 206 while (src.hasRemaining()) { 207 fc.write(src); 208 } 209 return rem; 210 } finally { 211 fc.close(); 212 } 213 } catch (UnixException x) { 214 throw new FileSystemException(file.getPathForExceptionMessage(), 215 null, "Unable to write extended attribute '" + name + 216 "': " + x.getMessage()); 217 } 218 } finally { 219 close(fd); 220 } 221 } 222 223 @Override 224 public void delete(String name) throws IOException { 225 if (System.getSecurityManager() != null) 226 checkAccess(file.getPathForPermissionCheck(), false, true); 227 228 int fd = -1; 229 try { 230 fd = file.openForAttributeAccess(followLinks); 231 232 int dfd = openat(fd, HERE, (O_RDONLY|O_XATTR), 0); 233 try { 234 unlinkat(dfd, nameAsBytes(file,name), 0); 235 } finally { 236 close(dfd); 237 } 238 } catch (UnixException x) { 239 throw new FileSystemException(file.getPathForExceptionMessage(), 240 null, "Unable to delete extended attribute '" + name + 241 "': " + x.getMessage()); 242 } finally { 243 close(fd); 244 } 245 } 246 247 /** 248 * Used by copyTo/moveTo to copy extended attributes from source to target. 249 * 250 * @param ofd 251 * file descriptor for source file 252 * @param nfd 253 * file descriptor for target file 254 */ 255 static void copyExtendedAttributes(int ofd, int nfd) { 256 try { 257 // open extended attribute directory 258 int dfd = openat(ofd, HERE, (O_RDONLY|O_XATTR), 0); 259 long dp = 0L; 260 try { 261 dp = fdopendir(dfd); 262 } catch (UnixException x) { 263 close(dfd); 264 throw x; 265 } 266 267 // copy each extended attribute 268 try { 269 byte[] name; 270 while ((name = readdir(dp)) != null) { 271 // ignore "." and ".." 272 if (name[0] == '.') { 273 if (name.length == 1) 274 continue; 275 if (name.length == 2 && name[1] == '.') 276 continue; 277 } 278 copyExtendedAttribute(ofd, name, nfd); 279 } 280 } finally { 281 closedir(dp); 282 } 283 } catch (UnixException ignore) { 284 } 285 } 286 287 private static void copyExtendedAttribute(int ofd, byte[] name, int nfd) 288 throws UnixException 289 { 290 // open source attribute file 291 int src = openat(ofd, name, (O_RDONLY|O_XATTR), 0); 292 try { 293 // create target attribute file 294 int dst = openat(nfd, name, (O_CREAT|O_WRONLY|O_TRUNC|O_XATTR), 295 UnixFileModeAttribute.ALL_PERMISSIONS); 296 try { 297 UnixCopyFile.transfer(dst, src, 0L); 298 } finally { 299 close(dst); 300 } 301 } finally { 302 close(src); 303 } 304 } 305 }