diff options
Diffstat (limited to 'winsup/cygwin/ntea.cc')
-rw-r--r-- | winsup/cygwin/ntea.cc | 514 |
1 files changed, 0 insertions, 514 deletions
diff --git a/winsup/cygwin/ntea.cc b/winsup/cygwin/ntea.cc deleted file mode 100644 index 25ba6db1f..000000000 --- a/winsup/cygwin/ntea.cc +++ /dev/null @@ -1,514 +0,0 @@ -/* ntea.cc: code for manipulating Extended Attributes - - Copyright 1997, 1998, 2000, 2001, 2006, 2008, 2009, 2010 Red Hat, Inc. - -This file is part of Cygwin. - -This software is a copyrighted work licensed under the terms of the -Cygwin license. Please consult the file "CYGWIN_LICENSE" for -details. */ - -#include "winsup.h" -#include "cygtls.h" -#include "security.h" -#include "path.h" -#include "fhandler.h" -#include "dtable.h" -#include "cygheap.h" -#include "ntdll.h" -#include <stdlib.h> -#include <attr/xattr.h> - -#define MAX_EA_NAME_LEN 256 -#define MAX_EA_VALUE_LEN 65536 - -/* 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; - ssize_t ret = -1; - HANDLE h = hdl; - 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); - - /* Early open if handle is NULL. This allows to return error codes like - ENOENT before we actually check for the correctness of the EA name and - stuff like that. */ - if (!hdl) - { - status = NtOpenFile (&h, READ_CONTROL | FILE_READ_EA, &attr, &io, - FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT); - if (!NT_SUCCESS (status)) - { - __seterrno_from_nt_status (status); - goto out; - } - hdl = NULL; - } - - fea = (PFILE_FULL_EA_INFORMATION) alloca (EA_BUFSIZ); - - if (name) - { - size_t nlen; - - /* For compatibility with Linux, we only allow user xattrs and - return EOPNOTSUPP otherwise. */ - if (ascii_strncasematch (name, "user.", 5)) - name += 5; - else - { - set_errno (EOPNOTSUPP); - 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 (h) - { - status = NtQueryEaFile (h, &io, fea, EA_BUFSIZ, TRUE, gea, glen, - NULL, TRUE); - if (status != STATUS_ACCESS_DENIED || !hdl) - break; - } - status = NtOpenFile (&h, READ_CONTROL | FILE_READ_EA, &attr, &io, - FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT); - if (!NT_SUCCESS (status)) - break; - hdl = NULL; - } - if (!NT_SUCCESS (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 (name) - { - /* 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; - } - if (size > 0) - { - if (size < fea->EaValueLength) - { - set_errno (ERANGE); - goto out; - } - memcpy (value, fea->EaName + fea->EaNameLength + 1, - fea->EaValueLength); - } - ret = fea->EaValueLength; - } - else - { - ret = 0; - do - { - fea->EaNameLength += 5; /* "user." */ - if (size > 0) - { - if ((size_t) ret + fea->EaNameLength + 1 > size) - { - set_errno (ERANGE); - goto out; - } - /* For compatibility with Linux, we always prepend "user." to - the attribute name, so effectively we only support user - attributes from a application point of view. */ - char tmpbuf[MAX_EA_NAME_LEN * 2]; - char *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: - if (!hdl) - CloseHandle (h); - 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); - - /* Early open if handle is NULL. This allows to return error codes like - ENOENT before we actually check for the correctness of the EA name and - stuff like that. */ - if (!hdl) - { - status = NtOpenFile (&h, READ_CONTROL | FILE_WRITE_EA, &attr, &io, - FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT); - if (!NT_SUCCESS (status)) - { - __seterrno_from_nt_status (status); - goto out; - } - hdl = NULL; - } - - /* For compatibility with Linux, we only allow user xattrs and - return EOPNOTSUPP otherwise. */ - if (!ascii_strncasematch (name, "user.", 5)) - { - 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; - } - - /* Skip "user." prefix. */ - name += 5; - - 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 path_conv", 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 path_conv", 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; -} |