Last active
September 2, 2018 13:21
-
-
Save fumiyas/fa3ff0f3e537af423fb99f1d8ebef87e to your computer and use it in GitHub Desktop.
macOS getxattr(2) is broken on SMB shares
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
macOS getxattr(2) is broken on SMB shares: | |
* Cannot read xattr larger than 1048576 bytes. | |
* Fails by ERANGE (Result too large) if 'size' argument is smaller than | |
entire xattr size. | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/errno.h> | |
#include <sys/xattr.h> | |
int main(int argc, char **argv) { | |
setbuf(stdout, NULL); | |
if (argc < 3) { | |
printf("Usage: %s PATH NAME [READ_CHUNK_SIZE]\n", argv[0]); | |
exit(1); | |
} | |
const char *path = argv[1]; | |
const char *ea_name = argv[2]; | |
size_t ea_read_chunk_size_max = (argc >= 4) ? strtol(argv[3], NULL, 10) : 0; | |
printf("path: %s\n", path); | |
printf("ea name: %s\n", ea_name); | |
ssize_t ea_size = getxattr(path, ea_name, NULL, 0, 0, 0); | |
if (ea_size == -1) { | |
fprintf(stderr, "%s: ERROR: getxattr failed: %s: %s: %s\n", | |
argv[0], path, ea_name, strerror(errno)); | |
exit(1); | |
} | |
printf("ea size: %ld\n", (long)ea_size); | |
unsigned char *ea_value = malloc(ea_size); | |
if (ea_value == NULL) { | |
fprintf(stderr, "%s: ERROR: malloc failed: %s\n", | |
argv[0], strerror(errno)); | |
exit(1); | |
} | |
u_int32_t ea_read_offset = 0; | |
unsigned char *ea_value_ptr = ea_value; | |
size_t ea_read_remained = ea_size; | |
ssize_t ea_read_chunk_size; | |
for (long i=1; ea_read_offset < ea_size; i++) { | |
if (ea_read_chunk_size_max == 0 || ea_read_chunk_size_max > ea_read_remained) { | |
ea_read_chunk_size = ea_read_remained; | |
} else { | |
ea_read_chunk_size = ea_read_chunk_size_max; | |
} | |
ea_read_chunk_size = getxattr(path, ea_name, ea_value_ptr, ea_read_chunk_size, ea_read_offset, 0); | |
if (ea_read_chunk_size == -1) { | |
fprintf(stderr, "%s: ERROR: getxattr failed: %s: %s: %s\n", | |
argv[0], path, ea_name, strerror(errno)); | |
exit(1); | |
} | |
printf(" loop %8ld: read chunk size=%ld, offset=%ld\n", i, (long)ea_read_chunk_size, (long)ea_read_offset); | |
ea_value_ptr += ea_read_chunk_size; | |
ea_read_offset += ea_read_chunk_size; | |
ea_read_remained -= ea_read_chunk_size; | |
} | |
printf("ea read size: %ld\n", (long)ea_read_offset); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ ./getxattr '/Volumes/smb/foo.txt' com.apple.ResourceFork | |
path: /Volumes/smb/foo.txt | |
ea name: com.apple.ResourceFork | |
ea size: 6682679 | |
loop 1: read chunk size=1048576, offset=0 | |
./getxattr: ERROR: getxattr failed: /Volumes/smb/foo.txt: com.apple.ResourceFork: Result too large | |
$ ./getxattr '/Volumes/smb/foo.txt' com.apple.ResourceFork 100000 | |
path: /Volumes/smb/foo.txt | |
ea name: com.apple.ResourceFork | |
ea size: 6682679 | |
./getxattr: ERROR: getxattr failed: /Volumes/smb/foo.txt: com.apple.ResourceFork: Result too large |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment