* 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:
@@ -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;
|
||||
#define MAX_EA_NAME_LEN 256
|
||||
#define MAX_EA_VALUE_LEN 65536
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* At least one maximum sized entry fits. */
|
||||
#define EA_BUFSIZ (sizeof (FILE_FULL_EA_INFORMATION) + MAX_EA_NAME_LEN \
|
||||
+ MAX_EA_VALUE_LEN)
|
||||
|
||||
int __stdcall
|
||||
read_ea (HANDLE hdl, const char *file, const char *attrname, char *attrbuf,
|
||||
int 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);
|
||||
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)
|
||||
CloseHandle (h);
|
||||
if (!NT_SUCCESS (status))
|
||||
debug_printf ("%x = NtQueryEaFile (%s, %s), Win32 error %d",
|
||||
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);
|
||||
debug_printf ("%d = read_ea (%S, %s, %p, %lu)",
|
||||
ret, attr.ObjectName, name, value, size);
|
||||
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user