1a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot/*
2a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
3a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot *
4a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * Redistribution and use in source and binary forms, with or without
5a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * modification, are permitted provided that the following conditions
6a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * are met:
7a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot *
8a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot *   - Redistributions of source code must retain the above copyright
9a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot *     notice, this list of conditions and the following disclaimer.
10a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot *
11a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot *   - Redistributions in binary form must reproduce the above copyright
12a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot *     notice, this list of conditions and the following disclaimer in the
13a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot *     documentation and/or other materials provided with the distribution.
14a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot *
15a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot *   - Neither the name of Oracle nor the names of its
16a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot *     contributors may be used to endorse or promote products derived
17a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot *     from this software without specific prior written permission.
18a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot *
19a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot */
31a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
32a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot/*
33a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * This source code is provided to illustrate the usage of a given feature
34a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * or technique and has been deliberately simplified. Additional steps
35a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * required for a production-quality application, such as security checks,
36a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * input validation and proper error handling, might not be present in
37a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * this sample code.
38a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot */
39a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
40a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
41a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotimport java.nio.file.*;
42a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotimport java.nio.file.attribute.*;
43a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotimport static java.nio.file.attribute.PosixFilePermission.*;
44a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotimport static java.nio.file.FileVisitResult.*;
45a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotimport java.io.IOException;
46a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotimport java.util.*;
47a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
48a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot/**
49a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * Sample code that changes the permissions of files in a similar manner to the
50a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * chmod(1) program.
51a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot */
52a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
53a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotpublic class Chmod {
54a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
55a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    /**
56a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * Compiles a list of one or more <em>symbolic mode expressions</em> that
57a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * may be used to change a set of file permissions. This method is
58a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * intended for use where file permissions are required to be changed in
59a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * a manner similar to the UNIX <i>chmod</i> program.
60a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *
61a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * <p> The {@code exprs} parameter is a comma separated list of expressions
62a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * where each takes the form:
63a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * <blockquote>
64a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * <i>who operator</i> [<i>permissions</i>]
65a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * </blockquote>
66a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * where <i>who</i> is one or more of the characters {@code 'u'}, {@code 'g'},
67a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * {@code 'o'}, or {@code 'a'} meaning the owner (user), group, others, or
68a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * all (owner, group, and others) respectively.
69a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *
70a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * <p> <i>operator</i> is the character {@code '+'}, {@code '-'}, or {@code
71a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * '='} signifying how permissions are to be changed. {@code '+'} means the
72a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * permissions are added, {@code '-'} means the permissions are removed, and
73a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * {@code '='} means the permissions are assigned absolutely.
74a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *
75a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * <p> <i>permissions</i> is a sequence of zero or more of the following:
76a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * {@code 'r'} for read permission, {@code 'w'} for write permission, and
77a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * {@code 'x'} for execute permission. If <i>permissions</i> is omitted
78a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * when assigned absolutely, then the permissions are cleared for
79a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * the owner, group, or others as identified by <i>who</i>. When omitted
80a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * when adding or removing then the expression is ignored.
81a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *
82a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * <p> The following examples demonstrate possible values for the {@code
83a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * exprs} parameter:
84a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *
85a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * <table border="0">
86a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * <tr>
87a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *   <td> {@code u=rw} </td>
88a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *   <td> Sets the owner permissions to be read and write. </td>
89a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * </tr>
90a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * <tr>
91a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *   <td> {@code ug+w} </td>
92a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *   <td> Sets the owner write and group write permissions. </td>
93a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * </tr>
94a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * <tr>
95a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *   <td> {@code u+w,o-rwx} </td>
96a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *   <td> Sets the owner write, and removes the others read, others write
97a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *     and others execute permissions. </td>
98a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * </tr>
99a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * <tr>
100a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *   <td> {@code o=} </td>
101a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *   <td> Sets the others permission to none (others read, others write and
102a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *     others execute permissions are removed if set) </td>
103a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * </tr>
104a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * </table>
105a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *
106a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * @param   exprs
107a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *          List of one or more <em>symbolic mode expressions</em>
108a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *
109a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * @return  A {@code Changer} that may be used to changer a set of
110a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *          file permissions
111a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *
112a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * @throws  IllegalArgumentException
113a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     *          If the value of the {@code exprs} parameter is invalid
114a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     */
115a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    public static Changer compile(String exprs) {
116a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        // minimum is who and operator (u= for example)
117a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        if (exprs.length() < 2)
118a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            throw new IllegalArgumentException("Invalid mode");
119a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
120a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        // permissions that the changer will add or remove
121a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        final Set<PosixFilePermission> toAdd = new HashSet<PosixFilePermission>();
122a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        final Set<PosixFilePermission> toRemove = new HashSet<PosixFilePermission>();
123a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
124a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        // iterate over each of expression modes
125a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        for (String expr: exprs.split(",")) {
126a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            // minimum of who and operator
127a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            if (expr.length() < 2)
128a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                throw new IllegalArgumentException("Invalid mode");
129a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
130a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            int pos = 0;
131a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
132a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            // who
133a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            boolean u = false;
134a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            boolean g = false;
135a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            boolean o = false;
136a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            boolean done = false;
137a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            for (;;) {
138a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                switch (expr.charAt(pos)) {
139a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    case 'u' : u = true; break;
140a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    case 'g' : g = true; break;
141a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    case 'o' : o = true; break;
142a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    case 'a' : u = true; g = true; o = true; break;
143a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    default : done = true;
144a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                }
145a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                if (done)
146a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    break;
147a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                pos++;
148a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            }
149a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            if (!u && !g && !o)
150a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                throw new IllegalArgumentException("Invalid mode");
151a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
152a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            // get operator and permissions
153a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            char op = expr.charAt(pos++);
154a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            String mask = (expr.length() == pos) ? "" : expr.substring(pos);
155a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
156a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            // operator
157a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            boolean add = (op == '+');
158a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            boolean remove = (op == '-');
159a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            boolean assign = (op == '=');
160a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            if (!add && !remove && !assign)
161a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                throw new IllegalArgumentException("Invalid mode");
162a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
163a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            // who= means remove all
164a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            if (assign && mask.length() == 0) {
165a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                assign = false;
166a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                remove = true;
167a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                mask = "rwx";
168a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            }
169a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
170a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            // permissions
171a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            boolean r = false;
172a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            boolean w = false;
173a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            boolean x = false;
174a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            for (int i=0; i<mask.length(); i++) {
175a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                switch (mask.charAt(i)) {
176a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    case 'r' : r = true; break;
177a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    case 'w' : w = true; break;
178a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    case 'x' : x = true; break;
179a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    default:
180a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                        throw new IllegalArgumentException("Invalid mode");
181a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                }
182a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            }
183a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
184a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            // update permissions set
185a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            if (add) {
186a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                if (u) {
187a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (r) toAdd.add(OWNER_READ);
188a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (w) toAdd.add(OWNER_WRITE);
189a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (x) toAdd.add(OWNER_EXECUTE);
190a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                }
191a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                if (g) {
192a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (r) toAdd.add(GROUP_READ);
193a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (w) toAdd.add(GROUP_WRITE);
194a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (x) toAdd.add(GROUP_EXECUTE);
195a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                }
196a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                if (o) {
197a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (r) toAdd.add(OTHERS_READ);
198a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (w) toAdd.add(OTHERS_WRITE);
199a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (x) toAdd.add(OTHERS_EXECUTE);
200a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                }
201a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            }
202a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            if (remove) {
203a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                if (u) {
204a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (r) toRemove.add(OWNER_READ);
205a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (w) toRemove.add(OWNER_WRITE);
206a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (x) toRemove.add(OWNER_EXECUTE);
207a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                }
208a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                if (g) {
209a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (r) toRemove.add(GROUP_READ);
210a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (w) toRemove.add(GROUP_WRITE);
211a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (x) toRemove.add(GROUP_EXECUTE);
212a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                }
213a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                if (o) {
214a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (r) toRemove.add(OTHERS_READ);
215a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (w) toRemove.add(OTHERS_WRITE);
216a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (x) toRemove.add(OTHERS_EXECUTE);
217a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                }
218a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            }
219a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            if (assign) {
220a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                if (u) {
221a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (r) toAdd.add(OWNER_READ);
222a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                      else toRemove.add(OWNER_READ);
223a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (w) toAdd.add(OWNER_WRITE);
224a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                      else toRemove.add(OWNER_WRITE);
225a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (x) toAdd.add(OWNER_EXECUTE);
226a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                      else toRemove.add(OWNER_EXECUTE);
227a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                }
228a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                if (g) {
229a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (r) toAdd.add(GROUP_READ);
230a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                      else toRemove.add(GROUP_READ);
231a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (w) toAdd.add(GROUP_WRITE);
232a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                      else toRemove.add(GROUP_WRITE);
233a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (x) toAdd.add(GROUP_EXECUTE);
234a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                      else toRemove.add(GROUP_EXECUTE);
235a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                }
236a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                if (o) {
237a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (r) toAdd.add(OTHERS_READ);
238a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                      else toRemove.add(OTHERS_READ);
239a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (w) toAdd.add(OTHERS_WRITE);
240a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                      else toRemove.add(OTHERS_WRITE);
241a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                    if (x) toAdd.add(OTHERS_EXECUTE);
242a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                      else toRemove.add(OTHERS_EXECUTE);
243a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                }
244a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            }
245a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        }
246a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
247a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        // return changer
248a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        return new Changer() {
249a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            @Override
250a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            public Set<PosixFilePermission> change(Set<PosixFilePermission> perms) {
251a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                perms.addAll(toAdd);
252a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                perms.removeAll(toRemove);
253a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                return perms;
254a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            }
255a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        };
256a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    }
257a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
258a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    /**
259a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * A task that <i>changes</i> a set of {@link PosixFilePermission} elements.
260a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     */
261a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    public interface Changer {
262a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        /**
263a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot         * Applies the changes to the given set of permissions.
264a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot         *
265a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot         * @param   perms
266a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot         *          The set of permissions to change
267a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot         *
268a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot         * @return  The {@code perms} parameter
269a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot         */
270a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        Set<PosixFilePermission> change(Set<PosixFilePermission> perms);
271a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    }
272a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
273a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    /**
274a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * Changes the permissions of the file using the given Changer.
275a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     */
276a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    static void chmod(Path file, Changer changer) {
277a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        try {
278a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file);
279a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            Files.setPosixFilePermissions(file, changer.change(perms));
280a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        } catch (IOException x) {
281a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            System.err.println(x);
282a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        }
283a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    }
284a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
285a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    /**
286a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     * Changes the permission of each file and directory visited
287a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot     */
288a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    static class TreeVisitor implements FileVisitor<Path> {
289a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        private final Changer changer;
290a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
291a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        TreeVisitor(Changer changer) {
292a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            this.changer = changer;
293a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        }
294a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
295a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        @Override
296a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
297a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            chmod(dir, changer);
298a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            return CONTINUE;
299a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        }
300a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
301a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        @Override
302a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
303a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            chmod(file, changer);
304a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            return CONTINUE;
305a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        }
306a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
307a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        @Override
308a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
309a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            if (exc != null)
310a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                System.err.println("WARNING: " + exc);
311a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            return CONTINUE;
312a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        }
313a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
314a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        @Override
315a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        public FileVisitResult visitFileFailed(Path file, IOException exc) {
316a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            System.err.println("WARNING: " + exc);
317a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            return CONTINUE;
318a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        }
319a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    }
320a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
321a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    static void usage() {
322a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        System.err.println("java Chmod [-R] symbolic-mode-list file...");
323a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        System.exit(-1);
324a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    }
325a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
326a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    public static void main(String[] args) throws IOException {
327a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        if (args.length < 2)
328a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            usage();
329a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        int argi = 0;
330a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        int maxDepth = 0;
331a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        if (args[argi].equals("-R")) {
332a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            if (args.length < 3)
333a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot                usage();
334a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            argi++;
335a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            maxDepth = Integer.MAX_VALUE;
336a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        }
337a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
338a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        // compile the symbolic mode expressions
339a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        Changer changer = compile(args[argi++]);
340a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        TreeVisitor visitor = new TreeVisitor(changer);
341a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot
342a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        Set<FileVisitOption> opts = Collections.emptySet();
343a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        while (argi < args.length) {
344a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            Path file = Paths.get(args[argi]);
345a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            Files.walkFileTree(file, opts, maxDepth, visitor);
346a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot            argi++;
347a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot        }
348a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot    }
349a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot}
350