1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.jimfs; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 21 import com.google.common.collect.ImmutableMap; 22 import com.google.common.collect.ImmutableSet; 23 import java.nio.file.attribute.FileAttributeView; 24 import java.nio.file.attribute.FileTime; 25 import java.nio.file.attribute.GroupPrincipal; 26 import java.nio.file.attribute.PosixFilePermission; 27 import java.nio.file.attribute.UserPrincipal; 28 import java.util.Set; 29 import java.util.concurrent.ConcurrentHashMap; 30 import java.util.concurrent.ConcurrentMap; 31 import java.util.concurrent.atomic.AtomicInteger; 32 33 /** 34 * Attribute provider that provides the "unix" attribute view. 35 * 36 * @author Colin Decker 37 */ 38 final class UnixAttributeProvider extends AttributeProvider { 39 40 private static final ImmutableSet<String> ATTRIBUTES = 41 ImmutableSet.of("uid", "ino", "dev", "nlink", "rdev", "ctime", "mode", "gid"); 42 43 private static final ImmutableSet<String> INHERITED_VIEWS = 44 ImmutableSet.of("basic", "owner", "posix"); 45 46 private final AtomicInteger uidGenerator = new AtomicInteger(); 47 private final ConcurrentMap<Object, Integer> idCache = new ConcurrentHashMap<>(); 48 49 @Override name()50 public String name() { 51 return "unix"; 52 } 53 54 @Override inherits()55 public ImmutableSet<String> inherits() { 56 return INHERITED_VIEWS; 57 } 58 59 @Override fixedAttributes()60 public ImmutableSet<String> fixedAttributes() { 61 return ATTRIBUTES; 62 } 63 64 @Override viewType()65 public Class<UnixFileAttributeView> viewType() { 66 return UnixFileAttributeView.class; 67 } 68 69 @Override view( FileLookup lookup, ImmutableMap<String, FileAttributeView> inheritedViews)70 public UnixFileAttributeView view( 71 FileLookup lookup, ImmutableMap<String, FileAttributeView> inheritedViews) { 72 // This method should not be called... and it cannot be called through the public APIs in 73 // java.nio.file since there is no public UnixFileAttributeView type. 74 throw new UnsupportedOperationException(); 75 } 76 77 // TODO(cgdecker): Since we can now guarantee that the owner/group for an file are our own 78 // implementation of UserPrincipal/GroupPrincipal, it would be nice to have them store a unique 79 // ID themselves and just get that rather than doing caching here. Then this could be a singleton 80 // like the rest of the AttributeProviders. However, that would require a way for the owner/posix 81 // providers to create their default principals using the lookup service for the specific file 82 // system. 83 84 /** Returns an ID that is guaranteed to be the same for any invocation with equal objects. */ getUniqueId(Object object)85 private Integer getUniqueId(Object object) { 86 Integer id = idCache.get(object); 87 if (id == null) { 88 id = uidGenerator.incrementAndGet(); 89 Integer existing = idCache.putIfAbsent(object, id); 90 if (existing != null) { 91 return existing; 92 } 93 } 94 return id; 95 } 96 97 @SuppressWarnings("unchecked") 98 @Override get(File file, String attribute)99 public Object get(File file, String attribute) { 100 switch (attribute) { 101 case "uid": 102 UserPrincipal user = (UserPrincipal) file.getAttribute("owner", "owner"); 103 return getUniqueId(user); 104 case "gid": 105 GroupPrincipal group = (GroupPrincipal) file.getAttribute("posix", "group"); 106 return getUniqueId(group); 107 case "mode": 108 Set<PosixFilePermission> permissions = 109 (Set<PosixFilePermission>) file.getAttribute("posix", "permissions"); 110 return toMode(permissions); 111 case "ctime": 112 return FileTime.fromMillis(file.getCreationTime()); 113 case "rdev": 114 return 0L; 115 case "dev": 116 return 1L; 117 case "ino": 118 return file.id(); 119 case "nlink": 120 return file.links(); 121 default: 122 return null; 123 } 124 } 125 126 @Override set(File file, String view, String attribute, Object value, boolean create)127 public void set(File file, String view, String attribute, Object value, boolean create) { 128 throw unsettable(view, attribute, create); 129 } 130 131 @SuppressWarnings("OctalInteger") toMode(Set<PosixFilePermission> permissions)132 private static int toMode(Set<PosixFilePermission> permissions) { 133 int result = 0; 134 for (PosixFilePermission permission : permissions) { 135 checkNotNull(permission); 136 switch (permission) { 137 case OWNER_READ: 138 result |= 0400; // note: octal numbers 139 break; 140 case OWNER_WRITE: 141 result |= 0200; 142 break; 143 case OWNER_EXECUTE: 144 result |= 0100; 145 break; 146 case GROUP_READ: 147 result |= 0040; 148 break; 149 case GROUP_WRITE: 150 result |= 0020; 151 break; 152 case GROUP_EXECUTE: 153 result |= 0010; 154 break; 155 case OTHERS_READ: 156 result |= 0004; 157 break; 158 case OTHERS_WRITE: 159 result |= 0002; 160 break; 161 case OTHERS_EXECUTE: 162 result |= 0001; 163 break; 164 default: 165 throw new AssertionError(); // no other possible values 166 } 167 } 168 return result; 169 } 170 } 171