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