@@ -46,6 +46,9 @@ abstract class UnixUserDefinedFileAttributeView
46
46
// namespace for extended user attributes
47
47
private static final String USER_NAMESPACE = "user." ;
48
48
49
+ private static final int MIN_LISTXATTR_BUF_SIZE = 1024 ;
50
+ private static final int MAX_LISTXATTR_BUF_SIZE = 32 * 1024 ;
51
+
49
52
private byte [] nameAsBytes (UnixPath file , String name ) throws IOException {
50
53
if (name == null )
51
54
throw new NullPointerException ("'name' is null" );
@@ -59,7 +62,7 @@ private byte[] nameAsBytes(UnixPath file, String name) throws IOException {
59
62
}
60
63
61
64
// Parses buffer as array of NULL-terminated C strings.
62
- private List <String > asList (long address , int size ) {
65
+ private static List <String > asList (long address , int size ) {
63
66
List <String > list = new ArrayList <>();
64
67
int start = 0 ;
65
68
int pos = 0 ;
@@ -70,17 +73,30 @@ private List<String> asList(long address, int size) {
70
73
unsafe .copyMemory (null , address +start , value ,
71
74
Unsafe .ARRAY_BYTE_BASE_OFFSET , len );
72
75
String s = Util .toString (value );
73
- if (s .startsWith (USER_NAMESPACE )) {
74
- s = s .substring (USER_NAMESPACE .length ());
75
- list .add (s );
76
- }
76
+ list .add (s );
77
77
start = pos + 1 ;
78
78
}
79
79
pos ++;
80
80
}
81
81
return list ;
82
82
}
83
83
84
+ // runs flistxattr, increases buffer size up to MAX_LISTXATTR_BUF_SIZE if required
85
+ private static List <String > list (int fd , int bufSize ) throws UnixException {
86
+ try {
87
+ try (NativeBuffer buffer = NativeBuffers .getNativeBuffer (bufSize )) {
88
+ int n = flistxattr (fd , buffer .address (), bufSize );
89
+ return asList (buffer .address (), n );
90
+ } // release buffer before recursion
91
+ } catch (UnixException x ) {
92
+ if (x .errno () == ERANGE && bufSize < MAX_LISTXATTR_BUF_SIZE ) {
93
+ return list (fd , bufSize * 2 ); // try larger buffer size:
94
+ } else {
95
+ throw x ;
96
+ }
97
+ }
98
+ }
99
+
84
100
private final UnixPath file ;
85
101
private final boolean followLinks ;
86
102
@@ -105,32 +121,17 @@ public List<String> list() throws IOException {
105
121
} catch (UnixException x ) {
106
122
x .rethrowAsIOException (file );
107
123
}
108
- NativeBuffer buffer = null ;
109
124
try {
110
- int size = 1024 ;
111
- buffer = NativeBuffers .getNativeBuffer (size );
112
- for (;;) {
113
- try {
114
- int n = flistxattr (fd , buffer .address (), size );
115
- List <String > list = asList (buffer .address (), n );
116
- return Collections .unmodifiableList (list );
117
- } catch (UnixException x ) {
118
- // allocate larger buffer if required
119
- if (x .errno () == ERANGE && size < 32 *1024 ) {
120
- buffer .release ();
121
- size *= 2 ;
122
- buffer = null ;
123
- buffer = NativeBuffers .getNativeBuffer (size );
124
- continue ;
125
- }
126
- throw new FileSystemException (file .getPathForExceptionMessage (),
127
- null , "Unable to get list of extended attributes: " +
128
- x .getMessage ());
129
- }
130
- }
125
+ List <String > attrNames = list (fd , MIN_LISTXATTR_BUF_SIZE );
126
+ return attrNames .stream ()
127
+ .filter (s -> s .startsWith (USER_NAMESPACE ))
128
+ .map (s -> s .substring (USER_NAMESPACE .length ()))
129
+ .toList ();
130
+ } catch (UnixException x ) {
131
+ throw new FileSystemException (file .getPathForExceptionMessage (),
132
+ null , "Unable to get list of extended attributes: " +
133
+ x .getMessage ());
131
134
} finally {
132
- if (buffer != null )
133
- buffer .release ();
134
135
close (fd );
135
136
}
136
137
}
@@ -312,57 +313,18 @@ public void delete(String name) throws IOException {
312
313
* file descriptor for target file
313
314
*/
314
315
static void copyExtendedAttributes (int ofd , int nfd ) {
315
- NativeBuffer buffer = null ;
316
316
try {
317
-
318
- // call flistxattr to get list of extended attributes.
319
- int size = 1024 ;
320
- buffer = NativeBuffers .getNativeBuffer (size );
321
- for (;;) {
317
+ List <String > attrNames = list (ofd , MIN_LISTXATTR_BUF_SIZE );
318
+ for (String name : attrNames ) {
322
319
try {
323
- size = flistxattr (ofd , buffer .address (), size );
324
- break ;
325
- } catch (UnixException x ) {
326
- // allocate larger buffer if required
327
- if (x .errno () == ERANGE && size < 32 *1024 ) {
328
- buffer .release ();
329
- size *= 2 ;
330
- buffer = null ;
331
- buffer = NativeBuffers .getNativeBuffer (size );
332
- continue ;
333
- }
334
-
335
- // unable to get list of attributes
336
- return ;
337
- }
338
- }
339
-
340
- // parse buffer as array of NULL-terminated C strings.
341
- long address = buffer .address ();
342
- int start = 0 ;
343
- int pos = 0 ;
344
- while (pos < size ) {
345
- if (unsafe .getByte (address + pos ) == 0 ) {
346
- // extract attribute name and copy attribute to target.
347
- // FIXME: We can avoid needless copying by using address+pos
348
- // as the address of the name.
349
- int len = pos - start ;
350
- byte [] name = new byte [len ];
351
- unsafe .copyMemory (null , address +start , name ,
352
- Unsafe .ARRAY_BYTE_BASE_OFFSET , len );
353
- try {
354
- copyExtendedAttribute (ofd , name , nfd );
355
- } catch (UnixException ignore ) {
356
- // ignore
357
- }
358
- start = pos + 1 ;
320
+ copyExtendedAttribute (ofd , Util .toBytes (name ), nfd );
321
+ } catch (UnixException ignore ){
322
+ // ignore
359
323
}
360
- pos ++;
361
324
}
362
-
363
- } finally {
364
- if (buffer != null )
365
- buffer .release ();
325
+ } catch (UnixException e ) {
326
+ // unable to get list of attributes
327
+ return ;
366
328
}
367
329
}
368
330
0 commit comments