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