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 @SuppressWarnings("unchecked") 153 public void setAttribute(String attribute, Object value) 154 throws IOException 155 { 156 if (attribute.equals(PERMISSIONS_NAME)) { 157 setPermissions((Set<PosixFilePermission>)value); 158 return; 159 } 160 if (attribute.equals(OWNER_NAME)) { 161 setOwner((UserPrincipal)value); 162 return; 163 } 164 if (attribute.equals(GROUP_NAME)) { 165 setGroup((GroupPrincipal)value); 166 return; 167 } 168 super.setAttribute(attribute, value); 169 } 170 171 /** 172 * Invoked by readAttributes or sub-classes to add all matching posix 173 * attributes to the builder 174 */ 175 final void addPosixAttributesToBuilder(PosixFileAttributes attrs, 176 AttributesBuilder builder) 177 { 178 if (builder.match(PERMISSIONS_NAME)) 179 builder.add(PERMISSIONS_NAME, attrs.permissions()); 180 if (builder.match(OWNER_NAME)) 181 builder.add(OWNER_NAME, attrs.owner()); 182 if (builder.match(GROUP_NAME)) 183 builder.add(GROUP_NAME, attrs.group()); 184 } 185 186 @Override 187 public Map<String,Object> readAttributes(String[] attributes) 188 throws IOException 189 { 190 AttributesBuilder builder = AttributesBuilder.create(attributes); 191 PosixFileAttributes attrs = readAttributes(); 192 addBasicAttributesToBuilder(attrs, builder); 193 addPosixAttributesToBuilder(attrs, builder); 194 return builder.unmodifiableMap(); 195 } 196 197 @Override 198 public UnixFileAttributes readAttributes() throws IOException { 199 checkReadExtended(); 200 try { 201 return UnixFileAttributes.get(file, followLinks); 202 } catch (UnixException x) { 203 x.rethrowAsIOException(file); 204 return null; // keep compiler happy 205 } 206 } 207 208 // chmod 209 final void setMode(int mode) throws IOException { 210 checkWriteExtended(); 211 try { 212 if (followLinks) { 213 chmod(file, mode); 214 } else { 215 int fd = file.openForAttributeAccess(false); 216 try { 217 fchmod(fd, mode); 218 } finally { 219 close(fd); 220 } 221 } 222 } catch (UnixException x) { 223 x.rethrowAsIOException(file); 224 } 225 } 226 227 // chown 228 final void setOwners(int uid, int gid) throws IOException { 229 checkWriteExtended(); 230 try { 231 if (followLinks) { 232 chown(file, uid, gid); 233 } else { 234 lchown(file, uid, gid); 235 } 236 } catch (UnixException x) { 237 x.rethrowAsIOException(file); 238 } 239 } 240 241 @Override 242 public void setPermissions(Set<PosixFilePermission> perms) 243 throws IOException 244 { 245 setMode(UnixFileModeAttribute.toUnixMode(perms)); 246 } 247 248 @Override 249 public void setOwner(UserPrincipal owner) 250 throws IOException 251 { 252 if (owner == null) 253 throw new NullPointerException("'owner' is null"); 254 if (!(owner instanceof UnixUserPrincipals.User)) 255 throw new ProviderMismatchException(); 256 if (owner instanceof UnixUserPrincipals.Group) 257 throw new IOException("'owner' parameter can't be a group"); 258 int uid = ((UnixUserPrincipals.User)owner).uid(); 259 setOwners(uid, -1); 260 } 261 262 @Override 263 public UserPrincipal getOwner() throws IOException { 264 return readAttributes().owner(); 265 } 266 267 @Override 268 public void setGroup(GroupPrincipal group) 269 throws IOException 270 { 271 if (group == null) 272 throw new NullPointerException("'owner' is null"); 273 if (!(group instanceof UnixUserPrincipals.Group)) 274 throw new ProviderMismatchException(); 275 int gid = ((UnixUserPrincipals.Group)group).gid(); 276 setOwners(-1, gid); 277 } 278 } 279 280 private static class Unix extends Posix { 281 private static final String MODE_NAME = "mode"; 282 private static final String INO_NAME = "ino"; 283 private static final String DEV_NAME = "dev"; 284 private static final String RDEV_NAME = "rdev"; 285 private static final String NLINK_NAME = "nlink"; 286 private static final String UID_NAME = "uid"; 287 private static final String GID_NAME = "gid"; 288 private static final String CTIME_NAME = "ctime"; 289 290 Unix(UnixPath file, boolean followLinks) { 291 super(file, followLinks); 292 } 293 294 @Override 295 public String name() { 296 return "unix"; 297 } 298 299 @Override 300 public void setAttribute(String attribute, Object value) 301 throws IOException 302 { 303 if (attribute.equals(MODE_NAME)) { 304 setMode((Integer)value); 305 return; 306 } 307 if (attribute.equals(UID_NAME)) { 308 setOwners((Integer)value, -1); 309 return; 310 } 311 if (attribute.equals(GID_NAME)) { 312 setOwners(-1, (Integer)value); 313 return; 314 } 315 super.setAttribute(attribute, value); 316 } 317 318 @Override 319 public Map<String,Object> readAttributes(String[] attributes) 320 throws IOException 321 { 322 AttributesBuilder builder = AttributesBuilder.create(attributes); 323 UnixFileAttributes attrs = readAttributes(); 324 addBasicAttributesToBuilder(attrs, builder); 325 addPosixAttributesToBuilder(attrs, builder); 326 if (builder.match(MODE_NAME)) 327 builder.add(MODE_NAME, attrs.mode()); 328 if (builder.match(INO_NAME)) 329 builder.add(INO_NAME, attrs.ino()); 330 if (builder.match(DEV_NAME)) 331 builder.add(DEV_NAME, attrs.dev()); 332 if (builder.match(RDEV_NAME)) 333 builder.add(RDEV_NAME, attrs.rdev()); 334 if (builder.match(NLINK_NAME)) 335 builder.add(NLINK_NAME, attrs.nlink()); 336 if (builder.match(UID_NAME)) 337 builder.add(UID_NAME, attrs.uid()); 338 if (builder.match(GID_NAME)) 339 builder.add(GID_NAME, attrs.gid()); 340 if (builder.match(CTIME_NAME)) 341 builder.add(CTIME_NAME, attrs.ctime()); 342 return builder.unmodifiableMap(); 343 } 344 } 345 346 static Basic createBasicView(UnixPath file, boolean followLinks) { 347 return new Basic(file, followLinks); 348 } 349 350 static Posix createPosixView(UnixPath file, boolean followLinks) { 351 return new Posix(file, followLinks); 352 } 353 354 static Unix createUnixView(UnixPath file, boolean followLinks) { 355 return new Unix(file, followLinks); 356 } 357 358 static FileOwnerAttributeViewImpl createOwnerView(UnixPath file, boolean followLinks) { 359 return new FileOwnerAttributeViewImpl(createPosixView(file, followLinks)); 360 } 361 }