1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 package org.apache.hadoop.fs.permission;
19 
20 import java.io.DataInput;
21 import java.io.DataOutput;
22 import java.io.IOException;
23 
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.hadoop.conf.Configuration;
27 import org.apache.hadoop.io.Writable;
28 import org.apache.hadoop.io.WritableFactories;
29 import org.apache.hadoop.io.WritableFactory;
30 
31 /**
32  * A class for file/directory permissions.
33  */
34 public class FsPermission implements Writable {
35   private static final Log LOG = LogFactory.getLog(FsPermission.class);
36 
37   static final WritableFactory FACTORY = new WritableFactory() {
38     public Writable newInstance() { return new FsPermission(); }
39   };
40   static {                                      // register a ctor
WritableFactories.setFactory(FsPermission.class, FACTORY)41     WritableFactories.setFactory(FsPermission.class, FACTORY);
WritableFactories.setFactory(ImmutableFsPermission.class, FACTORY)42     WritableFactories.setFactory(ImmutableFsPermission.class, FACTORY);
43   }
44 
45   /** Create an immutable {@link FsPermission} object. */
createImmutable(short permission)46   public static FsPermission createImmutable(short permission) {
47     return new ImmutableFsPermission(permission);
48   }
49 
50   //POSIX permission style
51   private FsAction useraction = null;
52   private FsAction groupaction = null;
53   private FsAction otheraction = null;
54 
FsPermission()55   private FsPermission() {}
56 
57   /**
58    * Construct by the given {@link FsAction}.
59    * @param u user action
60    * @param g group action
61    * @param o other action
62    */
FsPermission(FsAction u, FsAction g, FsAction o)63   public FsPermission(FsAction u, FsAction g, FsAction o) {set(u, g, o);}
64 
65   /**
66    * Construct by the given mode.
67    * @param mode
68    * @see #toShort()
69    */
FsPermission(short mode)70   public FsPermission(short mode) { fromShort(mode); }
71 
72   /**
73    * Copy constructor
74    *
75    * @param other other permission
76    */
FsPermission(FsPermission other)77   public FsPermission(FsPermission other) {
78     this.useraction = other.useraction;
79     this.groupaction = other.groupaction;
80     this.otheraction = other.otheraction;
81   }
82 
83   /**
84    * Construct by given mode, either in octal or symbolic format.
85    * @param mode mode as a string, either in octal or symbolic format
86    * @throws IllegalArgumentException if <code>mode</code> is invalid
87    */
FsPermission(String mode)88   public FsPermission(String mode) {
89     this(new UmaskParser(mode).getUMask());
90   }
91 
92   /** Return user {@link FsAction}. */
getUserAction()93   public FsAction getUserAction() {return useraction;}
94 
95   /** Return group {@link FsAction}. */
getGroupAction()96   public FsAction getGroupAction() {return groupaction;}
97 
98   /** Return other {@link FsAction}. */
getOtherAction()99   public FsAction getOtherAction() {return otheraction;}
100 
set(FsAction u, FsAction g, FsAction o)101   private void set(FsAction u, FsAction g, FsAction o) {
102     useraction = u;
103     groupaction = g;
104     otheraction = o;
105   }
fromShort(short n)106   public void fromShort(short n) {
107     FsAction[] v = FsAction.values();
108     set(v[(n >>> 6) & 7], v[(n >>> 3) & 7], v[n & 7]);
109   }
110 
111   /** {@inheritDoc} */
write(DataOutput out)112   public void write(DataOutput out) throws IOException {
113     out.writeShort(toShort());
114   }
115 
116   /** {@inheritDoc} */
readFields(DataInput in)117   public void readFields(DataInput in) throws IOException {
118     fromShort(in.readShort());
119   }
120 
121   /**
122    * Create and initialize a {@link FsPermission} from {@link DataInput}.
123    */
read(DataInput in)124   public static FsPermission read(DataInput in) throws IOException {
125     FsPermission p = new FsPermission();
126     p.readFields(in);
127     return p;
128   }
129 
130   /**
131    * Encode the object to a short.
132    */
toShort()133   public short toShort() {
134     int s = (useraction.ordinal() << 6) | (groupaction.ordinal() << 3) |
135              otheraction.ordinal();
136     return (short)s;
137   }
138 
139   /** {@inheritDoc} */
equals(Object obj)140   public boolean equals(Object obj) {
141     if (obj instanceof FsPermission) {
142       FsPermission that = (FsPermission)obj;
143       return this.useraction == that.useraction
144           && this.groupaction == that.groupaction
145           && this.otheraction == that.otheraction;
146     }
147     return false;
148   }
149 
150   /** {@inheritDoc} */
hashCode()151   public int hashCode() {return toShort();}
152 
153   /** {@inheritDoc} */
toString()154   public String toString() {
155     return useraction.SYMBOL + groupaction.SYMBOL + otheraction.SYMBOL;
156   }
157 
158   /** Apply a umask to this permission and return a new one */
applyUMask(FsPermission umask)159   public FsPermission applyUMask(FsPermission umask) {
160     return new FsPermission(useraction.and(umask.useraction.not()),
161         groupaction.and(umask.groupaction.not()),
162         otheraction.and(umask.otheraction.not()));
163   }
164 
165   /** umask property label */
166   public static final String DEPRECATED_UMASK_LABEL = "dfs.umask";
167   public static final String UMASK_LABEL = "dfs.umaskmode";
168   public static final int DEFAULT_UMASK = 0022;
169 
170   /**
171    * Get the user file creation mask (umask)
172    *
173    * {@code UMASK_LABEL} config param has umask value that is either symbolic
174    * or octal.
175    *
176    * Symbolic umask is applied relative to file mode creation mask;
177    * the permission op characters '+' clears the corresponding bit in the mask,
178    * '-' sets bits in the mask.
179    *
180    * Octal umask, the specified bits are set in the file mode creation mask.
181    *
182    * {@code DEPRECATED_UMASK_LABEL} config param has umask value set to decimal.
183    */
getUMask(Configuration conf)184   public static FsPermission getUMask(Configuration conf) {
185     int umask = DEFAULT_UMASK;
186 
187     // To ensure backward compatibility first use the deprecated key.
188     // If the deprecated key is not present then check for the new key
189     if(conf != null) {
190       int oldStyleValue = conf.getInt(DEPRECATED_UMASK_LABEL, Integer.MIN_VALUE);
191       if(oldStyleValue != Integer.MIN_VALUE) { // Property was set with old key
192         LOG.warn(DEPRECATED_UMASK_LABEL + " configuration key is deprecated. " +
193             "Convert to " + UMASK_LABEL + ", using octal or symbolic umask " +
194             "specifications.");
195         umask = oldStyleValue;
196       } else {
197         String confUmask = conf.get(UMASK_LABEL);
198         if(confUmask != null) { // UMASK_LABEL is set
199           return new FsPermission(confUmask);
200         }
201       }
202     }
203 
204     return new FsPermission((short)umask);
205   }
206 
207   /** Set the user file creation mask (umask) */
setUMask(Configuration conf, FsPermission umask)208   public static void setUMask(Configuration conf, FsPermission umask) {
209     conf.set(UMASK_LABEL, String.format("%1$03o", umask.toShort()));
210   }
211 
212   /** Get the default permission. */
getDefault()213   public static FsPermission getDefault() {
214     return new FsPermission((short)0777);
215   }
216 
217   /**
218    * Create a FsPermission from a Unix symbolic permission string
219    * @param unixSymbolicPermission e.g. "-rw-rw-rw-"
220    */
valueOf(String unixSymbolicPermission)221   public static FsPermission valueOf(String unixSymbolicPermission) {
222     if (unixSymbolicPermission == null) {
223       return null;
224     }
225     else if (unixSymbolicPermission.length() != 10) {
226       throw new IllegalArgumentException("length != 10(unixSymbolicPermission="
227           + unixSymbolicPermission + ")");
228     }
229     int n = 0;
230     for(int i = 1; i < unixSymbolicPermission.length(); i++) {
231       n = n << 1;
232       char c = unixSymbolicPermission.charAt(i);
233       n += (c == '-' || c == 'T' || c == 'S') ? 0: 1;
234     }
235     return new FsPermission((short)n);
236   }
237 
238   private static class ImmutableFsPermission extends FsPermission {
ImmutableFsPermission(short permission)239     public ImmutableFsPermission(short permission) {
240       super(permission);
241     }
applyUMask(FsPermission umask)242     public FsPermission applyUMask(FsPermission umask) {
243       throw new UnsupportedOperationException();
244     }
readFields(DataInput in)245     public void readFields(DataInput in) throws IOException {
246       throw new UnsupportedOperationException();
247     }
248   }
249 }
250