Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java
32288 views
1
/*
2
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.nio.fs;
27
28
import java.nio.file.*;
29
import java.nio.file.attribute.*;
30
import java.util.*;
31
import java.io.IOException;
32
import sun.misc.Unsafe;
33
34
import static sun.nio.fs.UnixConstants.*;
35
import static sun.nio.fs.SolarisConstants.*;
36
import static sun.nio.fs.SolarisNativeDispatcher.*;
37
38
39
/**
40
* Solaris implementation of AclFileAttributeView with native support for
41
* NFSv4 ACLs on ZFS.
42
*/
43
44
class SolarisAclFileAttributeView
45
extends AbstractAclFileAttributeView
46
{
47
private static final Unsafe unsafe = Unsafe.getUnsafe();
48
49
// Maximum number of entries allowed in an ACL
50
private static final int MAX_ACL_ENTRIES = 1024;
51
52
/**
53
* typedef struct ace {
54
* uid_t a_who;
55
* uint32_t a_access_mask;
56
* uint16_t a_flags;
57
* uint16_t a_type;
58
* } ace_t;
59
*/
60
private static final short SIZEOF_ACE_T = 12;
61
private static final short OFFSETOF_UID = 0;
62
private static final short OFFSETOF_MASK = 4;
63
private static final short OFFSETOF_FLAGS = 8;
64
private static final short OFFSETOF_TYPE = 10;
65
66
private final UnixPath file;
67
private final boolean followLinks;
68
69
SolarisAclFileAttributeView(UnixPath file, boolean followLinks) {
70
this.file = file;
71
this.followLinks = followLinks;
72
}
73
74
/**
75
* Permission checks to access file
76
*/
77
private void checkAccess(UnixPath file,
78
boolean checkRead,
79
boolean checkWrite)
80
{
81
SecurityManager sm = System.getSecurityManager();
82
if (sm != null) {
83
if (checkRead)
84
file.checkRead();
85
if (checkWrite)
86
file.checkWrite();
87
sm.checkPermission(new RuntimePermission("accessUserInformation"));
88
}
89
}
90
91
/**
92
* Encode the ACL to the given buffer
93
*/
94
private static void encode(List<AclEntry> acl, long address) {
95
long offset = address;
96
for (AclEntry ace: acl) {
97
int flags = 0;
98
99
// map UserPrincipal to uid and flags
100
UserPrincipal who = ace.principal();
101
if (!(who instanceof UnixUserPrincipals.User))
102
throw new ProviderMismatchException();
103
UnixUserPrincipals.User user = (UnixUserPrincipals.User)who;
104
int uid;
105
if (user.isSpecial()) {
106
uid = -1;
107
if (who == UnixUserPrincipals.SPECIAL_OWNER)
108
flags |= ACE_OWNER;
109
else if (who == UnixUserPrincipals.SPECIAL_GROUP)
110
flags |= (ACE_GROUP | ACE_IDENTIFIER_GROUP);
111
else if (who == UnixUserPrincipals.SPECIAL_EVERYONE)
112
flags |= ACE_EVERYONE;
113
else
114
throw new AssertionError("Unable to map special identifier");
115
} else {
116
if (user instanceof UnixUserPrincipals.Group) {
117
uid = user.gid();
118
flags |= ACE_IDENTIFIER_GROUP;
119
} else {
120
uid = user.uid();
121
}
122
}
123
124
// map ACE type
125
int type;
126
switch (ace.type()) {
127
case ALLOW:
128
type = ACE_ACCESS_ALLOWED_ACE_TYPE;
129
break;
130
case DENY:
131
type = ACE_ACCESS_DENIED_ACE_TYPE;
132
break;
133
case AUDIT:
134
type = ACE_SYSTEM_AUDIT_ACE_TYPE;
135
break;
136
case ALARM:
137
type = ACE_SYSTEM_ALARM_ACE_TYPE;
138
break;
139
default:
140
throw new AssertionError("Unable to map ACE type");
141
}
142
143
// map permissions
144
Set<AclEntryPermission> aceMask = ace.permissions();
145
int mask = 0;
146
if (aceMask.contains(AclEntryPermission.READ_DATA))
147
mask |= ACE_READ_DATA;
148
if (aceMask.contains(AclEntryPermission.WRITE_DATA))
149
mask |= ACE_WRITE_DATA;
150
if (aceMask.contains(AclEntryPermission.APPEND_DATA))
151
mask |= ACE_APPEND_DATA;
152
if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS))
153
mask |= ACE_READ_NAMED_ATTRS;
154
if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS))
155
mask |= ACE_WRITE_NAMED_ATTRS;
156
if (aceMask.contains(AclEntryPermission.EXECUTE))
157
mask |= ACE_EXECUTE;
158
if (aceMask.contains(AclEntryPermission.DELETE_CHILD))
159
mask |= ACE_DELETE_CHILD;
160
if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES))
161
mask |= ACE_READ_ATTRIBUTES;
162
if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES))
163
mask |= ACE_WRITE_ATTRIBUTES;
164
if (aceMask.contains(AclEntryPermission.DELETE))
165
mask |= ACE_DELETE;
166
if (aceMask.contains(AclEntryPermission.READ_ACL))
167
mask |= ACE_READ_ACL;
168
if (aceMask.contains(AclEntryPermission.WRITE_ACL))
169
mask |= ACE_WRITE_ACL;
170
if (aceMask.contains(AclEntryPermission.WRITE_OWNER))
171
mask |= ACE_WRITE_OWNER;
172
if (aceMask.contains(AclEntryPermission.SYNCHRONIZE))
173
mask |= ACE_SYNCHRONIZE;
174
175
// FIXME - it would be desirable to know here if the file is a
176
// directory or not. Solaris returns EINVAL if an ACE has a directory
177
// -only flag and the file is not a directory.
178
Set<AclEntryFlag> aceFlags = ace.flags();
179
if (aceFlags.contains(AclEntryFlag.FILE_INHERIT))
180
flags |= ACE_FILE_INHERIT_ACE;
181
if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT))
182
flags |= ACE_DIRECTORY_INHERIT_ACE;
183
if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT))
184
flags |= ACE_NO_PROPAGATE_INHERIT_ACE;
185
if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY))
186
flags |= ACE_INHERIT_ONLY_ACE;
187
188
unsafe.putInt(offset + OFFSETOF_UID, uid);
189
unsafe.putInt(offset + OFFSETOF_MASK, mask);
190
unsafe.putShort(offset + OFFSETOF_FLAGS, (short)flags);
191
unsafe.putShort(offset + OFFSETOF_TYPE, (short)type);
192
193
offset += SIZEOF_ACE_T;
194
}
195
}
196
197
/**
198
* Decode the buffer, returning an ACL
199
*/
200
private static List<AclEntry> decode(long address, int n) {
201
ArrayList<AclEntry> acl = new ArrayList<>(n);
202
for (int i=0; i<n; i++) {
203
long offset = address + i*SIZEOF_ACE_T;
204
205
int uid = unsafe.getInt(offset + OFFSETOF_UID);
206
int mask = unsafe.getInt(offset + OFFSETOF_MASK);
207
int flags = (int)unsafe.getShort(offset + OFFSETOF_FLAGS);
208
int type = (int)unsafe.getShort(offset + OFFSETOF_TYPE);
209
210
// map uid and flags to UserPrincipal
211
UnixUserPrincipals.User who = null;
212
if ((flags & ACE_OWNER) > 0) {
213
who = UnixUserPrincipals.SPECIAL_OWNER;
214
} else if ((flags & ACE_GROUP) > 0) {
215
who = UnixUserPrincipals.SPECIAL_GROUP;
216
} else if ((flags & ACE_EVERYONE) > 0) {
217
who = UnixUserPrincipals.SPECIAL_EVERYONE;
218
} else if ((flags & ACE_IDENTIFIER_GROUP) > 0) {
219
who = UnixUserPrincipals.fromGid(uid);
220
} else {
221
who = UnixUserPrincipals.fromUid(uid);
222
}
223
224
AclEntryType aceType = null;
225
switch (type) {
226
case ACE_ACCESS_ALLOWED_ACE_TYPE:
227
aceType = AclEntryType.ALLOW;
228
break;
229
case ACE_ACCESS_DENIED_ACE_TYPE:
230
aceType = AclEntryType.DENY;
231
break;
232
case ACE_SYSTEM_AUDIT_ACE_TYPE:
233
aceType = AclEntryType.AUDIT;
234
break;
235
case ACE_SYSTEM_ALARM_ACE_TYPE:
236
aceType = AclEntryType.ALARM;
237
break;
238
default:
239
assert false;
240
}
241
242
Set<AclEntryPermission> aceMask = EnumSet.noneOf(AclEntryPermission.class);
243
if ((mask & ACE_READ_DATA) > 0)
244
aceMask.add(AclEntryPermission.READ_DATA);
245
if ((mask & ACE_WRITE_DATA) > 0)
246
aceMask.add(AclEntryPermission.WRITE_DATA);
247
if ((mask & ACE_APPEND_DATA ) > 0)
248
aceMask.add(AclEntryPermission.APPEND_DATA);
249
if ((mask & ACE_READ_NAMED_ATTRS) > 0)
250
aceMask.add(AclEntryPermission.READ_NAMED_ATTRS);
251
if ((mask & ACE_WRITE_NAMED_ATTRS) > 0)
252
aceMask.add(AclEntryPermission.WRITE_NAMED_ATTRS);
253
if ((mask & ACE_EXECUTE) > 0)
254
aceMask.add(AclEntryPermission.EXECUTE);
255
if ((mask & ACE_DELETE_CHILD ) > 0)
256
aceMask.add(AclEntryPermission.DELETE_CHILD);
257
if ((mask & ACE_READ_ATTRIBUTES) > 0)
258
aceMask.add(AclEntryPermission.READ_ATTRIBUTES);
259
if ((mask & ACE_WRITE_ATTRIBUTES) > 0)
260
aceMask.add(AclEntryPermission.WRITE_ATTRIBUTES);
261
if ((mask & ACE_DELETE) > 0)
262
aceMask.add(AclEntryPermission.DELETE);
263
if ((mask & ACE_READ_ACL) > 0)
264
aceMask.add(AclEntryPermission.READ_ACL);
265
if ((mask & ACE_WRITE_ACL) > 0)
266
aceMask.add(AclEntryPermission.WRITE_ACL);
267
if ((mask & ACE_WRITE_OWNER) > 0)
268
aceMask.add(AclEntryPermission.WRITE_OWNER);
269
if ((mask & ACE_SYNCHRONIZE) > 0)
270
aceMask.add(AclEntryPermission.SYNCHRONIZE);
271
272
Set<AclEntryFlag> aceFlags = EnumSet.noneOf(AclEntryFlag.class);
273
if ((flags & ACE_FILE_INHERIT_ACE) > 0)
274
aceFlags.add(AclEntryFlag.FILE_INHERIT);
275
if ((flags & ACE_DIRECTORY_INHERIT_ACE) > 0)
276
aceFlags.add(AclEntryFlag.DIRECTORY_INHERIT);
277
if ((flags & ACE_NO_PROPAGATE_INHERIT_ACE) > 0)
278
aceFlags.add(AclEntryFlag.NO_PROPAGATE_INHERIT);
279
if ((flags & ACE_INHERIT_ONLY_ACE) > 0)
280
aceFlags.add(AclEntryFlag.INHERIT_ONLY);
281
282
// build the ACL entry and add it to the list
283
AclEntry ace = AclEntry.newBuilder()
284
.setType(aceType)
285
.setPrincipal(who)
286
.setPermissions(aceMask).setFlags(aceFlags).build();
287
acl.add(ace);
288
}
289
290
return acl;
291
}
292
293
// Retrns true if NFSv4 ACLs not enabled on file system
294
private static boolean isAclsEnabled(int fd) {
295
try {
296
long enabled = fpathconf(fd, _PC_ACL_ENABLED);
297
if (enabled == _ACL_ACE_ENABLED)
298
return true;
299
} catch (UnixException x) {
300
}
301
return false;
302
}
303
304
@Override
305
public List<AclEntry> getAcl()
306
throws IOException
307
{
308
// permission check
309
checkAccess(file, true, false);
310
311
// open file (will fail if file is a link and not following links)
312
int fd = file.openForAttributeAccess(followLinks);
313
try {
314
long address = unsafe.allocateMemory(SIZEOF_ACE_T * MAX_ACL_ENTRIES);
315
try {
316
// read ACL and decode it
317
int n = facl(fd, ACE_GETACL, MAX_ACL_ENTRIES, address);
318
assert n >= 0;
319
return decode(address, n);
320
} catch (UnixException x) {
321
if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {
322
throw new FileSystemException(file.getPathForExceptionMessage(),
323
null, x.getMessage() + " (file system does not support NFSv4 ACLs)");
324
}
325
x.rethrowAsIOException(file);
326
return null; // keep compiler happy
327
} finally {
328
unsafe.freeMemory(address);
329
}
330
} finally {
331
close(fd);
332
}
333
}
334
335
@Override
336
public void setAcl(List<AclEntry> acl) throws IOException {
337
// permission check
338
checkAccess(file, false, true);
339
340
// open file (will fail if file is a link and not following links)
341
int fd = file.openForAttributeAccess(followLinks);
342
try {
343
// SECURITY: need to copy list as can change during processing
344
acl = new ArrayList<AclEntry>(acl);
345
int n = acl.size();
346
347
long address = unsafe.allocateMemory(SIZEOF_ACE_T * n);
348
try {
349
encode(acl, address);
350
facl(fd, ACE_SETACL, n, address);
351
} catch (UnixException x) {
352
if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {
353
throw new FileSystemException(file.getPathForExceptionMessage(),
354
null, x.getMessage() + " (file system does not support NFSv4 ACLs)");
355
}
356
if (x.errno() == EINVAL && (n < 3))
357
throw new IOException("ACL must contain at least 3 entries");
358
x.rethrowAsIOException(file);
359
} finally {
360
unsafe.freeMemory(address);
361
}
362
} finally {
363
close(fd);
364
}
365
}
366
367
@Override
368
public UserPrincipal getOwner()
369
throws IOException
370
{
371
checkAccess(file, true, false);
372
373
try {
374
UnixFileAttributes attrs =
375
UnixFileAttributes.get(file, followLinks);
376
return UnixUserPrincipals.fromUid(attrs.uid());
377
} catch (UnixException x) {
378
x.rethrowAsIOException(file);
379
return null; // keep compile happy
380
}
381
}
382
383
@Override
384
public void setOwner(UserPrincipal owner) throws IOException {
385
checkAccess(file, true, false);
386
387
if (!(owner instanceof UnixUserPrincipals.User))
388
throw new ProviderMismatchException();
389
if (owner instanceof UnixUserPrincipals.Group)
390
throw new IOException("'owner' parameter is a group");
391
int uid = ((UnixUserPrincipals.User)owner).uid();
392
393
try {
394
if (followLinks) {
395
lchown(file, uid, -1);
396
} else {
397
chown(file, uid, -1);
398
}
399
} catch (UnixException x) {
400
x.rethrowAsIOException(file);
401
}
402
}
403
}
404
405