• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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