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