* Throughout, use __try/__except/__endtry blocks, rather than myfault
handler. * cygtls.cc (_cygtls::remove): Accommodate the fact that pathbufs has been moved from _local_storage to _cygtls. * cygtls.h (class tls_pathbuf): Add comment to hint to gendef usage of counters. Change type of counters to uint32_t for clarity. Remove _cygtls as friend class. (struct _local_storage): Move pathbufs from here... (struct _cygtls): ...to here, allowing to access it from _sigbe. (class san): Only define on 32 bit. Remove errno, _c_cnt and _w_cnt members. (san::setup): Drop parameter. Don't initialize removed members. (san::leave): Don't set removed members. (class myfault): Only define on 32 bit. (myfault::faulted): Only keep implementation not taking any parameter. Drop argument in call to sebastian.setup. (__try/__leave/__except/__endtry): Implement to support real SEH. For now stick to SJLJ on 32 bit. * dcrt0.cc (dll_crt0_0): Drop 64 bit call to exception::install_myfault_handler. * exception.h (exception_handler): Define with EXCEPTION_DISPOSITION as return type. (PDISPATCHER_CONTEXT): Define as void * on 32 bit. Define as pointer to _DISPATCHER_CONTEXT on 64 bit. (class exception): Define separately for 32 and 64 bit. (exception::myfault): Add handler for myfault SEH handling on 64 bit. (exception::exception): Fix mangled method name to account for change in type of last parameter. (exception::install_myfault_handler): Remove. * exceptions.cc (exception::myfault_handle): Remove. (exception::myfault): New SEH handler for 64 bit. * gendef (_sigbe): Set tls_pathbuf counters to 0 explicitely when returning to the caller. * ntdll.h: Move a comment to a better place. (struct _SCOPE_TABLE): Define on 64 bit. * thread.cc (verifyable_object_isvalid): Remove gcc 4.7 workaround. * tls_pbuf.cc (tls_pbuf): Fix to accommodate new place of pathbufs. (tls_pathbuf::destroy): Change type of loop variables to uint32_t. * tls_pbuf.h (class tmp_pathbuf): Change type of buffer counters to uint32_t. Accommodate new place of pathbufs. * tlsoffsets.h: Regenerate. * tlsoffsets64.h: Regenerate.
This commit is contained in:
@@ -60,167 +60,171 @@ read_ea (HANDLE hdl, path_conv &pc, const char *name, char *value, size_t size)
|
||||
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)
|
||||
__try
|
||||
{
|
||||
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;
|
||||
}
|
||||
pc.get_object_attr (attr, sec_none_nih);
|
||||
|
||||
fea = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
|
||||
debug_printf ("read_ea (%S, %s, %p, %lu)",
|
||||
attr.ObjectName, name, value, size);
|
||||
|
||||
if (name)
|
||||
{
|
||||
size_t nlen;
|
||||
|
||||
/* For compatibility with Linux, we only allow user xattrs and
|
||||
return ENOTSUP otherwise. */
|
||||
if (ascii_strncasematch (name, "user.", 5))
|
||||
name += 5;
|
||||
else
|
||||
/* 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)
|
||||
{
|
||||
set_errno (ENOTSUP);
|
||||
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))
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case STATUS_NO_EAS_ON_FILE:
|
||||
ret = 0;
|
||||
break;
|
||||
case STATUS_INVALID_DEVICE_REQUEST:
|
||||
set_errno (ENOTSUP);
|
||||
break;
|
||||
case STATUS_NOT_FOUND:
|
||||
/* STATUS_NOT_FOUND is returned when calling NtQueryEaFile on NFS.
|
||||
In theory this should mean that the file just has no EAs, but in
|
||||
fact NFS doesn't support EAs, other than the EAs which are used
|
||||
for NFS requests. We're playing safe and convert STATUS_NOT_FOUND
|
||||
to ENOATTR, unless we're on NFS, where we convert it to ENOTSUP. */
|
||||
set_errno (pc.fs_is_nfs () ? ENOTSUP : ENOATTR);
|
||||
break;
|
||||
case STATUS_NONEXISTENT_EA_ENTRY:
|
||||
/* Actually STATUS_NONEXISTENT_EA_ENTRY is either never generated, or
|
||||
it was only generated in some old and long forgotton NT version.
|
||||
See below. For safty reasons, we handle it here, nevertheless. */
|
||||
set_errno (ENOATTR);
|
||||
break;
|
||||
default:
|
||||
__seterrno_from_nt_status (status);
|
||||
break;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
if (name)
|
||||
{
|
||||
/* Another weird behaviour of NtQueryEaFile. 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
|
||||
NtQueryEaFile 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)
|
||||
status = NtOpenFile (&h, READ_CONTROL | FILE_READ_EA, &attr, &io,
|
||||
FILE_SHARE_VALID_FLAGS,
|
||||
FILE_OPEN_FOR_BACKUP_INTENT);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
set_errno (ERANGE);
|
||||
goto out;
|
||||
__seterrno_from_nt_status (status);
|
||||
__leave;
|
||||
}
|
||||
memcpy (value, fea->EaName + fea->EaNameLength + 1,
|
||||
fea->EaValueLength);
|
||||
hdl = NULL;
|
||||
}
|
||||
ret = fea->EaValueLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0;
|
||||
do
|
||||
|
||||
fea = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
|
||||
|
||||
if (name)
|
||||
{
|
||||
fea->EaNameLength += 5; /* "user." */
|
||||
size_t nlen;
|
||||
|
||||
/* For compatibility with Linux, we only allow user xattrs and
|
||||
return ENOTSUP otherwise. */
|
||||
if (ascii_strncasematch (name, "user.", 5))
|
||||
name += 5;
|
||||
else
|
||||
{
|
||||
set_errno (ENOTSUP);
|
||||
__leave;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case STATUS_NO_EAS_ON_FILE:
|
||||
ret = 0;
|
||||
break;
|
||||
case STATUS_INVALID_DEVICE_REQUEST:
|
||||
set_errno (ENOTSUP);
|
||||
break;
|
||||
case STATUS_NOT_FOUND:
|
||||
/* STATUS_NOT_FOUND is returned when calling NtQueryEaFile on NFS.
|
||||
In theory this should mean that the file just has no EAs, but
|
||||
in fact NFS doesn't support EAs, other than the EAs which are
|
||||
used for NFS requests. We're playing safe and convert
|
||||
STATUS_NOT_FOUND to ENOATTR, unless we're on NFS, where we
|
||||
convert it to ENOTSUP. */
|
||||
set_errno (pc.fs_is_nfs () ? ENOTSUP : ENOATTR);
|
||||
break;
|
||||
case STATUS_NONEXISTENT_EA_ENTRY:
|
||||
/* Actually STATUS_NONEXISTENT_EA_ENTRY is either never generated,
|
||||
or it was only generated in some old and long forgotton NT
|
||||
version. See below. For safty reasons, we handle it here,
|
||||
nevertheless. */
|
||||
set_errno (ENOATTR);
|
||||
break;
|
||||
default:
|
||||
__seterrno_from_nt_status (status);
|
||||
break;
|
||||
}
|
||||
__leave;
|
||||
}
|
||||
if (name)
|
||||
{
|
||||
/* Another weird behaviour of NtQueryEaFile. 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
|
||||
NtQueryEaFile returns success with the entry's EaValueLength
|
||||
set to 0. */
|
||||
if (!fea->EaValueLength)
|
||||
{
|
||||
set_errno (ENOATTR);
|
||||
__leave;
|
||||
}
|
||||
if (size > 0)
|
||||
{
|
||||
if ((size_t) ret + fea->EaNameLength + 1 > size)
|
||||
if (size < fea->EaValueLength)
|
||||
{
|
||||
set_errno (ERANGE);
|
||||
goto out;
|
||||
__leave;
|
||||
}
|
||||
/* 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;
|
||||
memcpy (value, fea->EaName + fea->EaNameLength + 1,
|
||||
fea->EaValueLength);
|
||||
}
|
||||
else
|
||||
ret += fea->EaNameLength + 1;
|
||||
strcpy (lastname, fea->EaName);
|
||||
status = NtQueryEaFile (h, &io, fea, EA_BUFSIZ, TRUE, NULL, 0,
|
||||
NULL, FALSE);
|
||||
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);
|
||||
__leave;
|
||||
}
|
||||
/* 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);
|
||||
}
|
||||
while (NT_SUCCESS (status) && strcmp (lastname, fea->EaName) != 0);
|
||||
}
|
||||
|
||||
out:
|
||||
__except (EFAULT) {}
|
||||
__endtry
|
||||
if (!hdl)
|
||||
CloseHandle (h);
|
||||
debug_printf ("%d = read_ea(%S, %s, %p, %lu)",
|
||||
@@ -241,120 +245,121 @@ write_ea (HANDLE hdl, path_conv &pc, const char *name, const char *value,
|
||||
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)
|
||||
__try
|
||||
{
|
||||
status = NtOpenFile (&h, READ_CONTROL | FILE_WRITE_EA, &attr, &io,
|
||||
FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
|
||||
if (!NT_SUCCESS (status))
|
||||
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)
|
||||
{
|
||||
__seterrno_from_nt_status (status);
|
||||
goto out;
|
||||
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);
|
||||
__leave;
|
||||
}
|
||||
hdl = NULL;
|
||||
}
|
||||
hdl = NULL;
|
||||
}
|
||||
|
||||
/* For compatibility with Linux, we only allow user xattrs and
|
||||
return ENOTSUP otherwise. */
|
||||
if (!ascii_strncasematch (name, "user.", 5))
|
||||
{
|
||||
set_errno (ENOTSUP);
|
||||
goto out;
|
||||
}
|
||||
/* For compatibility with Linux, we only allow user xattrs and
|
||||
return ENOTSUP otherwise. */
|
||||
if (!ascii_strncasematch (name, "user.", 5))
|
||||
{
|
||||
set_errno (ENOTSUP);
|
||||
__leave;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* removexattr is supposed to fail with ENOATTR if the requested EA is
|
||||
not available. This is equivalent to XATTR_REPLACE for setxattr. */
|
||||
if (!value)
|
||||
flags = XATTR_REPLACE;
|
||||
|
||||
if (flags)
|
||||
{
|
||||
if (flags != XATTR_CREATE && flags != XATTR_REPLACE)
|
||||
if (flags)
|
||||
{
|
||||
if (flags != XATTR_CREATE && flags != XATTR_REPLACE)
|
||||
{
|
||||
set_errno (EINVAL);
|
||||
__leave;
|
||||
}
|
||||
ssize_t rret = read_ea (hdl, pc, name, NULL, 0);
|
||||
if (flags == XATTR_CREATE && rret > 0)
|
||||
{
|
||||
set_errno (EEXIST);
|
||||
__leave;
|
||||
}
|
||||
if (flags == XATTR_REPLACE && rret < 0)
|
||||
__leave;
|
||||
}
|
||||
|
||||
/* Skip "user." prefix. */
|
||||
name += 5;
|
||||
|
||||
if ((nlen = strlen (name)) >= MAX_EA_NAME_LEN)
|
||||
{
|
||||
set_errno (EINVAL);
|
||||
goto out;
|
||||
__leave;
|
||||
}
|
||||
ssize_t rret = read_ea (hdl, pc, name, NULL, 0);
|
||||
if (flags == XATTR_CREATE && rret > 0)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
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;
|
||||
}
|
||||
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))
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case STATUS_EA_TOO_LARGE:
|
||||
/* STATUS_EA_TOO_LARGE has a matching Win32 error ERROR_EA_TABLE_FULL.
|
||||
For some unknown reason RtlNtStatusToDosError does not translate
|
||||
STATUS_EA_TOO_LARGE to ERROR_EA_TABLE_FULL, but instead 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. */
|
||||
set_errno (ENOSPC);
|
||||
break;
|
||||
case STATUS_INVALID_DEVICE_REQUEST:
|
||||
set_errno (ENOTSUP);
|
||||
break;
|
||||
default:
|
||||
__seterrno_from_nt_status (status);
|
||||
break;
|
||||
switch (status)
|
||||
{
|
||||
case STATUS_EA_TOO_LARGE:
|
||||
/* STATUS_EA_TOO_LARGE has a matching Win32 error code
|
||||
ERROR_EA_TABLE_FULL. For some reason RtlNtStatusToDosError
|
||||
does not translate STATUS_EA_TOO_LARGE to ERROR_EA_TABLE_FULL,
|
||||
but instead 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. */
|
||||
set_errno (ENOSPC);
|
||||
break;
|
||||
case STATUS_INVALID_DEVICE_REQUEST:
|
||||
set_errno (ENOTSUP);
|
||||
break;
|
||||
default:
|
||||
__seterrno_from_nt_status (status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
__except (EFAULT) {}
|
||||
__endtry
|
||||
if (!hdl)
|
||||
CloseHandle (h);
|
||||
debug_printf ("%d = write_ea(%S, %s, %p, %lu, %d)",
|
||||
|
Reference in New Issue
Block a user