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