001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.vfs2.util;
019
020import java.util.EnumMap;
021import java.util.Map;
022
023/**
024 * UNIX permissions.
025 *
026 * @since 2.1
027 */
028public class PosixPermissions {
029
030    /**
031     * Permission types.
032     */
033    public static enum Type {
034        /**
035         * User right readable.
036         */
037        UserReadable(00400),
038
039        /**
040         * User right writable.
041         */
042        UserWritable(00200),
043
044        /**
045         * User right executable.
046         */
047        UserExecutable(00100),
048
049        /**
050         * Group right readable.
051         */
052        GroupReadable(00040),
053
054        /**
055         * Group right writable.
056         */
057        GroupWritable(00020),
058
059        /**
060         * Group right executable.
061         */
062        GroupExecutable(00010),
063
064        /**
065         * Other right readable.
066         */
067        OtherReadable(00004),
068
069        /**
070         * Other right writable.
071         */
072        OtherWritable(00002),
073
074        /**
075         * Other right executable.
076         */
077        OtherExecutable(00001);
078
079        private final int mask;
080
081        /**
082         * Initialize with the mask
083         */
084        private Type(final int mask) {
085            this.mask = mask;
086        }
087
088        /**
089         * Return the mask for this permission.
090         *
091         * @return the mask for this permission.
092         */
093        public int getMask() {
094            return this.mask;
095        }
096
097    }
098
099    /**
100     * Current permissions.
101     */
102    private final int permissions;
103
104    /**
105     * If the user is the owner of the file.
106     */
107    private final boolean isOwner;
108
109    /**
110     * If one user group is the group of the file.
111     */
112    private final boolean isInGroup;
113
114    /**
115     * Creates a new PosixPermissions object.
116     *
117     * @param permissions The permissions
118     * @param isOwner true if the user is the owner of the file
119     * @param isInGroup true if the user is a group owner of the file
120     */
121    public PosixPermissions(final int permissions, final boolean isOwner, final boolean isInGroup) {
122        this.permissions = permissions;
123        this.isOwner = isOwner;
124        this.isInGroup = isInGroup;
125    }
126
127    /**
128     * Computes new permission from old ones.
129     *
130     * @param values The permissions to set.
131     * @return The new permissions.
132     */
133    private int computeNewPermissions(final Map<Type, Boolean> values) {
134        int newPerms = this.permissions;
135        for (final Map.Entry<Type, Boolean> entry : values.entrySet()) {
136            final Type type = entry.getKey();
137            if (entry.getValue()) {
138                newPerms |= type.getMask();
139            } else {
140                newPerms &= ~type.getMask();
141            }
142        }
143        return newPerms;
144    }
145
146    /**
147     * Tests whether the bit corresponding to the permission is set.
148     *
149     * @return whether the bit corresponding to the permission is set.
150     */
151    private boolean get(final Type type) {
152        return (type.getMask() & this.permissions) != 0;
153    }
154
155    /**
156     * Gets permissions.
157     *
158     * @return permissions.
159     */
160    public int getPermissions() {
161        return this.permissions;
162    }
163
164    /**
165     * Gets whether the permissions are executable.
166     *
167     * @return whether the permissions are executable.
168     */
169    public boolean isExecutable() {
170        if (this.isOwner) {
171            return this.get(Type.UserExecutable);
172        }
173        if (this.isInGroup) {
174            return this.get(Type.GroupExecutable);
175        }
176        return this.get(Type.OtherExecutable);
177    }
178
179    /**
180     * Gets whether the permissions are readable.
181     *
182     * @return whether the permissions are readable.
183     */
184    public boolean isReadable() {
185        if (this.isOwner) {
186            return this.get(Type.UserReadable);
187        }
188        if (this.isInGroup) {
189            return this.get(Type.GroupReadable);
190        }
191        return this.get(Type.OtherReadable);
192    }
193
194    /**
195     * Gets whether the permissions are writable.
196     *
197     * @return whether the permissions are writable.
198     */
199    public boolean isWritable() {
200        if (this.isOwner) {
201            return this.get(Type.UserWritable);
202        }
203        if (this.isInGroup) {
204            return this.get(Type.GroupWritable);
205        }
206        return this.get(Type.OtherWritable);
207    }
208
209    /**
210     * Creates new permissions based on these permissions.
211     *
212     * @param executable Whether the new permissions should be readable.
213     * @param ownerOnly Whether the new permissions are only for the owner.
214     * @return the new permissions.
215     */
216    public int makeExecutable(final boolean executable, final boolean ownerOnly) {
217        final EnumMap<Type, Boolean> map = new EnumMap<>(Type.class);
218        map.put(Type.UserExecutable, executable);
219        if (!ownerOnly) {
220            map.put(Type.GroupExecutable, executable);
221            map.put(Type.OtherExecutable, executable);
222        }
223        return this.computeNewPermissions(map);
224    }
225
226    /**
227     * Creates new permissions based on these permissions.
228     *
229     * @param readable Whether the new permissions should be readable.
230     * @param ownerOnly Whether the new permissions are only for the owner.
231     * @return the new permissions.
232     */
233    public Integer makeReadable(final boolean readable, final boolean ownerOnly) {
234        final EnumMap<Type, Boolean> map = new EnumMap<>(Type.class);
235        map.put(Type.UserReadable, readable);
236        if (!ownerOnly) {
237            map.put(Type.GroupReadable, readable);
238            map.put(Type.OtherReadable, readable);
239        }
240        return this.computeNewPermissions(map);
241    }
242
243    /**
244     * Creates new permissions based on these permissions.
245     *
246     * @param writable Whether the new permissions should be readable.
247     * @param ownerOnly Whether the new permissions are only for the owner.
248     * @return the new permissions.
249     */
250    public Integer makeWritable(final boolean writable, final boolean ownerOnly) {
251        final EnumMap<Type, Boolean> map = new EnumMap<>(Type.class);
252        map.put(Type.UserWritable, writable);
253        if (!ownerOnly) {
254            map.put(Type.GroupWritable, writable);
255            map.put(Type.OtherWritable, writable);
256        }
257        return this.computeNewPermissions(map);
258    }
259}