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 enum Type {
034
035        /**
036         * User right readable.
037         */
038        UserReadable(0x100),
039
040        /**
041         * User right writable.
042         */
043        UserWritable(0x080),
044
045        /**
046         * User right executable.
047         */
048        UserExecutable(0x040),
049
050        /**
051         * Group right readable.
052         */
053        GroupReadable(0x020),
054
055        /**
056         * Group right writable.
057         */
058        GroupWritable(0x010),
059
060        /**
061         * Group right executable.
062         */
063        GroupExecutable(0x008),
064
065        /**
066         * Other right readable.
067         */
068        OtherReadable(0x004),
069
070        /**
071         * Other right writable.
072         */
073        OtherWritable(0x002),
074
075        /**
076         * Other right executable.
077         */
078        OtherExecutable(0x001);
079
080        private final int mask;
081
082        /**
083         * Initialize with the mask
084         */
085        Type(final int mask) {
086            this.mask = mask;
087        }
088
089        /**
090         * Gets the mask for this permission.
091         *
092         * @return the mask for this permission.
093         */
094        public int getMask() {
095            return mask;
096        }
097
098    }
099
100    /**
101     * Current permissions.
102     */
103    private final int permissions;
104
105    /**
106     * If the user is the owner of the file.
107     */
108    private final boolean isOwner;
109
110    /**
111     * If one user group is the group of the file.
112     */
113    private final boolean isInGroup;
114
115    /**
116     * Creates a new PosixPermissions object.
117     *
118     * @param permissions The permissions
119     * @param isOwner true if the user is the owner of the file
120     * @param isInGroup true if the user is a group owner of the file
121     */
122    public PosixPermissions(final int permissions, final boolean isOwner, final boolean isInGroup) {
123        this.permissions = permissions;
124        this.isOwner = isOwner;
125        this.isInGroup = isInGroup;
126    }
127
128    /**
129     * Computes new permission from old ones.
130     *
131     * @param values The permissions to set.
132     * @return The new permissions.
133     */
134    private int computeNewPermissions(final Map<Type, Boolean> values) {
135        int newPerms = permissions;
136        for (final Map.Entry<Type, Boolean> entry : values.entrySet()) {
137            final Type type = entry.getKey();
138            if (entry.getValue()) {
139                newPerms |= type.getMask();
140            } else {
141                newPerms &= ~type.getMask();
142            }
143        }
144        return newPerms;
145    }
146
147    /**
148     * Tests whether the bit corresponding to the permission is set.
149     *
150     * @return whether the bit corresponding to the permission is set.
151     */
152    private boolean get(final Type type) {
153        return (type.getMask() & permissions) != 0;
154    }
155
156    /**
157     * Gets permissions.
158     *
159     * @return permissions.
160     */
161    public int getPermissions() {
162        return permissions;
163    }
164
165    /**
166     * Gets whether the permissions are executable.
167     *
168     * @return whether the permissions are executable.
169     */
170    public boolean isExecutable() {
171        if (isOwner) {
172            return get(Type.UserExecutable);
173        }
174        if (isInGroup) {
175            return get(Type.GroupExecutable);
176        }
177        return get(Type.OtherExecutable);
178    }
179
180    /**
181     * Gets whether the permissions are readable.
182     *
183     * @return whether the permissions are readable.
184     */
185    public boolean isReadable() {
186        if (isOwner) {
187            return get(Type.UserReadable);
188        }
189        if (isInGroup) {
190            return get(Type.GroupReadable);
191        }
192        return get(Type.OtherReadable);
193    }
194
195    /**
196     * Gets whether the permissions are writable.
197     *
198     * @return whether the permissions are writable.
199     */
200    public boolean isWritable() {
201        if (isOwner) {
202            return get(Type.UserWritable);
203        }
204        if (isInGroup) {
205            return get(Type.GroupWritable);
206        }
207        return get(Type.OtherWritable);
208    }
209
210    /**
211     * Creates new permissions based on these permissions.
212     *
213     * @param executable Whether the new permissions should be readable.
214     * @param ownerOnly Whether the new permissions are only for the owner.
215     * @return the new permissions.
216     */
217    public int makeExecutable(final boolean executable, final boolean ownerOnly) {
218        final EnumMap<Type, Boolean> map = new EnumMap<>(Type.class);
219        map.put(Type.UserExecutable, executable);
220        if (!ownerOnly) {
221            map.put(Type.GroupExecutable, executable);
222            map.put(Type.OtherExecutable, executable);
223        }
224        return computeNewPermissions(map);
225    }
226
227    /**
228     * Creates new permissions based on these permissions.
229     *
230     * @param readable Whether the new permissions should be readable.
231     * @param ownerOnly Whether the new permissions are only for the owner.
232     * @return the new permissions.
233     */
234    public Integer makeReadable(final boolean readable, final boolean ownerOnly) {
235        final EnumMap<Type, Boolean> map = new EnumMap<>(Type.class);
236        map.put(Type.UserReadable, readable);
237        if (!ownerOnly) {
238            map.put(Type.GroupReadable, readable);
239            map.put(Type.OtherReadable, readable);
240        }
241        return computeNewPermissions(map);
242    }
243
244    /**
245     * Creates new permissions based on these permissions.
246     *
247     * @param writable Whether the new permissions should be readable.
248     * @param ownerOnly Whether the new permissions are only for the owner.
249     * @return the new permissions.
250     */
251    public Integer makeWritable(final boolean writable, final boolean ownerOnly) {
252        final EnumMap<Type, Boolean> map = new EnumMap<>(Type.class);
253        map.put(Type.UserWritable, writable);
254        if (!ownerOnly) {
255            map.put(Type.GroupWritable, writable);
256            map.put(Type.OtherWritable, writable);
257        }
258        return computeNewPermissions(map);
259    }
260}