1 /* 2 * Copyright (c) 2008, 2009, 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.file.attribute.*; 30 import java.util.*; 31 import java.util.concurrent.TimeUnit; 32 import java.io.IOException; 33 34 import static sun.nio.fs.UnixNativeDispatcher.*; 35 36 class UnixFileAttributeViews { 37 38 static class Basic extends AbstractBasicFileAttributeView { 39 protected final UnixPath file; 40 protected final boolean followLinks; 41 42 Basic(UnixPath file, boolean followLinks) { 43 this.file = file; 44 this.followLinks = followLinks; 45 } 46 47 @Override 48 public BasicFileAttributes readAttributes() throws IOException { 49 file.checkRead(); 50 try { 51 UnixFileAttributes attrs = 52 UnixFileAttributes.get(file, followLinks); 53 return attrs.asBasicFileAttributes(); 54 } catch (UnixException x) { 55 x.rethrowAsIOException(file); 56 return null; // keep compiler happy 57 } 58 } 59 60 @Override 61 public void setTimes(FileTime lastModifiedTime, 62 FileTime lastAccessTime, 63 FileTime createTime) throws IOException 64 { 65 // null => don't change 66 if (lastModifiedTime == null && lastAccessTime == null) { 67 // no effect 68 return; 69 } 70 71 // permission check 72 file.checkWrite(); 73 74 int fd = file.openForAttributeAccess(followLinks); 75 try { 76 // if not changing both attributes then need existing attributes 77 if (lastModifiedTime == null || lastAccessTime == null) { 78 try { 79 UnixFileAttributes attrs = UnixFileAttributes.get(fd); 80 if (lastModifiedTime == null) 81 lastModifiedTime = attrs.lastModifiedTime(); 82 if (lastAccessTime == null) 83 lastAccessTime = attrs.lastAccessTime(); 84 } catch (UnixException x) { 85 x.rethrowAsIOException(file); 86 } 87 } 88 89 // uptime times 90 long modValue = lastModifiedTime.to(TimeUnit.MICROSECONDS); 91 long accessValue= lastAccessTime.to(TimeUnit.MICROSECONDS); 92 93 boolean retry = false; 94 try { 95 futimes(fd, accessValue, modValue); 96 } catch (UnixException x) { 97 // if futimes fails with EINVAL and one/both of the times is 98 // negative then we adjust the value to the epoch and retry. 99 if (x.errno() == UnixConstants.EINVAL && 100 (modValue < 0L || accessValue < 0L)) { 101 retry = true; 102 } else { 103 x.rethrowAsIOException(file); 104 } 105 } 106 if (retry) { 107 if (modValue < 0L) modValue = 0L; 108 if (accessValue < 0L) accessValue= 0L; 109 try { 110 futimes(fd, accessValue, modValue); 111 } catch (UnixException x) { 112 x.rethrowAsIOException(file); 113 } 114 } 115 } finally { 116 close(fd); 117 } 118 } 119 } 120 121 private static class Posix extends Basic implements PosixFileAttributeView { 122 private static final String PERMISSIONS_NAME = "permissions"; 123 private static final String OWNER_NAME = "owner"; 124 private static final String GROUP_NAME = "group"; 125 126 Posix(UnixPath file, boolean followLinks) { 127 super(file, followLinks); 128 } 129 130 final void checkReadExtended() { 131 SecurityManager sm = System.getSecurityManager(); 132 if (sm != null) { 133 file.checkRead(); 134 sm.checkPermission(new RuntimePermission("accessUserInformation")); 135 } 136 } 137 138 final void checkWriteExtended() { 139 SecurityManager sm = System.getSecurityManager(); 140 if (sm != null) { 141 file.checkWrite(); 142 sm.checkPermission(new RuntimePermission("accessUserInformation")); 143 } 144 } 145 146 @Override 147 public String name() { 148 return "posix"; 149 } 150 151 @Override 152 public Object getAttribute(String attribute) throws IOException { 153 if (attribute.equals(PERMISSIONS_NAME)) 154 return readAttributes().permissions(); 155 if (attribute.equals(OWNER_NAME)) 156 return readAttributes().owner(); 157 if (attribute.equals(GROUP_NAME)) 158 return readAttributes().group(); 159 return super.getAttribute(attribute); 160 } 161 162 @Override 163 @SuppressWarnings("unchecked") 164 public void setAttribute(String attribute, Object value) 165 throws IOException 166 { 167 if (attribute.equals(PERMISSIONS_NAME)) { 168 setPermissions((Set<PosixFilePermission>)value); 169 return; 170 } 171 if (attribute.equals(OWNER_NAME)) { 172 setOwner((UserPrincipal)value); 173 return; 174 } 175 if (attribute.equals(GROUP_NAME)) { 176 setGroup((GroupPrincipal)value); 177 return; 178 } 179 super.setAttribute(attribute, value); 180 } 181 182 /** 183 * Invoked by readAttributes or sub-classes to add all matching posix 184 * attributes to the builder 185 */ 186 final void addPosixAttributesToBuilder(PosixFileAttributes attrs, 187 AttributesBuilder builder) 188 { 189 if (builder.match(PERMISSIONS_NAME)) 190 builder.add(PERMISSIONS_NAME, attrs.permissions()); 191 if (builder.match(OWNER_NAME)) 192 builder.add(OWNER_NAME, attrs.owner()); 193 if (builder.match(GROUP_NAME)) 194 builder.add(GROUP_NAME, attrs.group()); 195 } 196 197 @Override 198 public Map<String,?> readAttributes(String[] attributes) 199 throws IOException 200 { 201 AttributesBuilder builder = AttributesBuilder.create(attributes); 202 PosixFileAttributes attrs = readAttributes(); 203 addBasicAttributesToBuilder(attrs, builder); 204 addPosixAttributesToBuilder(attrs, builder); 205 return builder.unmodifiableMap(); 206 } 207 208 @Override 209 public UnixFileAttributes readAttributes() throws IOException { 210 checkReadExtended(); 211 try { 212 return UnixFileAttributes.get(file, followLinks); 213 } catch (UnixException x) { 214 x.rethrowAsIOException(file); 215 return null; // keep compiler happy 216 } 217 } 218 219 // chmod 220 final void setMode(int mode) throws IOException { 221 checkWriteExtended(); 222 try { 223 if (followLinks) { 224 chmod(file, mode); 225 } else { 226 int fd = file.openForAttributeAccess(false); 227 try { 228 fchmod(fd, mode); 229 } finally { 230 close(fd); 231 } 232 } 233 } catch (UnixException x) { 234 x.rethrowAsIOException(file); 235 } 236 } 237 238 // chown 239 final void setOwners(int uid, int gid) throws IOException { 240 checkWriteExtended(); 241 try { 242 if (followLinks) { 243 chown(file, uid, gid); 244 } else { 245 lchown(file, uid, gid); 246 } 247 } catch (UnixException x) { 248 x.rethrowAsIOException(file); 249 } 250 } 251 252 @Override 253 public void setPermissions(Set<PosixFilePermission> perms) 254 throws IOException 255 { 256 setMode(UnixFileModeAttribute.toUnixMode(perms)); 257 } 258 259 @Override 260 public void setOwner(UserPrincipal owner) 261 throws IOException 262 { 263 if (owner == null) 264 throw new NullPointerException("'owner' is null"); 265 if (!(owner instanceof UnixUserPrincipals.User)) 266 throw new ProviderMismatchException(); 267 if (owner instanceof UnixUserPrincipals.Group) 268 throw new IOException("'owner' parameter can't be a group"); 269 int uid = ((UnixUserPrincipals.User)owner).uid(); 270 setOwners(uid, -1); 271 } 272 273 @Override 274 public UserPrincipal getOwner() throws IOException { 275 return readAttributes().owner(); 276 } 277 278 @Override 279 public void setGroup(GroupPrincipal group) 280 throws IOException 281 { 282 if (group == null) 283 throw new NullPointerException("'owner' is null"); 284 if (!(group instanceof UnixUserPrincipals.Group)) 285 throw new ProviderMismatchException(); 286 int gid = ((UnixUserPrincipals.Group)group).gid(); 287 setOwners(-1, gid); 288 } 289 } 290 291 private static class Unix extends Posix { 292 private static final String MODE_NAME = "mode"; 293 private static final String INO_NAME = "ino"; 294 private static final String DEV_NAME = "dev"; 295 private static final String RDEV_NAME = "rdev"; 296 private static final String NLINK_NAME = "nlink"; 297 private static final String UID_NAME = "uid"; 298 private static final String GID_NAME = "gid"; 299 private static final String CTIME_NAME = "ctime"; 300 301 Unix(UnixPath file, boolean followLinks) { 302 super(file, followLinks); 303 } 304 305 @Override 306 public String name() { 307 return "unix"; 308 } 309 310 @Override 311 public Object getAttribute(String attribute) throws IOException { 312 if (attribute.equals(MODE_NAME)) 313 return readAttributes().mode(); 314 if (attribute.equals(INO_NAME)) 315 return readAttributes().ino(); 316 if (attribute.equals(DEV_NAME)) 317 return readAttributes().dev(); 318 if (attribute.equals(RDEV_NAME)) 319 return readAttributes().rdev(); 320 if (attribute.equals(NLINK_NAME)) 321 return readAttributes().nlink(); 322 if (attribute.equals(UID_NAME)) 323 return readAttributes().uid(); 324 if (attribute.equals(GID_NAME)) 325 return readAttributes().gid(); 326 if (attribute.equals(CTIME_NAME)) 327 return readAttributes().ctime(); 328 return super.getAttribute(attribute); 329 } 330 331 @Override 332 public void setAttribute(String attribute, Object value) 333 throws IOException 334 { 335 if (attribute.equals(MODE_NAME)) { 336 setMode((Integer)value); 337 return; 338 } 339 if (attribute.equals(UID_NAME)) { 340 setOwners((Integer)value, -1); 341 return; 342 } 343 if (attribute.equals(GID_NAME)) { 344 setOwners(-1, (Integer)value); 345 return; 346 } 347 super.setAttribute(attribute, value); 348 } 349 350 @Override 351 public Map<String,?> readAttributes(String[] attributes) 352 throws IOException 353 { 354 AttributesBuilder builder = AttributesBuilder.create(attributes); 355 UnixFileAttributes attrs = readAttributes(); 356 addBasicAttributesToBuilder(attrs, builder); 357 addPosixAttributesToBuilder(attrs, builder); 358 if (builder.match(MODE_NAME)) 359 builder.add(MODE_NAME, attrs.mode()); 360 if (builder.match(INO_NAME)) 361 builder.add(INO_NAME, attrs.ino()); 362 if (builder.match(DEV_NAME)) 363 builder.add(DEV_NAME, attrs.dev()); 364 if (builder.match(RDEV_NAME)) 365 builder.add(RDEV_NAME, attrs.rdev()); 366 if (builder.match(NLINK_NAME)) 367 builder.add(NLINK_NAME, attrs.nlink()); 368 if (builder.match(UID_NAME)) 369 builder.add(UID_NAME, attrs.uid()); 370 if (builder.match(GID_NAME)) 371 builder.add(GID_NAME, attrs.gid()); 372 if (builder.match(CTIME_NAME)) 373 builder.add(CTIME_NAME, attrs.ctime()); 374 return builder.unmodifiableMap(); 375 } 376 } 377 378 static Basic createBasicView(UnixPath file, boolean followLinks) { 379 return new Basic(file, followLinks); 380 } 381 382 static Posix createPosixView(UnixPath file, boolean followLinks) { 383 return new Posix(file, followLinks); 384 } 385 386 static Unix createUnixView(UnixPath file, boolean followLinks) { 387 return new Unix(file, followLinks); 388 } 389 390 static FileOwnerAttributeViewImpl createOwnerView(UnixPath file, boolean followLinks) { 391 return new FileOwnerAttributeViewImpl(createPosixView(file, followLinks)); 392 } 393 }