Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2008-02-10 18:43:04 +0300
committerCorinna Vinschen <corinna@vinschen.de>2008-02-10 18:43:04 +0300
commit50450dcc5f6f54bf1d8af7174fc950ca1449a9a3 (patch)
treed74c694e6412f33cbca27d8103b749fa308502ec
parentbebb25961c1ed29d217b1a40fc69c77ebdc18bcd (diff)
* 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.
-rw-r--r--winsup/cygwin/ChangeLog41
-rw-r--r--winsup/cygwin/Makefile.in2
-rw-r--r--winsup/cygwin/cygwin.din20
-rw-r--r--winsup/cygwin/errno.cc6
-rw-r--r--winsup/cygwin/fhandler.cc15
-rw-r--r--winsup/cygwin/fhandler.h4
-rw-r--r--winsup/cygwin/fhandler_disk_file.cc27
-rw-r--r--winsup/cygwin/include/cygwin/version.h5
-rw-r--r--winsup/cygwin/ntdll.h3
-rw-r--r--winsup/cygwin/ntea.cc561
-rw-r--r--winsup/cygwin/security.h8
11 files changed, 562 insertions, 130 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index e1d6a109c..5570c60f8 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,46 @@
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>
+
* libc/ftw.cc (ftw): Allow nfds < 0 for glibc compatibility.
* libc/nftw.c (nftw): Ditto.
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index a92b316d5..9586bfdd2 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -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 \
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 \
- 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 \
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 \
diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din
index eb767c55c..da6b986dd 100644
--- a/winsup/cygwin/cygwin.din
+++ b/winsup/cygwin/cygwin.din
@@ -28,6 +28,7 @@ sys_nerr = _sys_nerr DATA
_sys_nerr DATA
_timezone DATA
_tzname DATA
+_Exit SIGFE
a64l NOSIGFE
abort NOSIGFE
_abort = abort SIGFE
@@ -348,7 +349,6 @@ execvp SIGFE
_execvp = execvp SIGFE
exit = cygwin_exit SIGFE
_exit SIGFE
-_Exit SIGFE
exp NOSIGFE
_exp = exp NOSIGFE
exp10 NOSIGFE
@@ -432,12 +432,12 @@ _fcvtbuf = fcvtbuf SIGFE
fcvtf SIGFE
_fcvtf = fcvtf SIGFE
fdatasync SIGFE
-fdopendir SIGFE
fdim NOSIGFE
fdimf NOSIGFE
fdopen SIGFE
_fdopen = fdopen SIGFE
_fdopen64 = fdopen64 SIGFE
+fdopendir SIGFE
feof SIGFE
_feof = feof SIGFE
ferror SIGFE
@@ -453,6 +453,7 @@ _fgetpos = fgetpos SIGFE
_fgetpos64 = fgetpos64 SIGFE
fgets SIGFE
_fgets = fgets SIGFE
+fgetxattr SIGFE
fileno SIGFE
_fileno = fileno SIGFE
finite NOSIGFE
@@ -461,6 +462,7 @@ finitef NOSIGFE
_finitef = finitef NOSIGFE
fiprintf SIGFE
_fiprintf = fiprintf SIGFE
+flistxattr SIGFE
flock SIGFE
flockfile SIGFE
floor NOSIGFE
@@ -501,6 +503,7 @@ free SIGFE
_free = free SIGFE
freeaddrinfo = cygwin_freeaddrinfo SIGFE
freeifaddrs SIGFE
+fremovexattr SIGFE
freopen SIGFE
_freopen = freopen SIGFE
_freopen64 = freopen64 SIGFE
@@ -520,6 +523,7 @@ _fseeko64 = fseeko64 SIGFE
fsetpos SIGFE
_fsetpos = fsetpos SIGFE
_fsetpos64 = fsetpos64 SIGFE
+fsetxattr SIGFE
fstat SIGFE
_fstat = fstat SIGFE
_fstat64 = fstat64 SIGFE
@@ -695,6 +699,7 @@ getw SIGFE
_getw = getw SIGFE
getwd SIGFE
_getwd = getwd SIGFE
+getxattr SIGFE
glob SIGFE
_glob = glob SIGFE
globfree SIGFE
@@ -849,11 +854,14 @@ lgammaf NOSIGFE
_lgammaf = lgammaf NOSIGFE
lgammaf_r NOSIGFE
_lgammaf_r = lgammaf_r NOSIGFE
+lgetxattr SIGFE
link SIGFE
_link = link SIGFE
listen = cygwin_listen SIGFE
+listxattr SIGFE
llabs NOSIGFE
lldiv NOSIGFE
+llistxattr SIGFE
llrint = _f_llrint NOSIGFE
llrintf = _f_llrintf NOSIGFE
llrintl = _f_llrintl NOSIGFE
@@ -887,6 +895,7 @@ longjmp NOSIGFE
_longjmp = longjmp NOSIGFE
lrand48 NOSIGFE
_lrand48 = lrand48 NOSIGFE
+lremovexattr SIGFE
lrint = _f_lrint NOSIGFE
lrintf = _f_lrintf NOSIGFE
lrintl = _f_lrintl NOSIGFE
@@ -896,6 +905,7 @@ lsearch NOSIGFE
lseek SIGFE
_lseek = lseek SIGFE
_lseek64 = lseek64 SIGFE
+lsetxattr SIGFE
lstat SIGFE
_lstat = lstat SIGFE
_lstat64 = lstat64 SIGFE
@@ -1170,6 +1180,7 @@ remainderf NOSIGFE
_remainderf = remainderf NOSIGFE
remove SIGFE
_remove = remove SIGFE
+removexattr SIGFE
remque NOSIGFE
remquo NOSIGFE
remquof NOSIGFE
@@ -1341,6 +1352,7 @@ _setutent = setutent SIGFE
setutxent SIGFE
setvbuf SIGFE
_setvbuf = setvbuf SIGFE
+setxattr SIGFE
sexecl = sexecve_is_bad SIGFE
sexecle = sexecve_is_bad SIGFE
sexeclp = sexecve_is_bad SIGFE
@@ -1349,12 +1361,12 @@ sexecp = sexecve_is_bad SIGFE
sexecv = sexecve_is_bad SIGFE
sexecve = sexecve_is_bad SIGFE
sexecvpe = sexecve_is_bad SIGFE
+shm_open SIGFE
+shm_unlink SIGFE
shmat SIGFE
shmctl SIGFE
shmdt SIGFE
shmget SIGFE
-shm_open SIGFE
-shm_unlink SIGFE
shutdown = cygwin_shutdown SIGFE
sigaction SIGFE
sigaddset SIGFE
diff --git a/winsup/cygwin/errno.cc b/winsup/cygwin/errno.cc
index 50819a952..eebb46305 100644
--- a/winsup/cygwin/errno.cc
+++ b/winsup/cygwin/errno.cc
@@ -62,10 +62,15 @@ static NO_COPY struct
X (DISK_CORRUPT, EIO),
X (DISK_FULL, ENOSPC),
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 (EOM_OVERFLOW, EIO),
X (FILEMARK_DETECTED, EIO),
X (FILENAME_EXCED_RANGE, ENAMETOOLONG),
+ X (FILE_CORRUPT, EEXIST),
X (FILE_EXISTS, EEXIST),
X (FILE_INVALID, ENXIO),
X (FILE_NOT_FOUND, ENOENT),
@@ -76,6 +81,7 @@ static NO_COPY struct
X (INVALID_BLOCK_LENGTH, EIO),
X (INVALID_DATA, EINVAL),
X (INVALID_DRIVE, ENODEV),
+ X (INVALID_EA_NAME, EINVAL),
X (INVALID_FUNCTION, EBADRQC),
X (INVALID_HANDLE, EBADF),
X (INVALID_NAME, ENOENT),
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index a479d1b28..9a961172f 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -1476,6 +1476,21 @@ fhandler_base::facl (int cmd, int nentries, __aclent32_t *aclbufp)
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
fhandler_base::fadvise (_off64_t offset, _off64_t length, int advice)
{
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 28f34df45..cedf7f987 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -288,6 +288,8 @@ class fhandler_base
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 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 ftruncate (_off64_t, bool) __attribute__ ((regparm (3)));
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 fchown (__uid32_t uid, __gid32_t gid) __attribute__ ((regparm (2)));
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 ftruncate (_off64_t, bool) __attribute__ ((regparm (3)));
int __stdcall link (const char *) __attribute__ ((regparm (2)));
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index f660bb06c..a3c6566f5 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -946,6 +946,33 @@ cant_access_acl:
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
fhandler_disk_file::fadvise (_off64_t offset, _off64_t length, int advice)
{
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index 52e6a98d1..6690ebcb5 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -322,12 +322,15 @@ details. */
179: Export _f_llrint, _f_llrintf, _f_llrintl, _f_lrint, _f_lrintf,
_f_lrintl, _f_rint, _f_rintf, _f_rintl, llrint, llrintf, llrintl,
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 */
#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
shared memory regions. It is incremented when incompatible
diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h
index 91ddf28dd..0036e54ce 100644
--- a/winsup/cygwin/ntdll.h
+++ b/winsup/cygwin/ntdll.h
@@ -25,6 +25,9 @@
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xc0000034)
#define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xc000003A)
#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_DISK_FULL ((NTSTATUS) 0xc000007f)
#define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xc00000a1)
diff --git a/winsup/cygwin/ntea.cc b/winsup/cygwin/ntea.cc
index becb8ab2e..a5f9c7832 100644
--- a/winsup/cygwin/ntea.cc
+++ b/winsup/cygwin/ntea.cc
@@ -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.
-
- Written by Sergey S. Okhapkin (sos@prospect.com.ru)
+ Copyright 1997, 1998, 2000, 2001, 2006, 2008 Red Hat, Inc.
This file is part of Cygwin.
@@ -11,162 +9,485 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
-#include <stdlib.h>
-#include <ntdef.h>
+#include "cygtls.h"
+#include "cygerrno.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 <stdlib.h>
+#include <attr/xattr.h>
-/* Default to not using NTEA information */
-bool allow_ntea;
-
-/*
- * read_ea - read file's Extended Attribute.
- *
- * 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.
- */
+#define MAX_EA_NAME_LEN 256
+#define MAX_EA_VALUE_LEN 65536
-int __stdcall
-read_ea (HANDLE hdl, const char *file, const char *attrname, char *attrbuf,
- int len)
+/* At least one maximum sized entry fits. */
+#define EA_BUFSIZ (sizeof (FILE_FULL_EA_INFORMATION) + MAX_EA_NAME_LEN \
+ + MAX_EA_VALUE_LEN)
+
+#define NEXT_FEA(p) ((PFILE_FULL_EA_INFORMATION) (p->NextEntryOffset \
+ ? (char *) p + p->NextEntryOffset : NULL))
+
+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;
-
- /* 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. */
+ ssize_t ret = -1;
HANDLE h = hdl;
- NTSTATUS status = STATUS_SUCCESS;
- int ret = 0;
+ ULONG glen = 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)
{
- 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)
+ if (h)
{
- debug_printf ("Opening %s for querying EA %s failed, %E",
- file, attrname);
- goto out;
+ status = NtQueryEaFile (h, &io, fea, EA_BUFSIZ, TRUE, gea, glen,
+ NULL, TRUE);
+ if (status != STATUS_ACCESS_DENIED || !hdl)
+ break;
}
- status = NtQueryEaFile (h, &io, fea, flen, FALSE, gea, glen, NULL, TRUE);
- if (NT_SUCCESS (status) || !hdl)
+ status = NtOpenFile (&h, READ_CONTROL | FILE_READ_EA, &attr, &io,
+ FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
+ if (!NT_SUCCESS (status))
break;
- debug_printf ("1. chance, %x = NtQueryEaFile (%s, %s), Win32 error %d",
- status, file, attrname, RtlNtStatusToDosError (status));
hdl = NULL;
}
- if (!hdl)
- CloseHandle (h);
if (!NT_SUCCESS (status))
{
- ret = -1;
- debug_printf ("%x = NtQueryEaFile (%s, %s), Win32 error %d",
- status, file, attrname, RtlNtStatusToDosError (status));
+ if (status == STATUS_NO_EAS_ON_FILE)
+ ret = 0;
+ 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)
- ret = 0;
- else
+ if (name)
{
- memcpy (attrbuf, fea->EaName + fea->EaNameLength + 1,
- fea->EaValueLength);
+ if (size > 0)
+ {
+ 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;
}
+ 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:
- debug_printf ("%d = read_ea (%x, %s, %s, %x, %d)", ret, hdl, file, attrname,
- attrbuf, len);
+ if (!hdl)
+ CloseHandle (h);
+ debug_printf ("%d = read_ea (%S, %s, %p, %lu)",
+ ret, attr.ObjectName, name, value, size);
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)
+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;
- /* 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);
+ 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 = 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;
+ fea->EaNameLength = nlen;
+ fea->EaValueLength = size;
+ strcpy (fea->EaName, name);
+ if (value)
+ memcpy (fea->EaName + fea->EaNameLength + 1, value, size);
+
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)
+ if (h)
{
- debug_printf ("Opening %s for setting EA %s failed, %E",
- file, attrname);
- goto out;
+ status = NtSetEaFile (h, &io, fea, flen);
+ if (status != STATUS_ACCESS_DENIED || !hdl)
+ break;
}
- status = NtSetEaFile (h, &io, fea, flen);
- if (NT_SUCCESS (status) || !hdl)
+ status = NtOpenFile (&h, READ_CONTROL | FILE_WRITE_EA, &attr, &io,
+ FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
+ if (!NT_SUCCESS (status))
break;
- debug_printf ("1. chance, %x = NtQueryEaFile (%s, %s), Win32 error %d",
- status, file, attrname, RtlNtStatusToDosError (status));
hdl = NULL;
}
- if (!hdl)
- CloseHandle (h);
if (!NT_SUCCESS (status))
- debug_printf ("%x = NtQueryEaFile (%s, %s), Win32 error %d",
- status, file, attrname, RtlNtStatusToDosError (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 = true;
+ ret = 0;
out:
- debug_printf ("%d = write_ea (%x, %s, %s, %x, %d)", ret, hdl, file, attrname,
- attrbuf, len);
+ 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;
+}
diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h
index c69785563..ba0a06a94 100644
--- a/winsup/cygwin/security.h
+++ b/winsup/cygwin/security.h
@@ -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,
PSID sid2 = NO_SID, DWORD access2 = 0);
-int __stdcall read_ea (HANDLE hdl, const char *file, const char *attrname,
- char *buf, int len);
-BOOL __stdcall write_ea (HANDLE hdl, const char *file, const char *attrname,
- const char *buf, int len);
+ssize_t __stdcall read_ea (HANDLE hdl, path_conv &pc, const char *name,
+ char *value, size_t size);
+int __stdcall write_ea (HANDLE hdl, path_conv &pc, const char *name,
+ const char *value, size_t size, int flags);
/* Note: sid1 is usually (read: currently always) the current user's
effective sid (cygheap->user.sid ()). */