* Makefile.in (DLL_OFILES): Add ntea.o.
* cygwin.din (getxattr, listxattr, removexattr, setxattr, lgetxattr, llistxattr, lremovexattr, lsetxattr, fgetxattr, flistxattr, fremovexattr, fsetxattr): Export Linux extended attribute functions. Sort. * errno.cc (errmap): Add mappings for ERROR_EAS_DIDNT_FIT, ERROR_EAS_NOT_SUPPORTED, ERROR_EA_LIST_INCONSISTENT, ERROR_EA_TABLE_FULL, ERROR_FILE_CORRUPT, ERROR_INVALID_EA_NAME. * fhandler.h (class fhandler_base): Declare new fgetxattr and fsetxattr methods. (class fhandler_disk_file): Ditto. * fhandler.cc (fhandler_base::fgetxattr): New method. (fhandler_base::fsetxattr): New method. * fhandler_disk_file.cc (fhandler_disk_file::fgetxattr): New method. (fhandler_disk_file::fsetxattr): New method. * ntdll.h (STATUS_EA_TOO_LARGE): Define. (STATUS_NONEXISTENT_EA_ENTRY): Define. (STATUS_NO_EAS_ON_FILE): Define. * ntea.cc (read_ea): Rewrite for long pathnames and for using with Linux extended attribute functions. (write_ea): Ditto. (getxattr_worker): New static function. (getxattr): New function. (lgetxattr): New function. (fgetxattr): New function. (listxattr): New function. (llistxattr): New function. (flistxattr): New function. (setxattr_worker): New static function. (setxattr): New function. (lsetxattr): New function. (fsetxattr): New function. (removexattr): New function. (lsetxattr): New function. (fsetxattr): New function. * security.h (read_ea): Change declaration according to above changes. (write_ea): Ditto. * include/cygwin/version.h: Bump API minor version.
This commit is contained in:
parent
bebb25961c
commit
50450dcc5f
|
@ -1,3 +1,44 @@
|
||||||
|
2008-02-10 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
|
* Makefile.in (DLL_OFILES): Add ntea.o.
|
||||||
|
* cygwin.din (getxattr, listxattr, removexattr, setxattr, lgetxattr,
|
||||||
|
llistxattr, lremovexattr, lsetxattr, fgetxattr, flistxattr,
|
||||||
|
fremovexattr, fsetxattr): Export Linux extended attribute functions.
|
||||||
|
Sort.
|
||||||
|
* errno.cc (errmap): Add mappings for ERROR_EAS_DIDNT_FIT,
|
||||||
|
ERROR_EAS_NOT_SUPPORTED, ERROR_EA_LIST_INCONSISTENT,
|
||||||
|
ERROR_EA_TABLE_FULL, ERROR_FILE_CORRUPT, ERROR_INVALID_EA_NAME.
|
||||||
|
* fhandler.h (class fhandler_base): Declare new fgetxattr and
|
||||||
|
fsetxattr methods.
|
||||||
|
(class fhandler_disk_file): Ditto.
|
||||||
|
* fhandler.cc (fhandler_base::fgetxattr): New method.
|
||||||
|
(fhandler_base::fsetxattr): New method.
|
||||||
|
* fhandler_disk_file.cc (fhandler_disk_file::fgetxattr): New method.
|
||||||
|
(fhandler_disk_file::fsetxattr): New method.
|
||||||
|
* ntdll.h (STATUS_EA_TOO_LARGE): Define.
|
||||||
|
(STATUS_NONEXISTENT_EA_ENTRY): Define.
|
||||||
|
(STATUS_NO_EAS_ON_FILE): Define.
|
||||||
|
* ntea.cc (read_ea): Rewrite for long pathnames and for using with
|
||||||
|
Linux extended attribute functions.
|
||||||
|
(write_ea): Ditto.
|
||||||
|
(getxattr_worker): New static function.
|
||||||
|
(getxattr): New function.
|
||||||
|
(lgetxattr): New function.
|
||||||
|
(fgetxattr): New function.
|
||||||
|
(listxattr): New function.
|
||||||
|
(llistxattr): New function.
|
||||||
|
(flistxattr): New function.
|
||||||
|
(setxattr_worker): New static function.
|
||||||
|
(setxattr): New function.
|
||||||
|
(lsetxattr): New function.
|
||||||
|
(fsetxattr): New function.
|
||||||
|
(removexattr): New function.
|
||||||
|
(lsetxattr): New function.
|
||||||
|
(fsetxattr): New function.
|
||||||
|
* security.h (read_ea): Change declaration according to above changes.
|
||||||
|
(write_ea): Ditto.
|
||||||
|
* include/cygwin/version.h: Bump API minor version.
|
||||||
|
|
||||||
2008-02-10 Corinna Vinschen <corinna@vinschen.de>
|
2008-02-10 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* libc/ftw.cc (ftw): Allow nfds < 0 for glibc compatibility.
|
* libc/ftw.cc (ftw): Allow nfds < 0 for glibc compatibility.
|
||||||
|
|
|
@ -136,7 +136,7 @@ DLL_OFILES:=assert.o autoload.o bsdlib.o ctype.o cxx.o cygheap.o cygthread.o \
|
||||||
fhandler_zero.o flock.o fnmatch.o fork.o fts.o ftw.o getopt.o glob.o \
|
fhandler_zero.o flock.o fnmatch.o fork.o fts.o ftw.o getopt.o glob.o \
|
||||||
grp.o heap.o hookapi.o inet_addr.o inet_network.o init.o ioctl.o ipc.o \
|
grp.o heap.o hookapi.o inet_addr.o inet_network.o init.o ioctl.o ipc.o \
|
||||||
localtime.o lsearch.o malloc_wrapper.o minires-os-if.o \
|
localtime.o lsearch.o malloc_wrapper.o minires-os-if.o \
|
||||||
minires.o miscfuncs.o mktemp.o mmap.o msg.o net.o netdb.o nftw.o \
|
minires.o miscfuncs.o mktemp.o mmap.o msg.o net.o netdb.o nftw.o ntea.o \
|
||||||
passwd.o path.o pinfo.o pipe.o poll.o posix_ipc.o pthread.o random.o \
|
passwd.o path.o pinfo.o pipe.o poll.o posix_ipc.o pthread.o random.o \
|
||||||
regcomp.o regerror.o regexec.o regfree.o registry.o resource.o rexec.o \
|
regcomp.o regerror.o regexec.o regfree.o registry.o resource.o rexec.o \
|
||||||
rcmd.o scandir.o sched.o sec_acl.o sec_auth.o sec_helper.o security.o \
|
rcmd.o scandir.o sched.o sec_acl.o sec_auth.o sec_helper.o security.o \
|
||||||
|
|
|
@ -28,6 +28,7 @@ sys_nerr = _sys_nerr DATA
|
||||||
_sys_nerr DATA
|
_sys_nerr DATA
|
||||||
_timezone DATA
|
_timezone DATA
|
||||||
_tzname DATA
|
_tzname DATA
|
||||||
|
_Exit SIGFE
|
||||||
a64l NOSIGFE
|
a64l NOSIGFE
|
||||||
abort NOSIGFE
|
abort NOSIGFE
|
||||||
_abort = abort SIGFE
|
_abort = abort SIGFE
|
||||||
|
@ -348,7 +349,6 @@ execvp SIGFE
|
||||||
_execvp = execvp SIGFE
|
_execvp = execvp SIGFE
|
||||||
exit = cygwin_exit SIGFE
|
exit = cygwin_exit SIGFE
|
||||||
_exit SIGFE
|
_exit SIGFE
|
||||||
_Exit SIGFE
|
|
||||||
exp NOSIGFE
|
exp NOSIGFE
|
||||||
_exp = exp NOSIGFE
|
_exp = exp NOSIGFE
|
||||||
exp10 NOSIGFE
|
exp10 NOSIGFE
|
||||||
|
@ -432,12 +432,12 @@ _fcvtbuf = fcvtbuf SIGFE
|
||||||
fcvtf SIGFE
|
fcvtf SIGFE
|
||||||
_fcvtf = fcvtf SIGFE
|
_fcvtf = fcvtf SIGFE
|
||||||
fdatasync SIGFE
|
fdatasync SIGFE
|
||||||
fdopendir SIGFE
|
|
||||||
fdim NOSIGFE
|
fdim NOSIGFE
|
||||||
fdimf NOSIGFE
|
fdimf NOSIGFE
|
||||||
fdopen SIGFE
|
fdopen SIGFE
|
||||||
_fdopen = fdopen SIGFE
|
_fdopen = fdopen SIGFE
|
||||||
_fdopen64 = fdopen64 SIGFE
|
_fdopen64 = fdopen64 SIGFE
|
||||||
|
fdopendir SIGFE
|
||||||
feof SIGFE
|
feof SIGFE
|
||||||
_feof = feof SIGFE
|
_feof = feof SIGFE
|
||||||
ferror SIGFE
|
ferror SIGFE
|
||||||
|
@ -453,6 +453,7 @@ _fgetpos = fgetpos SIGFE
|
||||||
_fgetpos64 = fgetpos64 SIGFE
|
_fgetpos64 = fgetpos64 SIGFE
|
||||||
fgets SIGFE
|
fgets SIGFE
|
||||||
_fgets = fgets SIGFE
|
_fgets = fgets SIGFE
|
||||||
|
fgetxattr SIGFE
|
||||||
fileno SIGFE
|
fileno SIGFE
|
||||||
_fileno = fileno SIGFE
|
_fileno = fileno SIGFE
|
||||||
finite NOSIGFE
|
finite NOSIGFE
|
||||||
|
@ -461,6 +462,7 @@ finitef NOSIGFE
|
||||||
_finitef = finitef NOSIGFE
|
_finitef = finitef NOSIGFE
|
||||||
fiprintf SIGFE
|
fiprintf SIGFE
|
||||||
_fiprintf = fiprintf SIGFE
|
_fiprintf = fiprintf SIGFE
|
||||||
|
flistxattr SIGFE
|
||||||
flock SIGFE
|
flock SIGFE
|
||||||
flockfile SIGFE
|
flockfile SIGFE
|
||||||
floor NOSIGFE
|
floor NOSIGFE
|
||||||
|
@ -501,6 +503,7 @@ free SIGFE
|
||||||
_free = free SIGFE
|
_free = free SIGFE
|
||||||
freeaddrinfo = cygwin_freeaddrinfo SIGFE
|
freeaddrinfo = cygwin_freeaddrinfo SIGFE
|
||||||
freeifaddrs SIGFE
|
freeifaddrs SIGFE
|
||||||
|
fremovexattr SIGFE
|
||||||
freopen SIGFE
|
freopen SIGFE
|
||||||
_freopen = freopen SIGFE
|
_freopen = freopen SIGFE
|
||||||
_freopen64 = freopen64 SIGFE
|
_freopen64 = freopen64 SIGFE
|
||||||
|
@ -520,6 +523,7 @@ _fseeko64 = fseeko64 SIGFE
|
||||||
fsetpos SIGFE
|
fsetpos SIGFE
|
||||||
_fsetpos = fsetpos SIGFE
|
_fsetpos = fsetpos SIGFE
|
||||||
_fsetpos64 = fsetpos64 SIGFE
|
_fsetpos64 = fsetpos64 SIGFE
|
||||||
|
fsetxattr SIGFE
|
||||||
fstat SIGFE
|
fstat SIGFE
|
||||||
_fstat = fstat SIGFE
|
_fstat = fstat SIGFE
|
||||||
_fstat64 = fstat64 SIGFE
|
_fstat64 = fstat64 SIGFE
|
||||||
|
@ -695,6 +699,7 @@ getw SIGFE
|
||||||
_getw = getw SIGFE
|
_getw = getw SIGFE
|
||||||
getwd SIGFE
|
getwd SIGFE
|
||||||
_getwd = getwd SIGFE
|
_getwd = getwd SIGFE
|
||||||
|
getxattr SIGFE
|
||||||
glob SIGFE
|
glob SIGFE
|
||||||
_glob = glob SIGFE
|
_glob = glob SIGFE
|
||||||
globfree SIGFE
|
globfree SIGFE
|
||||||
|
@ -849,11 +854,14 @@ lgammaf NOSIGFE
|
||||||
_lgammaf = lgammaf NOSIGFE
|
_lgammaf = lgammaf NOSIGFE
|
||||||
lgammaf_r NOSIGFE
|
lgammaf_r NOSIGFE
|
||||||
_lgammaf_r = lgammaf_r NOSIGFE
|
_lgammaf_r = lgammaf_r NOSIGFE
|
||||||
|
lgetxattr SIGFE
|
||||||
link SIGFE
|
link SIGFE
|
||||||
_link = link SIGFE
|
_link = link SIGFE
|
||||||
listen = cygwin_listen SIGFE
|
listen = cygwin_listen SIGFE
|
||||||
|
listxattr SIGFE
|
||||||
llabs NOSIGFE
|
llabs NOSIGFE
|
||||||
lldiv NOSIGFE
|
lldiv NOSIGFE
|
||||||
|
llistxattr SIGFE
|
||||||
llrint = _f_llrint NOSIGFE
|
llrint = _f_llrint NOSIGFE
|
||||||
llrintf = _f_llrintf NOSIGFE
|
llrintf = _f_llrintf NOSIGFE
|
||||||
llrintl = _f_llrintl NOSIGFE
|
llrintl = _f_llrintl NOSIGFE
|
||||||
|
@ -887,6 +895,7 @@ longjmp NOSIGFE
|
||||||
_longjmp = longjmp NOSIGFE
|
_longjmp = longjmp NOSIGFE
|
||||||
lrand48 NOSIGFE
|
lrand48 NOSIGFE
|
||||||
_lrand48 = lrand48 NOSIGFE
|
_lrand48 = lrand48 NOSIGFE
|
||||||
|
lremovexattr SIGFE
|
||||||
lrint = _f_lrint NOSIGFE
|
lrint = _f_lrint NOSIGFE
|
||||||
lrintf = _f_lrintf NOSIGFE
|
lrintf = _f_lrintf NOSIGFE
|
||||||
lrintl = _f_lrintl NOSIGFE
|
lrintl = _f_lrintl NOSIGFE
|
||||||
|
@ -896,6 +905,7 @@ lsearch NOSIGFE
|
||||||
lseek SIGFE
|
lseek SIGFE
|
||||||
_lseek = lseek SIGFE
|
_lseek = lseek SIGFE
|
||||||
_lseek64 = lseek64 SIGFE
|
_lseek64 = lseek64 SIGFE
|
||||||
|
lsetxattr SIGFE
|
||||||
lstat SIGFE
|
lstat SIGFE
|
||||||
_lstat = lstat SIGFE
|
_lstat = lstat SIGFE
|
||||||
_lstat64 = lstat64 SIGFE
|
_lstat64 = lstat64 SIGFE
|
||||||
|
@ -1170,6 +1180,7 @@ remainderf NOSIGFE
|
||||||
_remainderf = remainderf NOSIGFE
|
_remainderf = remainderf NOSIGFE
|
||||||
remove SIGFE
|
remove SIGFE
|
||||||
_remove = remove SIGFE
|
_remove = remove SIGFE
|
||||||
|
removexattr SIGFE
|
||||||
remque NOSIGFE
|
remque NOSIGFE
|
||||||
remquo NOSIGFE
|
remquo NOSIGFE
|
||||||
remquof NOSIGFE
|
remquof NOSIGFE
|
||||||
|
@ -1341,6 +1352,7 @@ _setutent = setutent SIGFE
|
||||||
setutxent SIGFE
|
setutxent SIGFE
|
||||||
setvbuf SIGFE
|
setvbuf SIGFE
|
||||||
_setvbuf = setvbuf SIGFE
|
_setvbuf = setvbuf SIGFE
|
||||||
|
setxattr SIGFE
|
||||||
sexecl = sexecve_is_bad SIGFE
|
sexecl = sexecve_is_bad SIGFE
|
||||||
sexecle = sexecve_is_bad SIGFE
|
sexecle = sexecve_is_bad SIGFE
|
||||||
sexeclp = sexecve_is_bad SIGFE
|
sexeclp = sexecve_is_bad SIGFE
|
||||||
|
@ -1349,12 +1361,12 @@ sexecp = sexecve_is_bad SIGFE
|
||||||
sexecv = sexecve_is_bad SIGFE
|
sexecv = sexecve_is_bad SIGFE
|
||||||
sexecve = sexecve_is_bad SIGFE
|
sexecve = sexecve_is_bad SIGFE
|
||||||
sexecvpe = sexecve_is_bad SIGFE
|
sexecvpe = sexecve_is_bad SIGFE
|
||||||
|
shm_open SIGFE
|
||||||
|
shm_unlink SIGFE
|
||||||
shmat SIGFE
|
shmat SIGFE
|
||||||
shmctl SIGFE
|
shmctl SIGFE
|
||||||
shmdt SIGFE
|
shmdt SIGFE
|
||||||
shmget SIGFE
|
shmget SIGFE
|
||||||
shm_open SIGFE
|
|
||||||
shm_unlink SIGFE
|
|
||||||
shutdown = cygwin_shutdown SIGFE
|
shutdown = cygwin_shutdown SIGFE
|
||||||
sigaction SIGFE
|
sigaction SIGFE
|
||||||
sigaddset SIGFE
|
sigaddset SIGFE
|
||||||
|
|
|
@ -62,10 +62,15 @@ static NO_COPY struct
|
||||||
X (DISK_CORRUPT, EIO),
|
X (DISK_CORRUPT, EIO),
|
||||||
X (DISK_FULL, ENOSPC),
|
X (DISK_FULL, ENOSPC),
|
||||||
X (DUP_NAME, ENOTUNIQ),
|
X (DUP_NAME, ENOTUNIQ),
|
||||||
|
X (EAS_DIDNT_FIT, ENOSPC),
|
||||||
|
X (EAS_NOT_SUPPORTED, ENOTSUP),
|
||||||
|
X (EA_LIST_INCONSISTENT, EINVAL),
|
||||||
|
X (EA_TABLE_FULL, ENOSPC),
|
||||||
X (END_OF_MEDIA, ENOSPC),
|
X (END_OF_MEDIA, ENOSPC),
|
||||||
X (EOM_OVERFLOW, EIO),
|
X (EOM_OVERFLOW, EIO),
|
||||||
X (FILEMARK_DETECTED, EIO),
|
X (FILEMARK_DETECTED, EIO),
|
||||||
X (FILENAME_EXCED_RANGE, ENAMETOOLONG),
|
X (FILENAME_EXCED_RANGE, ENAMETOOLONG),
|
||||||
|
X (FILE_CORRUPT, EEXIST),
|
||||||
X (FILE_EXISTS, EEXIST),
|
X (FILE_EXISTS, EEXIST),
|
||||||
X (FILE_INVALID, ENXIO),
|
X (FILE_INVALID, ENXIO),
|
||||||
X (FILE_NOT_FOUND, ENOENT),
|
X (FILE_NOT_FOUND, ENOENT),
|
||||||
|
@ -76,6 +81,7 @@ static NO_COPY struct
|
||||||
X (INVALID_BLOCK_LENGTH, EIO),
|
X (INVALID_BLOCK_LENGTH, EIO),
|
||||||
X (INVALID_DATA, EINVAL),
|
X (INVALID_DATA, EINVAL),
|
||||||
X (INVALID_DRIVE, ENODEV),
|
X (INVALID_DRIVE, ENODEV),
|
||||||
|
X (INVALID_EA_NAME, EINVAL),
|
||||||
X (INVALID_FUNCTION, EBADRQC),
|
X (INVALID_FUNCTION, EBADRQC),
|
||||||
X (INVALID_HANDLE, EBADF),
|
X (INVALID_HANDLE, EBADF),
|
||||||
X (INVALID_NAME, ENOENT),
|
X (INVALID_NAME, ENOENT),
|
||||||
|
|
|
@ -1476,6 +1476,21 @@ fhandler_base::facl (int cmd, int nentries, __aclent32_t *aclbufp)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
fhandler_base::fgetxattr (const char *name, void *value, size_t size)
|
||||||
|
{
|
||||||
|
set_errno (ENOTSUP);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fhandler_base::fsetxattr (const char *name, const void *value, size_t size,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
set_errno (ENOTSUP);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fhandler_base::fadvise (_off64_t offset, _off64_t length, int advice)
|
fhandler_base::fadvise (_off64_t offset, _off64_t length, int advice)
|
||||||
{
|
{
|
||||||
|
|
|
@ -288,6 +288,8 @@ class fhandler_base
|
||||||
virtual int __stdcall fchmod (mode_t mode) __attribute__ ((regparm (1)));
|
virtual int __stdcall fchmod (mode_t mode) __attribute__ ((regparm (1)));
|
||||||
virtual int __stdcall fchown (__uid32_t uid, __gid32_t gid) __attribute__ ((regparm (2)));
|
virtual int __stdcall fchown (__uid32_t uid, __gid32_t gid) __attribute__ ((regparm (2)));
|
||||||
virtual int __stdcall facl (int, int, __acl32 *) __attribute__ ((regparm (3)));
|
virtual int __stdcall facl (int, int, __acl32 *) __attribute__ ((regparm (3)));
|
||||||
|
virtual ssize_t __stdcall fgetxattr (const char *, void *, size_t) __attribute__ ((regparm (3)));
|
||||||
|
virtual int __stdcall fsetxattr (const char *, const void *, size_t, int) __attribute__ ((regparm (3)));
|
||||||
virtual int __stdcall fadvise (_off64_t, _off64_t, int) __attribute__ ((regparm (3)));
|
virtual int __stdcall fadvise (_off64_t, _off64_t, int) __attribute__ ((regparm (3)));
|
||||||
virtual int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3)));
|
virtual int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3)));
|
||||||
virtual int __stdcall link (const char *) __attribute__ ((regparm (2)));
|
virtual int __stdcall link (const char *) __attribute__ ((regparm (2)));
|
||||||
|
@ -686,6 +688,8 @@ class fhandler_disk_file: public fhandler_base
|
||||||
int __stdcall fchmod (mode_t mode) __attribute__ ((regparm (1)));
|
int __stdcall fchmod (mode_t mode) __attribute__ ((regparm (1)));
|
||||||
int __stdcall fchown (__uid32_t uid, __gid32_t gid) __attribute__ ((regparm (2)));
|
int __stdcall fchown (__uid32_t uid, __gid32_t gid) __attribute__ ((regparm (2)));
|
||||||
int __stdcall facl (int, int, __acl32 *) __attribute__ ((regparm (3)));
|
int __stdcall facl (int, int, __acl32 *) __attribute__ ((regparm (3)));
|
||||||
|
ssize_t __stdcall fgetxattr (const char *, void *, size_t) __attribute__ ((regparm (3)));
|
||||||
|
int __stdcall fsetxattr (const char *, const void *, size_t, int) __attribute__ ((regparm (3)));
|
||||||
int __stdcall fadvise (_off64_t, _off64_t, int) __attribute__ ((regparm (3)));
|
int __stdcall fadvise (_off64_t, _off64_t, int) __attribute__ ((regparm (3)));
|
||||||
int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3)));
|
int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3)));
|
||||||
int __stdcall link (const char *) __attribute__ ((regparm (2)));
|
int __stdcall link (const char *) __attribute__ ((regparm (2)));
|
||||||
|
|
|
@ -946,6 +946,33 @@ cant_access_acl:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
fhandler_disk_file::fgetxattr (const char *name, void *value, size_t size)
|
||||||
|
{
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
|
||||||
|
if (pc.is_fs_special ())
|
||||||
|
{
|
||||||
|
set_errno (ENOTSUP);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return read_ea (get_handle (), pc, name, (char *) value, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fhandler_disk_file::fsetxattr (const char *name, const void *value, size_t size,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
|
||||||
|
if (pc.is_fs_special ())
|
||||||
|
{
|
||||||
|
set_errno (ENOTSUP);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return write_ea (get_handle (), pc, name, (const char *) value, size, flags);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fhandler_disk_file::fadvise (_off64_t offset, _off64_t length, int advice)
|
fhandler_disk_file::fadvise (_off64_t offset, _off64_t length, int advice)
|
||||||
{
|
{
|
||||||
|
|
|
@ -322,12 +322,15 @@ details. */
|
||||||
179: Export _f_llrint, _f_llrintf, _f_llrintl, _f_lrint, _f_lrintf,
|
179: Export _f_llrint, _f_llrintf, _f_llrintl, _f_lrint, _f_lrintf,
|
||||||
_f_lrintl, _f_rint, _f_rintf, _f_rintl, llrint, llrintf, llrintl,
|
_f_lrintl, _f_rint, _f_rintf, _f_rintl, llrint, llrintf, llrintl,
|
||||||
rintl, lrintl, and redirect exports of lrint, lrintf, rint, rintf.
|
rintl, lrintl, and redirect exports of lrint, lrintf, rint, rintf.
|
||||||
|
180: Export getxattr, lgetxattr, fgetxattr, listxattr, llistxattr,
|
||||||
|
flistxattr, setxattr, lsetxattr, fsetxattr, removexattr,
|
||||||
|
lremovexattr, fremovexattr.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
|
/* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
|
||||||
|
|
||||||
#define CYGWIN_VERSION_API_MAJOR 0
|
#define CYGWIN_VERSION_API_MAJOR 0
|
||||||
#define CYGWIN_VERSION_API_MINOR 179
|
#define CYGWIN_VERSION_API_MINOR 180
|
||||||
|
|
||||||
/* There is also a compatibity version number associated with the
|
/* There is also a compatibity version number associated with the
|
||||||
shared memory regions. It is incremented when incompatible
|
shared memory regions. It is incremented when incompatible
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xc0000034)
|
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xc0000034)
|
||||||
#define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xc000003A)
|
#define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xc000003A)
|
||||||
#define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xc0000043)
|
#define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xc0000043)
|
||||||
|
#define STATUS_EA_TOO_LARGE ((NTSTATUS) 0xc0000050)
|
||||||
|
#define STATUS_NONEXISTENT_EA_ENTRY ((NTSTATUS) 0xc0000051)
|
||||||
|
#define STATUS_NO_EAS_ON_FILE ((NTSTATUS) 0xc0000052)
|
||||||
#define STATUS_DELETE_PENDING ((NTSTATUS) 0xc0000056)
|
#define STATUS_DELETE_PENDING ((NTSTATUS) 0xc0000056)
|
||||||
#define STATUS_DISK_FULL ((NTSTATUS) 0xc000007f)
|
#define STATUS_DISK_FULL ((NTSTATUS) 0xc000007f)
|
||||||
#define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xc00000a1)
|
#define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xc00000a1)
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
/* ntea.cc: code for manipulating NTEA information
|
/* ntea.cc: code for manipulating Extended Attributes
|
||||||
|
|
||||||
Copyright 1997, 1998, 2000, 2001, 2006 Red Hat, Inc.
|
Copyright 1997, 1998, 2000, 2001, 2006, 2008 Red Hat, Inc.
|
||||||
|
|
||||||
Written by Sergey S. Okhapkin (sos@prospect.com.ru)
|
|
||||||
|
|
||||||
This file is part of Cygwin.
|
This file is part of Cygwin.
|
||||||
|
|
||||||
|
@ -11,162 +9,485 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||||
details. */
|
details. */
|
||||||
|
|
||||||
#include "winsup.h"
|
#include "winsup.h"
|
||||||
#include <stdlib.h>
|
#include "cygtls.h"
|
||||||
#include <ntdef.h>
|
#include "cygerrno.h"
|
||||||
#include "security.h"
|
#include "security.h"
|
||||||
|
#include "path.h"
|
||||||
|
#include "fhandler.h"
|
||||||
|
#include "dtable.h"
|
||||||
|
#include "pinfo.h"
|
||||||
|
#include "cygheap.h"
|
||||||
|
#include <ntdef.h>
|
||||||
#include "ntdll.h"
|
#include "ntdll.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <attr/xattr.h>
|
||||||
|
|
||||||
/* Default to not using NTEA information */
|
#define MAX_EA_NAME_LEN 256
|
||||||
bool allow_ntea;
|
#define MAX_EA_VALUE_LEN 65536
|
||||||
|
|
||||||
/*
|
/* At least one maximum sized entry fits. */
|
||||||
* read_ea - read file's Extended Attribute.
|
#define EA_BUFSIZ (sizeof (FILE_FULL_EA_INFORMATION) + MAX_EA_NAME_LEN \
|
||||||
*
|
+ MAX_EA_VALUE_LEN)
|
||||||
* Parameters:
|
|
||||||
* file - pointer to filename
|
|
||||||
* attrname- pointer to EA name (case insensitiv)
|
|
||||||
* attrbuf - pointer to buffer to store EA's value.
|
|
||||||
* len - length of attrbuf.
|
|
||||||
* Return value:
|
|
||||||
* 0 - if file or attribute "attrname" not found.
|
|
||||||
* N - number of bytes stored in attrbuf if success.
|
|
||||||
* -1 - attrbuf too small for EA value.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int __stdcall
|
#define NEXT_FEA(p) ((PFILE_FULL_EA_INFORMATION) (p->NextEntryOffset \
|
||||||
read_ea (HANDLE hdl, const char *file, const char *attrname, char *attrbuf,
|
? (char *) p + p->NextEntryOffset : NULL))
|
||||||
int len)
|
|
||||||
|
ssize_t __stdcall
|
||||||
|
read_ea (HANDLE hdl, path_conv &pc, const char *name, char *value, size_t size)
|
||||||
{
|
{
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
NTSTATUS status;
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
|
ssize_t ret = -1;
|
||||||
/* Prepare buffer which receives the result. */
|
|
||||||
ULONG flen = sizeof (FILE_FULL_EA_INFORMATION) + strlen (attrname)
|
|
||||||
+ len + 1;
|
|
||||||
PFILE_FULL_EA_INFORMATION fea = (PFILE_FULL_EA_INFORMATION) alloca (flen);
|
|
||||||
/* Prepare buffer specifying the EA to search for. */
|
|
||||||
ULONG glen = sizeof (FILE_GET_EA_INFORMATION) + strlen (attrname);
|
|
||||||
PFILE_GET_EA_INFORMATION gea = (PFILE_GET_EA_INFORMATION) alloca (glen);
|
|
||||||
gea->NextEntryOffset = 0;
|
|
||||||
gea->EaNameLength = strlen (attrname);
|
|
||||||
strcpy (gea->EaName, attrname);
|
|
||||||
|
|
||||||
/* If no incoming hdl is given, the loop only runs once, trying to
|
|
||||||
open the file and to query the EA. If an incoming hdl is given,
|
|
||||||
the loop runs twice, first trying to query with the given hdl.
|
|
||||||
If this fails it tries to open the file and to query with that
|
|
||||||
handle again. */
|
|
||||||
HANDLE h = hdl;
|
HANDLE h = hdl;
|
||||||
NTSTATUS status = STATUS_SUCCESS;
|
ULONG glen = 0;
|
||||||
int ret = 0;
|
PFILE_GET_EA_INFORMATION gea = NULL;
|
||||||
|
PFILE_FULL_EA_INFORMATION fea;
|
||||||
|
/* We have to store the latest EaName to compare with the next one, since
|
||||||
|
ZwQueryEaFile has a bug when accessing files on a remote share. It
|
||||||
|
returns the last EA entry of the file infinitely. Even utilizing the
|
||||||
|
optional EaIndex only helps marginally. If you use that, the last
|
||||||
|
EA in the file is returned twice. */
|
||||||
|
char lastname[MAX_EA_NAME_LEN];
|
||||||
|
|
||||||
|
myfault efault;
|
||||||
|
if (efault.faulted (EFAULT))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
pc.get_object_attr (attr, sec_none_nih);
|
||||||
|
|
||||||
|
debug_printf ("read_ea (%S, %s, %p, %lu)",
|
||||||
|
attr.ObjectName, name, value, size);
|
||||||
|
|
||||||
|
fea = (PFILE_FULL_EA_INFORMATION) alloca (EA_BUFSIZ);
|
||||||
|
|
||||||
|
if (name)
|
||||||
|
{
|
||||||
|
size_t nlen;
|
||||||
|
|
||||||
|
/* Samba hides the user namespace from Windows clients. If we try to
|
||||||
|
retrieve a user namespace item, we remove the leading namespace from
|
||||||
|
the name, otherwise the search fails. */
|
||||||
|
if (pc.fs_is_samba ())
|
||||||
|
if (ascii_strncasematch (name, "user.", 5))
|
||||||
|
name += 5;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set_errno (ENOATTR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((nlen = strlen (name)) >= MAX_EA_NAME_LEN)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
glen = sizeof (FILE_GET_EA_INFORMATION) + nlen;
|
||||||
|
gea = (PFILE_GET_EA_INFORMATION) alloca (glen);
|
||||||
|
|
||||||
|
gea->NextEntryOffset = 0;
|
||||||
|
gea->EaNameLength = nlen;
|
||||||
|
strcpy (gea->EaName, name);
|
||||||
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!hdl && (h = CreateFile (file, FILE_READ_EA,
|
if (h)
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
||||||
&sec_none_nih, OPEN_EXISTING,
|
|
||||||
FILE_FLAG_BACKUP_SEMANTICS, NULL))
|
|
||||||
== INVALID_HANDLE_VALUE)
|
|
||||||
{
|
{
|
||||||
debug_printf ("Opening %s for querying EA %s failed, %E",
|
status = NtQueryEaFile (h, &io, fea, EA_BUFSIZ, TRUE, gea, glen,
|
||||||
file, attrname);
|
NULL, TRUE);
|
||||||
goto out;
|
if (status != STATUS_ACCESS_DENIED || !hdl)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
status = NtQueryEaFile (h, &io, fea, flen, FALSE, gea, glen, NULL, TRUE);
|
status = NtOpenFile (&h, READ_CONTROL | FILE_READ_EA, &attr, &io,
|
||||||
if (NT_SUCCESS (status) || !hdl)
|
FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
break;
|
break;
|
||||||
debug_printf ("1. chance, %x = NtQueryEaFile (%s, %s), Win32 error %d",
|
|
||||||
status, file, attrname, RtlNtStatusToDosError (status));
|
|
||||||
hdl = NULL;
|
hdl = NULL;
|
||||||
}
|
}
|
||||||
if (!hdl)
|
|
||||||
CloseHandle (h);
|
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
ret = -1;
|
if (status == STATUS_NO_EAS_ON_FILE)
|
||||||
debug_printf ("%x = NtQueryEaFile (%s, %s), Win32 error %d",
|
ret = 0;
|
||||||
status, file, attrname, RtlNtStatusToDosError (status));
|
else if (status == STATUS_NONEXISTENT_EA_ENTRY)
|
||||||
|
/* Actually this error code is either never generated, or it was only
|
||||||
|
generated in some old and long forgotton NT version. See below. */
|
||||||
|
set_errno (ENOATTR);
|
||||||
|
else
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
if (!fea->EaValueLength)
|
if (name)
|
||||||
ret = 0;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
memcpy (attrbuf, fea->EaName + fea->EaNameLength + 1,
|
if (size > 0)
|
||||||
fea->EaValueLength);
|
{
|
||||||
|
if (size < fea->EaValueLength)
|
||||||
|
{
|
||||||
|
set_errno (ERANGE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* Another weird behaviour of ZwQueryEaFile. If you ask for a
|
||||||
|
specific EA which is not present in the file's EA list, you don't
|
||||||
|
get a useful error code like STATUS_NONEXISTENT_EA_ENTRY. Rather
|
||||||
|
ZwQueryEaFile returns success with the entry's EaValueLength
|
||||||
|
set to 0. */
|
||||||
|
if (!fea->EaValueLength)
|
||||||
|
{
|
||||||
|
set_errno (ENOATTR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy (value, fea->EaName + fea->EaNameLength + 1,
|
||||||
|
fea->EaValueLength);
|
||||||
|
}
|
||||||
ret = fea->EaValueLength;
|
ret = fea->EaValueLength;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (pc.fs_is_samba ()) /* See below. */
|
||||||
|
fea->EaNameLength += 5;
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
if ((size_t) ret + fea->EaNameLength + 1 > size)
|
||||||
|
{
|
||||||
|
set_errno (ERANGE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* Samba hides the user namespace from Windows clients. We add
|
||||||
|
it in EA listings to keep tools like attr/getfattr/setfattr
|
||||||
|
happy. */
|
||||||
|
char tmpbuf[MAX_EA_NAME_LEN * 2], *tp = tmpbuf;
|
||||||
|
if (pc.fs_is_samba ())
|
||||||
|
tp = stpcpy (tmpbuf, "user.");
|
||||||
|
stpcpy (tp, fea->EaName);
|
||||||
|
/* NTFS stores all EA names in uppercase unfortunately. To keep
|
||||||
|
compatibility with ext/xfs EA namespaces and accompanying
|
||||||
|
tools, which expect the namespaces to be lower case, we return
|
||||||
|
EA names in lowercase if the file is on a native NTFS. */
|
||||||
|
if (pc.fs_is_ntfs ())
|
||||||
|
strlwr (tp);
|
||||||
|
tp = stpcpy (value, tmpbuf) + 1;
|
||||||
|
ret += tp - value;
|
||||||
|
value = tp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret += fea->EaNameLength + 1;
|
||||||
|
strcpy (lastname, fea->EaName);
|
||||||
|
status = NtQueryEaFile (h, &io, fea, EA_BUFSIZ, TRUE, NULL, 0,
|
||||||
|
NULL, FALSE);
|
||||||
|
}
|
||||||
|
while (NT_SUCCESS (status) && strcmp (lastname, fea->EaName) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
debug_printf ("%d = read_ea (%x, %s, %s, %x, %d)", ret, hdl, file, attrname,
|
|
||||||
attrbuf, len);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* write_ea - write file's Extended Attribute.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* file - pointer to filename
|
|
||||||
* attrname- pointer to EA name (case insensitiv)
|
|
||||||
* attrbuf - pointer to buffer with EA value.
|
|
||||||
* len - length of attrbuf.
|
|
||||||
* Return value:
|
|
||||||
* true if success, false otherwice.
|
|
||||||
* Note: if len=0 given EA will be deleted.
|
|
||||||
*/
|
|
||||||
|
|
||||||
BOOL __stdcall
|
|
||||||
write_ea (HANDLE hdl, const char *file, const char *attrname,
|
|
||||||
const char *attrbuf, int len)
|
|
||||||
{
|
|
||||||
IO_STATUS_BLOCK io;
|
|
||||||
|
|
||||||
/* Prepare buffer specifying the EA to write back. */
|
|
||||||
ULONG flen = sizeof (FILE_FULL_EA_INFORMATION) + strlen (attrname)
|
|
||||||
+ len + 1;
|
|
||||||
PFILE_FULL_EA_INFORMATION fea = (PFILE_FULL_EA_INFORMATION) alloca (flen);
|
|
||||||
fea->NextEntryOffset = 0;
|
|
||||||
fea->Flags = 0;
|
|
||||||
fea->EaNameLength = strlen (attrname);
|
|
||||||
fea->EaValueLength = len;
|
|
||||||
strcpy (fea->EaName, attrname);
|
|
||||||
memcpy (fea->EaName + fea->EaNameLength + 1, attrbuf, len);
|
|
||||||
|
|
||||||
/* If no incoming hdl is given, the loop only runs once, trying to
|
|
||||||
open the file and to set the EA. If an incoming hdl is given,
|
|
||||||
the loop runs twice, first trying to set the EA with the given hdl.
|
|
||||||
If this fails it tries to open the file and to set the EA with that
|
|
||||||
handle again. */
|
|
||||||
HANDLE h = hdl;
|
|
||||||
NTSTATUS status = STATUS_SUCCESS;
|
|
||||||
bool ret = false;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (!hdl && (h = CreateFile (file, FILE_READ_EA,
|
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
||||||
&sec_none_nih, OPEN_EXISTING,
|
|
||||||
FILE_FLAG_BACKUP_SEMANTICS, NULL))
|
|
||||||
== INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
debug_printf ("Opening %s for setting EA %s failed, %E",
|
|
||||||
file, attrname);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
status = NtSetEaFile (h, &io, fea, flen);
|
|
||||||
if (NT_SUCCESS (status) || !hdl)
|
|
||||||
break;
|
|
||||||
debug_printf ("1. chance, %x = NtQueryEaFile (%s, %s), Win32 error %d",
|
|
||||||
status, file, attrname, RtlNtStatusToDosError (status));
|
|
||||||
hdl = NULL;
|
|
||||||
}
|
|
||||||
if (!hdl)
|
if (!hdl)
|
||||||
CloseHandle (h);
|
CloseHandle (h);
|
||||||
if (!NT_SUCCESS (status))
|
debug_printf ("%d = read_ea (%S, %s, %p, %lu)",
|
||||||
debug_printf ("%x = NtQueryEaFile (%s, %s), Win32 error %d",
|
ret, attr.ObjectName, name, value, size);
|
||||||
status, file, attrname, RtlNtStatusToDosError (status));
|
|
||||||
else
|
|
||||||
ret = true;
|
|
||||||
|
|
||||||
out:
|
|
||||||
debug_printf ("%d = write_ea (%x, %s, %s, %x, %d)", ret, hdl, file, attrname,
|
|
||||||
attrbuf, len);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __stdcall
|
||||||
|
write_ea (HANDLE hdl, path_conv &pc, const char *name, const char *value,
|
||||||
|
size_t size, int flags)
|
||||||
|
{
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
NTSTATUS status;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
int ret = -1;
|
||||||
|
HANDLE h = hdl;
|
||||||
|
PFILE_FULL_EA_INFORMATION fea;
|
||||||
|
ULONG flen;
|
||||||
|
size_t nlen;
|
||||||
|
|
||||||
|
myfault efault;
|
||||||
|
if (efault.faulted (EFAULT))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
pc.get_object_attr (attr, sec_none_nih);
|
||||||
|
|
||||||
|
debug_printf ("write_ea (%S, %s, %p, %lu, %d)",
|
||||||
|
attr.ObjectName, name, value, size, flags);
|
||||||
|
|
||||||
|
/* Samba hides the user namespace from Windows clients. If we get a
|
||||||
|
user namespace item, we remove the leading namespace from the name.
|
||||||
|
This keeps tools like attr/getfattr/setfattr happy. Otherwise
|
||||||
|
setting the EA fails as if we don't have the permissions. */
|
||||||
|
if (pc.fs_is_samba () && ascii_strncasematch (name, "user.", 5))
|
||||||
|
name += 5;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set_errno (EOPNOTSUPP);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* removexattr is supposed to fail with ENOATTR if the requested EA is not
|
||||||
|
available. This is equivalent to the XATTR_REPLACE flag for setxattr. */
|
||||||
|
if (!value)
|
||||||
|
flags = XATTR_REPLACE;
|
||||||
|
|
||||||
|
if (flags)
|
||||||
|
{
|
||||||
|
if (flags != XATTR_CREATE && flags != XATTR_REPLACE)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ssize_t rret = read_ea (hdl, pc, name, NULL, 0);
|
||||||
|
if (flags == XATTR_CREATE && rret > 0)
|
||||||
|
{
|
||||||
|
set_errno (EEXIST);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (flags == XATTR_REPLACE && rret < 0)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((nlen = strlen (name)) >= MAX_EA_NAME_LEN)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
flen = sizeof (FILE_FULL_EA_INFORMATION) + nlen + 1 + size;
|
||||||
|
fea = (PFILE_FULL_EA_INFORMATION) alloca (flen);
|
||||||
|
fea->NextEntryOffset = 0;
|
||||||
|
fea->Flags = 0;
|
||||||
|
fea->EaNameLength = nlen;
|
||||||
|
fea->EaValueLength = size;
|
||||||
|
strcpy (fea->EaName, name);
|
||||||
|
if (value)
|
||||||
|
memcpy (fea->EaName + fea->EaNameLength + 1, value, size);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (h)
|
||||||
|
{
|
||||||
|
status = NtSetEaFile (h, &io, fea, flen);
|
||||||
|
if (status != STATUS_ACCESS_DENIED || !hdl)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
status = NtOpenFile (&h, READ_CONTROL | FILE_WRITE_EA, &attr, &io,
|
||||||
|
FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
|
break;
|
||||||
|
hdl = NULL;
|
||||||
|
}
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
/* STATUS_EA_TOO_LARGE has a matching Win32 error ERROR_EA_TABLE_FULL.
|
||||||
|
Too bad RtlNtStatusToDosError does not translate STATUS_EA_TOO_LARGE
|
||||||
|
to ERROR_EA_TABLE_FULL, but to ERROR_EA_LIST_INCONSISTENT. This
|
||||||
|
error code is also returned for STATUS_EA_LIST_INCONSISTENT, which
|
||||||
|
means the incoming EA list is... inconsistent. For obvious reasons
|
||||||
|
we translate ERROR_EA_LIST_INCONSISTENT to EINVAL, so we have to
|
||||||
|
handle STATUS_EA_TOO_LARGE explicitely here, to get the correct
|
||||||
|
mapping to ENOSPC. */
|
||||||
|
if (status == STATUS_EA_TOO_LARGE)
|
||||||
|
set_errno (ENOSPC);
|
||||||
|
else
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (!hdl)
|
||||||
|
CloseHandle (h);
|
||||||
|
debug_printf ("%d = write_ea (%S, %s, %p, %lu, %d)",
|
||||||
|
ret, attr.ObjectName, name, value, size, flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t __stdcall
|
||||||
|
getxattr_worker (path_conv &pc, const char *name, void *value, size_t size)
|
||||||
|
{
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
|
if (pc.error)
|
||||||
|
{
|
||||||
|
debug_printf ("got %d error from build_fh_name", pc.error);
|
||||||
|
set_errno (pc.error);
|
||||||
|
}
|
||||||
|
else if (pc.exists ())
|
||||||
|
{
|
||||||
|
fhandler_base *fh;
|
||||||
|
|
||||||
|
if (!(fh = build_fh_pc (pc)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = fh->fgetxattr (name, value, size);
|
||||||
|
delete fh;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
set_errno (ENOENT);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" ssize_t
|
||||||
|
getxattr (const char *path, const char *name, void *value, size_t size)
|
||||||
|
{
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
path_conv pc (path, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
|
||||||
|
return getxattr_worker (pc, name, value, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" ssize_t
|
||||||
|
lgetxattr (const char *path, const char *name, void *value, size_t size)
|
||||||
|
{
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
path_conv pc (path, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes);
|
||||||
|
return getxattr_worker (pc, name, value, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" ssize_t
|
||||||
|
fgetxattr (int fd, const char *name, void *value, size_t size)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cygheap_fdget cfd (fd);
|
||||||
|
if (cfd < 0)
|
||||||
|
res = -1;
|
||||||
|
else
|
||||||
|
res = cfd->fgetxattr (name, value, size);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" ssize_t
|
||||||
|
listxattr (const char *path, char *list, size_t size)
|
||||||
|
{
|
||||||
|
path_conv pc (path, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
|
||||||
|
return getxattr_worker (pc, NULL, list, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" ssize_t
|
||||||
|
llistxattr (const char *path, char *list, size_t size)
|
||||||
|
{
|
||||||
|
path_conv pc (path, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes);
|
||||||
|
return getxattr_worker (pc, NULL, list, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" ssize_t
|
||||||
|
flistxattr (int fd, char *list, size_t size)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
cygheap_fdget cfd (fd);
|
||||||
|
if (cfd < 0)
|
||||||
|
res = -1;
|
||||||
|
else
|
||||||
|
res = cfd->fgetxattr (NULL, list, size);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __stdcall
|
||||||
|
setxattr_worker (path_conv &pc, const char *name, const void *value,
|
||||||
|
size_t size, int flags)
|
||||||
|
{
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
|
if (pc.error)
|
||||||
|
{
|
||||||
|
debug_printf ("got %d error from build_fh_name", pc.error);
|
||||||
|
set_errno (pc.error);
|
||||||
|
}
|
||||||
|
else if (pc.exists ())
|
||||||
|
{
|
||||||
|
fhandler_base *fh;
|
||||||
|
|
||||||
|
if (!(fh = build_fh_pc (pc)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = fh->fsetxattr (name, value, size, flags);
|
||||||
|
delete fh;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
set_errno (ENOENT);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
setxattr (const char *path, const char *name, const void *value, size_t size,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
if (!size)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
path_conv pc (path, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes);
|
||||||
|
return setxattr_worker (pc, name, value, size, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
lsetxattr (const char *path, const char *name, const void *value, size_t size,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
if (!size)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
path_conv pc (path, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes);
|
||||||
|
return setxattr_worker (pc, name, value, size, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
fsetxattr (int fd, const char *name, const void *value, size_t size, int flags)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (!size)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cygheap_fdget cfd (fd);
|
||||||
|
if (cfd < 0)
|
||||||
|
res = -1;
|
||||||
|
else
|
||||||
|
res = cfd->fsetxattr (name, value, size, flags);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
removexattr (const char *path, const char *name)
|
||||||
|
{
|
||||||
|
path_conv pc (path, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
|
||||||
|
return setxattr_worker (pc, name, NULL, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
lremovexattr (const char *path, const char *name)
|
||||||
|
{
|
||||||
|
path_conv pc (path, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes);
|
||||||
|
return setxattr_worker (pc, name, NULL, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
fremovexattr (int fd, const char *name)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
cygheap_fdget cfd (fd);
|
||||||
|
if (cfd < 0)
|
||||||
|
res = -1;
|
||||||
|
else
|
||||||
|
res = cfd->fsetxattr (name, NULL, 0, 0);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
|
@ -423,10 +423,10 @@ extern SECURITY_ATTRIBUTES *__stdcall __sec_user (PVOID sa_buf, PSID sid1, PSID
|
||||||
extern bool sec_acl (PACL acl, bool original, bool admins, PSID sid1 = NO_SID,
|
extern bool sec_acl (PACL acl, bool original, bool admins, PSID sid1 = NO_SID,
|
||||||
PSID sid2 = NO_SID, DWORD access2 = 0);
|
PSID sid2 = NO_SID, DWORD access2 = 0);
|
||||||
|
|
||||||
int __stdcall read_ea (HANDLE hdl, const char *file, const char *attrname,
|
ssize_t __stdcall read_ea (HANDLE hdl, path_conv &pc, const char *name,
|
||||||
char *buf, int len);
|
char *value, size_t size);
|
||||||
BOOL __stdcall write_ea (HANDLE hdl, const char *file, const char *attrname,
|
int __stdcall write_ea (HANDLE hdl, path_conv &pc, const char *name,
|
||||||
const char *buf, int len);
|
const char *value, size_t size, int flags);
|
||||||
|
|
||||||
/* Note: sid1 is usually (read: currently always) the current user's
|
/* Note: sid1 is usually (read: currently always) the current user's
|
||||||
effective sid (cygheap->user.sid ()). */
|
effective sid (cygheap->user.sid ()). */
|
||||||
|
|
Loading…
Reference in New Issue