based on coreutils-8.32
This commit is contained in:
0
lib/.dirstamp
Normal file
0
lib/.dirstamp
Normal file
43
lib/_Noreturn.h
Normal file
43
lib/_Noreturn.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* A C macro for declaring that a function does not return.
|
||||
Copyright (C) 2011-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _Noreturn
|
||||
# if (defined __cplusplus \
|
||||
&& ((201103 <= __cplusplus && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) \
|
||||
|| (defined _MSC_VER && 1900 <= _MSC_VER)) \
|
||||
&& 0)
|
||||
/* [[noreturn]] is not practically usable, because with it the syntax
|
||||
extern _Noreturn void func (...);
|
||||
would not be valid; such a declaration would only be valid with 'extern'
|
||||
and '_Noreturn' swapped, or without the 'extern' keyword. However, some
|
||||
AIX system header files and several gnulib header files use precisely
|
||||
this syntax with 'extern'. */
|
||||
# define _Noreturn [[noreturn]]
|
||||
# elif ((!defined __cplusplus || defined __clang__) \
|
||||
&& (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \
|
||||
|| 4 < __GNUC__ + (7 <= __GNUC_MINOR__) \
|
||||
|| (defined __apple_build_version__ \
|
||||
? 6000000 <= __apple_build_version__ \
|
||||
: 3 < __clang_major__ + (5 <= __clang_minor__))))
|
||||
/* _Noreturn works as-is. */
|
||||
# elif 2 < __GNUC__ + (8 <= __GNUC_MINOR__) || 0x5110 <= __SUNPRO_C
|
||||
# define _Noreturn __attribute__ ((__noreturn__))
|
||||
# elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0)
|
||||
# define _Noreturn __declspec (noreturn)
|
||||
# else
|
||||
# define _Noreturn
|
||||
# endif
|
||||
#endif
|
||||
52
lib/acl-errno-valid.c
Normal file
52
lib/acl-errno-valid.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/* Test whether ACLs are well supported on this system.
|
||||
|
||||
Copyright 2013-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Written by Paul Eggert. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <acl.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
/* Return true if errno value ERRNUM indicates that ACLs are well
|
||||
supported on this system. ERRNUM should be an errno value obtained
|
||||
after an ACL-related system call fails. */
|
||||
bool
|
||||
acl_errno_valid (int errnum)
|
||||
{
|
||||
/* Recognize some common errors such as from an NFS mount that does
|
||||
not support ACLs, even when local drives do. */
|
||||
switch (errnum)
|
||||
{
|
||||
case EBUSY: return false;
|
||||
case EINVAL: return false;
|
||||
#if defined __APPLE__ && defined __MACH__
|
||||
case ENOENT: return false;
|
||||
#endif
|
||||
case ENOSYS: return false;
|
||||
|
||||
#if defined ENOTSUP && ENOTSUP != EOPNOTSUPP
|
||||
# if ENOTSUP != ENOSYS /* Needed for the MS-Windows port of GNU Emacs. */
|
||||
case ENOTSUP: return false;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
case EOPNOTSUPP: return false;
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
507
lib/acl-internal.c
Normal file
507
lib/acl-internal.c
Normal file
@@ -0,0 +1,507 @@
|
||||
/* Test whether a file has a nontrivial ACL. -*- coding: utf-8 -*-
|
||||
|
||||
Copyright (C) 2002-2003, 2005-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "acl.h"
|
||||
|
||||
#include "acl-internal.h"
|
||||
|
||||
#if USE_ACL && HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
|
||||
|
||||
# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
|
||||
|
||||
/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
|
||||
Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial. */
|
||||
int
|
||||
acl_extended_nontrivial (acl_t acl)
|
||||
{
|
||||
/* acl is non-trivial if it is non-empty. */
|
||||
return (acl_entries (acl) > 0);
|
||||
}
|
||||
|
||||
# else /* Linux, FreeBSD, IRIX, Tru64, Cygwin >= 2.5 */
|
||||
|
||||
/* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS.
|
||||
Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
|
||||
Return -1 and set errno upon failure to determine it. */
|
||||
int
|
||||
acl_access_nontrivial (acl_t acl)
|
||||
{
|
||||
/* acl is non-trivial if it has some entries other than for "user::",
|
||||
"group::", and "other::". Normally these three should be present
|
||||
at least, allowing us to write
|
||||
return (3 < acl_entries (acl));
|
||||
but the following code is more robust. */
|
||||
# if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD, Cygwin >= 2.5 */
|
||||
|
||||
acl_entry_t ace;
|
||||
int got_one;
|
||||
|
||||
for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
|
||||
got_one > 0;
|
||||
got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
|
||||
{
|
||||
acl_tag_t tag;
|
||||
if (acl_get_tag_type (ace, &tag) < 0)
|
||||
return -1;
|
||||
if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
|
||||
return 1;
|
||||
}
|
||||
return got_one;
|
||||
|
||||
# elif HAVE_ACL_TO_SHORT_TEXT /* IRIX */
|
||||
/* Don't use acl_get_entry: it is undocumented. */
|
||||
|
||||
int count = acl->acl_cnt;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
acl_entry_t ace = &acl->acl_entry[i];
|
||||
acl_tag_t tag = ace->ae_tag;
|
||||
|
||||
if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ
|
||||
|| tag == ACL_OTHER_OBJ))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
# elif HAVE_ACL_FREE_TEXT /* Tru64 */
|
||||
/* Don't use acl_get_entry: it takes only one argument and does not work. */
|
||||
|
||||
int count = acl->acl_num;
|
||||
acl_entry_t ace;
|
||||
|
||||
for (ace = acl->acl_first; count > 0; ace = ace->next, count--)
|
||||
{
|
||||
acl_tag_t tag;
|
||||
acl_perm_t perm;
|
||||
|
||||
tag = ace->entry->acl_type;
|
||||
if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
|
||||
return 1;
|
||||
|
||||
perm = ace->entry->acl_perm;
|
||||
/* On Tru64, perm can also contain non-standard bits such as
|
||||
PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ... */
|
||||
if ((perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)) != 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
# else
|
||||
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
int
|
||||
acl_default_nontrivial (acl_t acl)
|
||||
{
|
||||
/* acl is non-trivial if it is non-empty. */
|
||||
return (acl_entries (acl) > 0);
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
#elif USE_ACL && HAVE_FACL && defined GETACL /* Solaris, Cygwin < 2.5, not HP-UX */
|
||||
|
||||
/* Test an ACL retrieved with GETACL.
|
||||
Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
acl_nontrivial (int count, aclent_t *entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
aclent_t *ace = &entries[i];
|
||||
|
||||
/* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
|
||||
If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
|
||||
We don't need to check ace->a_id in these cases. */
|
||||
if (!(ace->a_type == USER_OBJ
|
||||
|| ace->a_type == GROUP_OBJ
|
||||
|| ace->a_type == OTHER_OBJ
|
||||
/* Note: Cygwin does not return a CLASS_OBJ ("mask:") entry
|
||||
sometimes. */
|
||||
|| ace->a_type == CLASS_OBJ))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
# ifdef ACE_GETACL
|
||||
|
||||
/* A shortcut for a bitmask. */
|
||||
# define NEW_ACE_WRITEA_DATA (NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA)
|
||||
|
||||
/* Test an ACL retrieved with ACE_GETACL.
|
||||
Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
acl_ace_nontrivial (int count, ace_t *entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* The flags in the ace_t structure changed in a binary incompatible way
|
||||
when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
|
||||
How to distinguish the two conventions at runtime?
|
||||
In the old convention, usually three ACEs have a_flags = ACE_OWNER /
|
||||
ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400. In the new
|
||||
convention, these values are not used. */
|
||||
int old_convention = 0;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER))
|
||||
{
|
||||
old_convention = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (old_convention)
|
||||
/* Running on Solaris 10. */
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
ace_t *ace = &entries[i];
|
||||
|
||||
/* Note:
|
||||
If ace->a_flags = ACE_OWNER, ace->a_who is the st_uid from stat().
|
||||
If ace->a_flags = ACE_GROUP, ace->a_who is the st_gid from stat().
|
||||
We don't need to check ace->a_who in these cases. */
|
||||
if (!(ace->a_type == OLD_ALLOW
|
||||
&& (ace->a_flags == OLD_ACE_OWNER
|
||||
|| ace->a_flags == OLD_ACE_GROUP
|
||||
|| ace->a_flags == OLD_ACE_OTHER)))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Running on Solaris 10 (newer version) or Solaris 11. */
|
||||
unsigned int access_masks[6] =
|
||||
{
|
||||
0, /* owner@ deny */
|
||||
0, /* owner@ allow */
|
||||
0, /* group@ deny */
|
||||
0, /* group@ allow */
|
||||
0, /* everyone@ deny */
|
||||
0 /* everyone@ allow */
|
||||
};
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
ace_t *ace = &entries[i];
|
||||
unsigned int index1;
|
||||
unsigned int index2;
|
||||
|
||||
if (ace->a_type == NEW_ACE_ACCESS_ALLOWED_ACE_TYPE)
|
||||
index1 = 1;
|
||||
else if (ace->a_type == NEW_ACE_ACCESS_DENIED_ACE_TYPE)
|
||||
index1 = 0;
|
||||
else
|
||||
return 1;
|
||||
|
||||
if (ace->a_flags == NEW_ACE_OWNER)
|
||||
index2 = 0;
|
||||
else if (ace->a_flags == (NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP))
|
||||
index2 = 2;
|
||||
else if (ace->a_flags == NEW_ACE_EVERYONE)
|
||||
index2 = 4;
|
||||
else
|
||||
return 1;
|
||||
|
||||
access_masks[index1 + index2] |= ace->a_access_mask;
|
||||
}
|
||||
|
||||
/* The same bit shouldn't be both allowed and denied. */
|
||||
if (access_masks[0] & access_masks[1])
|
||||
return 1;
|
||||
if (access_masks[2] & access_masks[3])
|
||||
return 1;
|
||||
if (access_masks[4] & access_masks[5])
|
||||
return 1;
|
||||
|
||||
/* Check minimum masks. */
|
||||
if ((NEW_ACE_WRITE_NAMED_ATTRS
|
||||
| NEW_ACE_WRITE_ATTRIBUTES
|
||||
| NEW_ACE_WRITE_ACL
|
||||
| NEW_ACE_WRITE_OWNER)
|
||||
& ~ access_masks[1])
|
||||
return 1;
|
||||
access_masks[1] &= ~(NEW_ACE_WRITE_NAMED_ATTRS
|
||||
| NEW_ACE_WRITE_ATTRIBUTES
|
||||
| NEW_ACE_WRITE_ACL
|
||||
| NEW_ACE_WRITE_OWNER);
|
||||
if ((NEW_ACE_READ_NAMED_ATTRS
|
||||
| NEW_ACE_READ_ATTRIBUTES
|
||||
| NEW_ACE_READ_ACL
|
||||
| NEW_ACE_SYNCHRONIZE)
|
||||
& ~ access_masks[5])
|
||||
return 1;
|
||||
access_masks[5] &= ~(NEW_ACE_READ_NAMED_ATTRS
|
||||
| NEW_ACE_READ_ATTRIBUTES
|
||||
| NEW_ACE_READ_ACL
|
||||
| NEW_ACE_SYNCHRONIZE);
|
||||
|
||||
/* Check the allowed or denied bits. */
|
||||
switch ((access_masks[0] | access_masks[1])
|
||||
& ~(NEW_ACE_READ_NAMED_ATTRS
|
||||
| NEW_ACE_READ_ATTRIBUTES
|
||||
| NEW_ACE_READ_ACL
|
||||
| NEW_ACE_SYNCHRONIZE))
|
||||
{
|
||||
case 0:
|
||||
case NEW_ACE_READ_DATA:
|
||||
case NEW_ACE_WRITEA_DATA:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
|
||||
case NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
switch ((access_masks[2] | access_masks[3])
|
||||
& ~(NEW_ACE_READ_NAMED_ATTRS
|
||||
| NEW_ACE_READ_ATTRIBUTES
|
||||
| NEW_ACE_READ_ACL
|
||||
| NEW_ACE_SYNCHRONIZE))
|
||||
{
|
||||
case 0:
|
||||
case NEW_ACE_READ_DATA:
|
||||
case NEW_ACE_WRITEA_DATA:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
|
||||
case NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
switch ((access_masks[4] | access_masks[5])
|
||||
& ~(NEW_ACE_WRITE_NAMED_ATTRS
|
||||
| NEW_ACE_WRITE_ATTRIBUTES
|
||||
| NEW_ACE_WRITE_ACL
|
||||
| NEW_ACE_WRITE_OWNER))
|
||||
{
|
||||
case 0:
|
||||
case NEW_ACE_READ_DATA:
|
||||
case NEW_ACE_WRITEA_DATA:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
|
||||
case NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||||
case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check that the NEW_ACE_WRITE_DATA and NEW_ACE_APPEND_DATA bits are
|
||||
either both allowed or both denied. */
|
||||
if (((access_masks[0] & NEW_ACE_WRITE_DATA) != 0)
|
||||
!= ((access_masks[0] & NEW_ACE_APPEND_DATA) != 0))
|
||||
return 1;
|
||||
if (((access_masks[2] & NEW_ACE_WRITE_DATA) != 0)
|
||||
!= ((access_masks[2] & NEW_ACE_APPEND_DATA) != 0))
|
||||
return 1;
|
||||
if (((access_masks[4] & NEW_ACE_WRITE_DATA) != 0)
|
||||
!= ((access_masks[4] & NEW_ACE_APPEND_DATA) != 0))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
#elif USE_ACL && HAVE_GETACL /* HP-UX */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
acl_nontrivial (int count, struct acl_entry *entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (count > 3)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
struct acl_entry *ace = &entries[i];
|
||||
|
||||
if (ace->uid != ACL_NSUSER && ace->gid != ACL_NSGROUP)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
# if HAVE_ACLV_H /* HP-UX >= 11.11 */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
aclv_nontrivial (int count, struct acl *entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
struct acl *ace = &entries[i];
|
||||
|
||||
/* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
|
||||
If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
|
||||
We don't need to check ace->a_id in these cases. */
|
||||
if (!(ace->a_type == USER_OBJ /* no need to check ace->a_id here */
|
||||
|| ace->a_type == GROUP_OBJ /* no need to check ace->a_id here */
|
||||
|| ace->a_type == CLASS_OBJ
|
||||
|| ace->a_type == OTHER_OBJ))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
#elif USE_ACL && (HAVE_ACLX_GET || HAVE_STATACL) /* AIX */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
acl_nontrivial (struct acl *a)
|
||||
{
|
||||
/* The normal way to iterate through an ACL is like this:
|
||||
struct acl_entry *ace;
|
||||
for (ace = a->acl_ext; ace != acl_last (a); ace = acl_nxt (ace))
|
||||
{
|
||||
struct ace_id *aei;
|
||||
switch (ace->ace_type)
|
||||
{
|
||||
case ACC_PERMIT:
|
||||
case ACC_DENY:
|
||||
case ACC_SPECIFY:
|
||||
...;
|
||||
}
|
||||
for (aei = ace->ace_id; aei != id_last (ace); aei = id_nxt (aei))
|
||||
...
|
||||
}
|
||||
*/
|
||||
return (acl_last (a) != a->acl_ext ? 1 : 0);
|
||||
}
|
||||
|
||||
# if HAVE_ACLX_GET && defined ACL_AIX_WIP /* newer AIX */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
acl_nfs4_nontrivial (nfs4_acl_int_t *a)
|
||||
{
|
||||
# if 1 /* let's try this first */
|
||||
return (a->aclEntryN > 0 ? 1 : 0);
|
||||
# else
|
||||
int count = a->aclEntryN;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
nfs4_ace_int_t *ace = &a->aclEntry[i];
|
||||
|
||||
if (!((ace->flags & ACE4_ID_SPECIAL) != 0
|
||||
&& (ace->aceWho.special_whoid == ACE4_WHO_OWNER
|
||||
|| ace->aceWho.special_whoid == ACE4_WHO_GROUP
|
||||
|| ace->aceWho.special_whoid == ACE4_WHO_EVERYONE)
|
||||
&& ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE
|
||||
&& ace->aceFlags == 0
|
||||
&& (ace->aceMask & ~(ACE4_READ_DATA | ACE4_LIST_DIRECTORY
|
||||
| ACE4_WRITE_DATA | ACE4_ADD_FILE
|
||||
| ACE4_EXECUTE)) == 0))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
# endif
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
|
||||
|
||||
/* Test an ACL retrieved with ACL_GET.
|
||||
Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
int
|
||||
acl_nontrivial (int count, struct acl *entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
struct acl *ace = &entries[i];
|
||||
|
||||
/* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat().
|
||||
If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat().
|
||||
We don't need to check ace->a_id in these cases. */
|
||||
if (!(ace->a_type == USER_OBJ /* no need to check ace->a_id here */
|
||||
|| ace->a_type == GROUP_OBJ /* no need to check ace->a_id here */
|
||||
|| ace->a_type == CLASS_OBJ
|
||||
|| ace->a_type == OTHER_OBJ))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
free_permission_context (struct permission_context *ctx)
|
||||
{
|
||||
#if USE_ACL
|
||||
# if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
|
||||
if (ctx->acl)
|
||||
acl_free (ctx->acl);
|
||||
# if !HAVE_ACL_TYPE_EXTENDED
|
||||
if (ctx->default_acl)
|
||||
acl_free (ctx->default_acl);
|
||||
# endif
|
||||
|
||||
# elif defined GETACL /* Solaris, Cygwin < 2.5 */
|
||||
free (ctx->entries);
|
||||
# ifdef ACE_GETACL
|
||||
free (ctx->ace_entries);
|
||||
# endif
|
||||
|
||||
# elif HAVE_GETACL /* HP-UX */
|
||||
|
||||
# if HAVE_ACLV_H
|
||||
# endif
|
||||
|
||||
# elif HAVE_STATACL /* older AIX */
|
||||
|
||||
# elif HAVE_ACLSORT /* NonStop Kernel */
|
||||
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
302
lib/acl-internal.h
Normal file
302
lib/acl-internal.h
Normal file
@@ -0,0 +1,302 @@
|
||||
/* Internal implementation of access control lists. -*- coding: utf-8 -*-
|
||||
|
||||
Copyright (C) 2002-2003, 2005-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
|
||||
|
||||
#include "acl.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* All systems define the ACL related API in <sys/acl.h>. */
|
||||
#if HAVE_SYS_ACL_H
|
||||
# include <sys/acl.h>
|
||||
#endif
|
||||
#if defined HAVE_FACL && ! defined GETACLCNT && defined ACL_CNT
|
||||
# define GETACLCNT ACL_CNT
|
||||
#endif
|
||||
|
||||
/* On Linux and Cygwin >= 2.5, additional ACL related API is available in
|
||||
<acl/libacl.h>. */
|
||||
#ifdef HAVE_ACL_LIBACL_H
|
||||
# include <acl/libacl.h>
|
||||
#endif
|
||||
|
||||
/* On HP-UX >= 11.11, additional ACL API is available in <aclv.h>. */
|
||||
#if HAVE_ACLV_H
|
||||
# include <sys/types.h>
|
||||
# include <aclv.h>
|
||||
/* HP-UX 11.11 lacks these declarations. */
|
||||
extern int acl (char *, int, int, struct acl *);
|
||||
extern int aclsort (int, int, struct acl *);
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <limits.h>
|
||||
#ifndef MIN
|
||||
# define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
# define SIZE_MAX ((size_t) -1)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FCHMOD
|
||||
# define HAVE_FCHMOD false
|
||||
# define fchmod(fd, mode) (-1)
|
||||
#endif
|
||||
|
||||
#ifndef _GL_INLINE_HEADER_BEGIN
|
||||
#error "Please include config.h first."
|
||||
#endif
|
||||
_GL_INLINE_HEADER_BEGIN
|
||||
#ifndef ACL_INTERNAL_INLINE
|
||||
# define ACL_INTERNAL_INLINE _GL_INLINE
|
||||
#endif
|
||||
|
||||
#if USE_ACL
|
||||
|
||||
# if HAVE_ACL_GET_FILE
|
||||
/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
|
||||
/* Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
|
||||
|
||||
# ifndef MIN_ACL_ENTRIES
|
||||
# define MIN_ACL_ENTRIES 4
|
||||
# endif
|
||||
|
||||
/* POSIX 1003.1e (draft 17) */
|
||||
# ifdef HAVE_ACL_GET_FD
|
||||
/* Most platforms have a 1-argument acl_get_fd, only OSF/1 has a 2-argument
|
||||
macro(!). */
|
||||
# if HAVE_ACL_FREE_TEXT /* OSF/1 */
|
||||
ACL_INTERNAL_INLINE acl_t
|
||||
rpl_acl_get_fd (int fd)
|
||||
{
|
||||
return acl_get_fd (fd, ACL_TYPE_ACCESS);
|
||||
}
|
||||
# undef acl_get_fd
|
||||
# define acl_get_fd rpl_acl_get_fd
|
||||
# endif
|
||||
# else
|
||||
# define HAVE_ACL_GET_FD false
|
||||
# undef acl_get_fd
|
||||
# define acl_get_fd(fd) (NULL)
|
||||
# endif
|
||||
|
||||
/* POSIX 1003.1e (draft 17) */
|
||||
# ifdef HAVE_ACL_SET_FD
|
||||
/* Most platforms have a 2-argument acl_set_fd, only OSF/1 has a 3-argument
|
||||
macro(!). */
|
||||
# if HAVE_ACL_FREE_TEXT /* OSF/1 */
|
||||
ACL_INTERNAL_INLINE int
|
||||
rpl_acl_set_fd (int fd, acl_t acl)
|
||||
{
|
||||
return acl_set_fd (fd, ACL_TYPE_ACCESS, acl);
|
||||
}
|
||||
# undef acl_set_fd
|
||||
# define acl_set_fd rpl_acl_set_fd
|
||||
# endif
|
||||
# else
|
||||
# define HAVE_ACL_SET_FD false
|
||||
# undef acl_set_fd
|
||||
# define acl_set_fd(fd, acl) (-1)
|
||||
# endif
|
||||
|
||||
/* POSIX 1003.1e (draft 13) */
|
||||
# if ! HAVE_ACL_FREE_TEXT
|
||||
# define acl_free_text(buf) acl_free (buf)
|
||||
# endif
|
||||
|
||||
/* Linux-specific */
|
||||
/* Cygwin >= 2.5 implements this function, but it returns 1 for all
|
||||
directories, thus is unusable. */
|
||||
# if !defined HAVE_ACL_EXTENDED_FILE || defined __CYGWIN__
|
||||
# undef HAVE_ACL_EXTENDED_FILE
|
||||
# define HAVE_ACL_EXTENDED_FILE false
|
||||
# define acl_extended_file(name) (-1)
|
||||
# endif
|
||||
|
||||
# if ! defined HAVE_ACL_FROM_MODE && ! defined HAVE_ACL_FROM_TEXT
|
||||
# define acl_from_mode (NULL)
|
||||
# endif
|
||||
|
||||
/* Set to 0 if a file's mode is stored independently from the ACL. */
|
||||
# if (HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP) || defined __sgi /* Mac OS X, IRIX */
|
||||
# define MODE_INSIDE_ACL 0
|
||||
# endif
|
||||
|
||||
/* Return the number of entries in ACL.
|
||||
Return -1 and set errno upon failure to determine it. */
|
||||
/* Define a replacement for acl_entries if needed. (Only Linux has it.) */
|
||||
# if !HAVE_ACL_ENTRIES
|
||||
# define acl_entries rpl_acl_entries
|
||||
extern int acl_entries (acl_t);
|
||||
# endif
|
||||
|
||||
# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
|
||||
/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
|
||||
Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial. */
|
||||
extern int acl_extended_nontrivial (acl_t);
|
||||
# else
|
||||
/* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS.
|
||||
Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
|
||||
Return -1 and set errno upon failure to determine it. */
|
||||
extern int acl_access_nontrivial (acl_t);
|
||||
|
||||
/* ACL is an ACL, from a file, stored as type ACL_TYPE_DEFAULT.
|
||||
Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
|
||||
Return -1 and set errno upon failure to determine it. */
|
||||
extern int acl_default_nontrivial (acl_t);
|
||||
# endif
|
||||
|
||||
# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin < 2.5, not HP-UX */
|
||||
|
||||
/* Set to 0 if a file's mode is stored independently from the ACL. */
|
||||
# if defined __CYGWIN__ /* Cygwin */
|
||||
# define MODE_INSIDE_ACL 0
|
||||
# endif
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
extern int acl_nontrivial (int count, aclent_t *entries) _GL_ATTRIBUTE_PURE;
|
||||
|
||||
# ifdef ACE_GETACL /* Solaris 10 */
|
||||
|
||||
/* Test an ACL retrieved with ACE_GETACL.
|
||||
Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
extern int acl_ace_nontrivial (int count, ace_t *entries) _GL_ATTRIBUTE_PURE;
|
||||
|
||||
/* Definitions for when the built executable is executed on Solaris 10
|
||||
(newer version) or Solaris 11. */
|
||||
/* For a_type. */
|
||||
# define OLD_ALLOW 0
|
||||
# define OLD_DENY 1
|
||||
# define NEW_ACE_ACCESS_ALLOWED_ACE_TYPE 0 /* replaces ALLOW */
|
||||
# define NEW_ACE_ACCESS_DENIED_ACE_TYPE 1 /* replaces DENY */
|
||||
/* For a_flags. */
|
||||
# define OLD_ACE_OWNER 0x0100
|
||||
# define OLD_ACE_GROUP 0x0200
|
||||
# define OLD_ACE_OTHER 0x0400
|
||||
# define NEW_ACE_OWNER 0x1000
|
||||
# define NEW_ACE_GROUP 0x2000
|
||||
# define NEW_ACE_IDENTIFIER_GROUP 0x0040
|
||||
# define NEW_ACE_EVERYONE 0x4000
|
||||
/* For a_access_mask. */
|
||||
# define NEW_ACE_READ_DATA 0x001 /* corresponds to 'r' */
|
||||
# define NEW_ACE_WRITE_DATA 0x002 /* corresponds to 'w' */
|
||||
# define NEW_ACE_APPEND_DATA 0x004
|
||||
# define NEW_ACE_READ_NAMED_ATTRS 0x008
|
||||
# define NEW_ACE_WRITE_NAMED_ATTRS 0x010
|
||||
# define NEW_ACE_EXECUTE 0x020
|
||||
# define NEW_ACE_DELETE_CHILD 0x040
|
||||
# define NEW_ACE_READ_ATTRIBUTES 0x080
|
||||
# define NEW_ACE_WRITE_ATTRIBUTES 0x100
|
||||
# define NEW_ACE_DELETE 0x10000
|
||||
# define NEW_ACE_READ_ACL 0x20000
|
||||
# define NEW_ACE_WRITE_ACL 0x40000
|
||||
# define NEW_ACE_WRITE_OWNER 0x80000
|
||||
# define NEW_ACE_SYNCHRONIZE 0x100000
|
||||
|
||||
# endif
|
||||
|
||||
# elif HAVE_GETACL /* HP-UX */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
extern int acl_nontrivial (int count, struct acl_entry *entries);
|
||||
|
||||
# if HAVE_ACLV_H /* HP-UX >= 11.11 */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
extern int aclv_nontrivial (int count, struct acl *entries);
|
||||
|
||||
# endif
|
||||
|
||||
# elif HAVE_ACLX_GET && 0 /* AIX */
|
||||
|
||||
/* TODO */
|
||||
|
||||
# elif HAVE_STATACL /* older AIX */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
extern int acl_nontrivial (struct acl *a);
|
||||
|
||||
# elif HAVE_ACLSORT /* NonStop Kernel */
|
||||
|
||||
/* Return 1 if the given ACL is non-trivial.
|
||||
Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||||
extern int acl_nontrivial (int count, struct acl *entries);
|
||||
|
||||
# endif
|
||||
|
||||
/* Set to 1 if a file's mode is implicit by the ACL. */
|
||||
# ifndef MODE_INSIDE_ACL
|
||||
# define MODE_INSIDE_ACL 1
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
struct permission_context {
|
||||
mode_t mode;
|
||||
#if USE_ACL
|
||||
# if HAVE_ACL_GET_FILE /* Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */
|
||||
acl_t acl;
|
||||
# if !HAVE_ACL_TYPE_EXTENDED
|
||||
acl_t default_acl;
|
||||
# endif
|
||||
bool acls_not_supported;
|
||||
|
||||
# elif defined GETACL /* Solaris, Cygwin < 2.5 */
|
||||
int count;
|
||||
aclent_t *entries;
|
||||
# ifdef ACE_GETACL
|
||||
int ace_count;
|
||||
ace_t *ace_entries;
|
||||
# endif
|
||||
|
||||
# elif HAVE_GETACL /* HP-UX */
|
||||
struct acl_entry entries[NACLENTRIES];
|
||||
int count;
|
||||
# if HAVE_ACLV_H
|
||||
struct acl aclv_entries[NACLVENTRIES];
|
||||
int aclv_count;
|
||||
# endif
|
||||
|
||||
# elif HAVE_STATACL /* older AIX */
|
||||
union { struct acl a; char room[4096]; } u;
|
||||
bool have_u;
|
||||
|
||||
# elif HAVE_ACLSORT /* NonStop Kernel */
|
||||
struct acl entries[NACLENTRIES];
|
||||
int count;
|
||||
|
||||
# endif
|
||||
#endif
|
||||
};
|
||||
|
||||
int get_permissions (const char *, int, mode_t, struct permission_context *);
|
||||
int set_permissions (struct permission_context *, const char *, int);
|
||||
void free_permission_context (struct permission_context *);
|
||||
|
||||
_GL_INLINE_HEADER_END
|
||||
35
lib/acl.h
Normal file
35
lib/acl.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* acl.c - access control lists
|
||||
|
||||
Copyright (C) 2002, 2008-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Written by Paul Eggert. */
|
||||
|
||||
#ifndef _GL_ACL_H
|
||||
#define _GL_ACL_H 1
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
bool acl_errno_valid (int) _GL_ATTRIBUTE_CONST;
|
||||
int file_has_acl (char const *, struct stat const *);
|
||||
int qset_acl (char const *, int, mode_t);
|
||||
int set_acl (char const *, int, mode_t);
|
||||
int qcopy_acl (char const *, int, char const *, int, mode_t);
|
||||
int copy_acl (char const *, int, char const *, int, mode_t);
|
||||
int chmod_or_fchmod (char const *, int, mode_t);
|
||||
|
||||
#endif
|
||||
75
lib/acl_entries.c
Normal file
75
lib/acl_entries.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/* Return the number of entries in an ACL.
|
||||
|
||||
Copyright (C) 2002-2003, 2005-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Written by Paul Eggert and Andreas Gruenbacher. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "acl-internal.h"
|
||||
|
||||
/* This file assumes POSIX-draft like ACLs
|
||||
(Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5). */
|
||||
|
||||
/* Return the number of entries in ACL.
|
||||
Return -1 and set errno upon failure to determine it. */
|
||||
|
||||
int
|
||||
acl_entries (acl_t acl)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (acl != NULL)
|
||||
{
|
||||
#if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD, Mac OS X, Cygwin >= 2.5 */
|
||||
# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
|
||||
/* acl_get_entry returns 0 when it successfully fetches an entry,
|
||||
and -1/EINVAL at the end. */
|
||||
acl_entry_t ace;
|
||||
int got_one;
|
||||
|
||||
for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
|
||||
got_one >= 0;
|
||||
got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
|
||||
count++;
|
||||
# else /* Linux, FreeBSD, Cygwin >= 2.5 */
|
||||
/* acl_get_entry returns 1 when it successfully fetches an entry,
|
||||
and 0 at the end. */
|
||||
acl_entry_t ace;
|
||||
int got_one;
|
||||
|
||||
for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
|
||||
got_one > 0;
|
||||
got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
|
||||
count++;
|
||||
if (got_one < 0)
|
||||
return -1;
|
||||
# endif
|
||||
#else /* IRIX, Tru64 */
|
||||
# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */
|
||||
/* Don't use acl_get_entry: it is undocumented. */
|
||||
count = acl->acl_cnt;
|
||||
# endif
|
||||
# if HAVE_ACL_FREE_TEXT /* Tru64 */
|
||||
/* Don't use acl_get_entry: it takes only one argument and does not
|
||||
work. */
|
||||
count = acl->acl_num;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
213
lib/af_alg.c
Normal file
213
lib/af_alg.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/* af_alg.c - Compute message digests from file streams and buffers.
|
||||
Copyright (C) 2018-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Matteo Croce <mcroce@redhat.com>, 2018. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "af_alg.h"
|
||||
|
||||
#if USE_LINUX_CRYPTO_API
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <linux/if_alg.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "sys-limits.h"
|
||||
|
||||
#define BLOCKSIZE 32768
|
||||
|
||||
/* Return a newly created socket for ALG.
|
||||
On error, return a negative error number. */
|
||||
static int
|
||||
alg_socket (char const *alg)
|
||||
{
|
||||
struct sockaddr_alg salg = {
|
||||
.salg_family = AF_ALG,
|
||||
.salg_type = "hash",
|
||||
};
|
||||
/* Copy alg into salg.salg_name, without calling strcpy nor strlen. */
|
||||
for (size_t i = 0; (salg.salg_name[i] = alg[i]) != '\0'; i++)
|
||||
if (i == sizeof salg.salg_name - 1)
|
||||
/* alg is too long. */
|
||||
return -EINVAL;
|
||||
|
||||
int cfd = socket (AF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
|
||||
if (cfd < 0)
|
||||
return -EAFNOSUPPORT;
|
||||
int ofd = (bind (cfd, (struct sockaddr *) &salg, sizeof salg) == 0
|
||||
? accept4 (cfd, NULL, 0, SOCK_CLOEXEC)
|
||||
: -1);
|
||||
close (cfd);
|
||||
return ofd < 0 ? -EAFNOSUPPORT : ofd;
|
||||
}
|
||||
|
||||
int
|
||||
afalg_buffer (const char *buffer, size_t len, const char *alg,
|
||||
void *resblock, ssize_t hashlen)
|
||||
{
|
||||
/* On Linux < 4.9, the value for an empty stream is wrong (all zeroes).
|
||||
See <https://patchwork.kernel.org/patch/9308641/>.
|
||||
This was not fixed properly until November 2016,
|
||||
see <https://patchwork.kernel.org/patch/9434741/>. */
|
||||
if (len == 0)
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
int ofd = alg_socket (alg);
|
||||
if (ofd < 0)
|
||||
return ofd;
|
||||
|
||||
int result;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ssize_t size = (len > BLOCKSIZE ? BLOCKSIZE : len);
|
||||
if (send (ofd, buffer, size, MSG_MORE) != size)
|
||||
{
|
||||
result = -EAFNOSUPPORT;
|
||||
break;
|
||||
}
|
||||
buffer += size;
|
||||
len -= size;
|
||||
if (len == 0)
|
||||
{
|
||||
result = read (ofd, resblock, hashlen) == hashlen ? 0 : -EAFNOSUPPORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close (ofd);
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
afalg_stream (FILE *stream, const char *alg,
|
||||
void *resblock, ssize_t hashlen)
|
||||
{
|
||||
int ofd = alg_socket (alg);
|
||||
if (ofd < 0)
|
||||
return ofd;
|
||||
|
||||
/* If STREAM's size is known and nonzero and not too large, attempt
|
||||
sendfile to pipe the data. The nonzero restriction avoids issues
|
||||
with /proc files that pretend to be empty, and lets the classic
|
||||
read-write loop work around an empty-input bug noted below. */
|
||||
int fd = fileno (stream);
|
||||
int result;
|
||||
struct stat st;
|
||||
off_t off = ftello (stream);
|
||||
if (0 <= off && fstat (fd, &st) == 0
|
||||
&& (S_ISREG (st.st_mode) || S_TYPEISSHM (&st) || S_TYPEISTMO (&st))
|
||||
&& off < st.st_size && st.st_size - off < SYS_BUFSIZE_MAX)
|
||||
{
|
||||
/* Make sure the offset of fileno (stream) reflects how many bytes
|
||||
have been read from stream before this function got invoked.
|
||||
Note: fflush on an input stream after ungetc does not work as expected
|
||||
on some platforms. Therefore this situation is not supported here. */
|
||||
if (fflush (stream))
|
||||
result = -EIO;
|
||||
else
|
||||
{
|
||||
off_t nbytes = st.st_size - off;
|
||||
if (sendfile (ofd, fd, &off, nbytes) == nbytes)
|
||||
{
|
||||
if (read (ofd, resblock, hashlen) == hashlen)
|
||||
{
|
||||
/* The input buffers of stream are no longer valid. */
|
||||
if (lseek (fd, off, SEEK_SET) != (off_t)-1)
|
||||
result = 0;
|
||||
else
|
||||
/* The file position of fd has not changed. */
|
||||
result = -EAFNOSUPPORT;
|
||||
}
|
||||
else
|
||||
/* The file position of fd has not changed. */
|
||||
result = -EAFNOSUPPORT;
|
||||
}
|
||||
else
|
||||
/* The file position of fd has not changed. */
|
||||
result = -EAFNOSUPPORT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* sendfile not possible, do a classic read-write loop. */
|
||||
|
||||
/* Number of bytes to seek (backwards) in case of error. */
|
||||
off_t nseek = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char buf[BLOCKSIZE];
|
||||
/* When the stream is not seekable, start with a single-byte block,
|
||||
so that we can use ungetc() in the case that send() fails. */
|
||||
size_t blocksize = (nseek == 0 && off < 0 ? 1 : BLOCKSIZE);
|
||||
ssize_t size = fread (buf, 1, blocksize, stream);
|
||||
if (size == 0)
|
||||
{
|
||||
/* On Linux < 4.9, the value for an empty stream is wrong (all 0).
|
||||
See <https://patchwork.kernel.org/patch/9308641/>.
|
||||
This was not fixed properly until November 2016,
|
||||
see <https://patchwork.kernel.org/patch/9434741/>. */
|
||||
result = ferror (stream) ? -EIO : nseek == 0 ? -EAFNOSUPPORT : 0;
|
||||
break;
|
||||
}
|
||||
nseek -= size;
|
||||
if (send (ofd, buf, size, MSG_MORE) != size)
|
||||
{
|
||||
if (nseek == -1)
|
||||
{
|
||||
/* 1 byte of pushback buffer is guaranteed on stream, even
|
||||
if stream is not seekable. */
|
||||
ungetc ((unsigned char) buf[0], stream);
|
||||
result = -EAFNOSUPPORT;
|
||||
}
|
||||
else if (fseeko (stream, nseek, SEEK_CUR) == 0)
|
||||
/* The position of stream has been restored. */
|
||||
result = -EAFNOSUPPORT;
|
||||
else
|
||||
result = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Don't assume that EOF is sticky. See:
|
||||
<https://sourceware.org/bugzilla/show_bug.cgi?id=19476>. */
|
||||
if (feof (stream))
|
||||
{
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == 0 && read (ofd, resblock, hashlen) != hashlen)
|
||||
{
|
||||
if (nseek == 0 || fseeko (stream, nseek, SEEK_CUR) == 0)
|
||||
/* The position of stream has been restored. */
|
||||
result = -EAFNOSUPPORT;
|
||||
else
|
||||
result = -EIO;
|
||||
}
|
||||
}
|
||||
close (ofd);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
115
lib/af_alg.h
Normal file
115
lib/af_alg.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/* af_alg.h - Compute message digests from file streams and buffers.
|
||||
Copyright (C) 2018-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Matteo Croce <mcroce@redhat.com>, 2018.
|
||||
Documentation by Bruno Haible <bruno@clisp.org>, 2018. */
|
||||
|
||||
/* Declare specific functions for computing message digests
|
||||
using the Linux kernel crypto API, if available. This kernel API gives
|
||||
access to specialized crypto instructions (that would also be available
|
||||
in user space) or to crypto devices (not directly available in user space).
|
||||
|
||||
For a more complete set of facilities that use the Linux kernel crypto API,
|
||||
look at libkcapi. */
|
||||
|
||||
#ifndef AF_ALG_H
|
||||
# define AF_ALG_H 1
|
||||
|
||||
# include <stdio.h>
|
||||
# include <errno.h>
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
# if USE_LINUX_CRYPTO_API
|
||||
|
||||
/* Compute a message digest of a memory region.
|
||||
|
||||
The memory region starts at BUFFER and is LEN bytes long.
|
||||
|
||||
ALG is the message digest algorithm; see the file /proc/crypto.
|
||||
|
||||
RESBLOCK points to a block of HASHLEN bytes, for the result.
|
||||
HASHLEN must be the length of the message digest, in bytes, in particular:
|
||||
|
||||
alg | hashlen
|
||||
-------+--------
|
||||
md5 | 16
|
||||
sha1 | 20
|
||||
sha224 | 28
|
||||
sha256 | 32
|
||||
sha384 | 48
|
||||
sha512 | 64
|
||||
|
||||
If successful, fill RESBLOCK and return 0.
|
||||
Upon failure, return a negated error number. */
|
||||
int
|
||||
afalg_buffer (const char *buffer, size_t len, const char *alg,
|
||||
void *resblock, ssize_t hashlen);
|
||||
|
||||
/* Compute a message digest of data read from STREAM.
|
||||
|
||||
STREAM is an open file stream. The last operation on STREAM should
|
||||
not be 'ungetc', and if STREAM is also open for writing it should
|
||||
have been fflushed since its last write. Read from the current
|
||||
position to the end of STREAM. Handle regular files efficiently.
|
||||
|
||||
ALG is the message digest algorithm; see the file /proc/crypto.
|
||||
|
||||
RESBLOCK points to a block of HASHLEN bytes, for the result.
|
||||
HASHLEN must be the length of the message digest, in bytes, in particular:
|
||||
|
||||
alg | hashlen
|
||||
-------+--------
|
||||
md5 | 16
|
||||
sha1 | 20
|
||||
sha224 | 28
|
||||
sha256 | 32
|
||||
sha384 | 48
|
||||
sha512 | 64
|
||||
|
||||
If successful, fill RESBLOCK and return 0.
|
||||
Upon failure, return a negated error number.
|
||||
Unless returning 0 or -EIO, restore STREAM's file position so that
|
||||
the caller can fall back on some other method. */
|
||||
int
|
||||
afalg_stream (FILE *stream, const char *alg,
|
||||
void *resblock, ssize_t hashlen);
|
||||
|
||||
# else
|
||||
|
||||
static inline int
|
||||
afalg_buffer (const char *buffer, size_t len, const char *alg,
|
||||
void *resblock, ssize_t hashlen)
|
||||
{
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
static inline int
|
||||
afalg_stream (FILE *stream, const char *alg,
|
||||
void *resblock, ssize_t hashlen)
|
||||
{
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif /* AF_ALG_H */
|
||||
50
lib/alignof.h
Normal file
50
lib/alignof.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* Determine alignment of types.
|
||||
Copyright (C) 2003-2004, 2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _ALIGNOF_H
|
||||
#define _ALIGNOF_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* alignof_slot (TYPE)
|
||||
Determine the alignment of a structure slot (field) of a given type,
|
||||
at compile time. Note that the result depends on the ABI.
|
||||
This is the same as alignof (TYPE) and _Alignof (TYPE), defined in
|
||||
<stdalign.h> if __alignof_is_defined is 1.
|
||||
Note: The result cannot be used as a value for an 'enum' constant,
|
||||
due to bugs in HP-UX 10.20 cc and AIX 3.2.5 xlc. */
|
||||
#if defined __cplusplus
|
||||
template <class type> struct alignof_helper { char __slot1; type __slot2; };
|
||||
# define alignof_slot(type) offsetof (alignof_helper<type>, __slot2)
|
||||
#else
|
||||
# define alignof_slot(type) offsetof (struct { char __slot1; type __slot2; }, __slot2)
|
||||
#endif
|
||||
|
||||
/* alignof_type (TYPE)
|
||||
Determine the good alignment of an object of the given type at compile time.
|
||||
Note that this is not necessarily the same as alignof_slot(type).
|
||||
For example, with GNU C on x86 platforms: alignof_type(double) = 8, but
|
||||
- when -malign-double is not specified: alignof_slot(double) = 4,
|
||||
- when -malign-double is specified: alignof_slot(double) = 8.
|
||||
Note: The result cannot be used as a value for an 'enum' constant,
|
||||
due to bugs in HP-UX 10.20 cc and AIX 3.2.5 xlc. */
|
||||
#if defined __GNUC__ || defined __IBM__ALIGNOF__
|
||||
# define alignof_type __alignof__
|
||||
#else
|
||||
# define alignof_type alignof_slot
|
||||
#endif
|
||||
|
||||
#endif /* _ALIGNOF_H */
|
||||
478
lib/alloca.c
Normal file
478
lib/alloca.c
Normal file
@@ -0,0 +1,478 @@
|
||||
/* alloca.c -- allocate automatically reclaimed memory
|
||||
(Mostly) portable public-domain implementation -- D A Gwyn
|
||||
|
||||
This implementation of the PWB library alloca function,
|
||||
which is used to allocate space off the run-time stack so
|
||||
that it is automatically reclaimed upon procedure exit,
|
||||
was inspired by discussions with J. Q. Johnson of Cornell.
|
||||
J.Otto Tennant <jot@cray.com> contributed the Cray support.
|
||||
|
||||
There are some preprocessor constants that can
|
||||
be defined when compiling for your specific system, for
|
||||
improved efficiency; however, the defaults should be okay.
|
||||
|
||||
The general concept of this implementation is to keep
|
||||
track of all alloca-allocated blocks, and reclaim any
|
||||
that are found to be deeper in the stack than the current
|
||||
invocation. This heuristic does not reclaim storage as
|
||||
soon as it becomes invalid, but it will do so eventually.
|
||||
|
||||
As a special case, alloca(0) reclaims storage without
|
||||
allocating any. It is a good idea to use alloca(0) in
|
||||
your main control loop, etc. to force garbage collection. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <alloca.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef emacs
|
||||
# include "lisp.h"
|
||||
# include "blockinput.h"
|
||||
# ifdef EMACS_FREE
|
||||
# undef free
|
||||
# define free EMACS_FREE
|
||||
# endif
|
||||
#else
|
||||
# define memory_full() abort ()
|
||||
#endif
|
||||
|
||||
/* If compiling with GCC 2, this file's not needed. */
|
||||
#if !defined (__GNUC__) || __GNUC__ < 2
|
||||
|
||||
/* If someone has defined alloca as a macro,
|
||||
there must be some other way alloca is supposed to work. */
|
||||
# ifndef alloca
|
||||
|
||||
# ifdef emacs
|
||||
# ifdef static
|
||||
/* actually, only want this if static is defined as ""
|
||||
-- this is for usg, in which emacs must undefine static
|
||||
in order to make unexec workable
|
||||
*/
|
||||
# ifndef STACK_DIRECTION
|
||||
you
|
||||
lose
|
||||
-- must know STACK_DIRECTION at compile-time
|
||||
/* Using #error here is not wise since this file should work for
|
||||
old and obscure compilers. */
|
||||
# endif /* STACK_DIRECTION undefined */
|
||||
# endif /* static */
|
||||
# endif /* emacs */
|
||||
|
||||
/* If your stack is a linked list of frames, you have to
|
||||
provide an "address metric" ADDRESS_FUNCTION macro. */
|
||||
|
||||
# if defined (CRAY) && defined (CRAY_STACKSEG_END)
|
||||
long i00afunc ();
|
||||
# define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
|
||||
# else
|
||||
# define ADDRESS_FUNCTION(arg) &(arg)
|
||||
# endif
|
||||
|
||||
/* Define STACK_DIRECTION if you know the direction of stack
|
||||
growth for your system; otherwise it will be automatically
|
||||
deduced at run-time.
|
||||
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown */
|
||||
|
||||
# ifndef STACK_DIRECTION
|
||||
# define STACK_DIRECTION 0 /* Direction unknown. */
|
||||
# endif
|
||||
|
||||
# if STACK_DIRECTION != 0
|
||||
|
||||
# define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
|
||||
|
||||
# else /* STACK_DIRECTION == 0; need run-time code. */
|
||||
|
||||
static int stack_dir; /* 1 or -1 once known. */
|
||||
# define STACK_DIR stack_dir
|
||||
|
||||
static int
|
||||
find_stack_direction (int *addr, int depth)
|
||||
{
|
||||
int dir, dummy = 0;
|
||||
if (! addr)
|
||||
addr = &dummy;
|
||||
*addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1;
|
||||
dir = depth ? find_stack_direction (addr, depth - 1) : 0;
|
||||
return dir + dummy;
|
||||
}
|
||||
|
||||
# endif /* STACK_DIRECTION == 0 */
|
||||
|
||||
/* An "alloca header" is used to:
|
||||
(a) chain together all alloca'ed blocks;
|
||||
(b) keep track of stack depth.
|
||||
|
||||
It is very important that sizeof(header) agree with malloc
|
||||
alignment chunk size. The following default should work okay. */
|
||||
|
||||
# ifndef ALIGN_SIZE
|
||||
# define ALIGN_SIZE sizeof(double)
|
||||
# endif
|
||||
|
||||
typedef union hdr
|
||||
{
|
||||
char align[ALIGN_SIZE]; /* To force sizeof(header). */
|
||||
struct
|
||||
{
|
||||
union hdr *next; /* For chaining headers. */
|
||||
char *deep; /* For stack depth measure. */
|
||||
} h;
|
||||
} header;
|
||||
|
||||
static header *last_alloca_header = NULL; /* -> last alloca header. */
|
||||
|
||||
/* Return a pointer to at least SIZE bytes of storage,
|
||||
which will be automatically reclaimed upon exit from
|
||||
the procedure that called alloca. Originally, this space
|
||||
was supposed to be taken from the current stack frame of the
|
||||
caller, but that method cannot be made to work for some
|
||||
implementations of C, for example under Gould's UTX/32. */
|
||||
|
||||
void *
|
||||
alloca (size_t size)
|
||||
{
|
||||
auto char probe; /* Probes stack depth: */
|
||||
register char *depth = ADDRESS_FUNCTION (probe);
|
||||
|
||||
# if STACK_DIRECTION == 0
|
||||
if (STACK_DIR == 0) /* Unknown growth direction. */
|
||||
STACK_DIR = find_stack_direction (NULL, (size & 1) + 20);
|
||||
# endif
|
||||
|
||||
/* Reclaim garbage, defined as all alloca'd storage that
|
||||
was allocated from deeper in the stack than currently. */
|
||||
|
||||
{
|
||||
register header *hp; /* Traverses linked list. */
|
||||
|
||||
# ifdef emacs
|
||||
BLOCK_INPUT;
|
||||
# endif
|
||||
|
||||
for (hp = last_alloca_header; hp != NULL;)
|
||||
if ((STACK_DIR > 0 && hp->h.deep > depth)
|
||||
|| (STACK_DIR < 0 && hp->h.deep < depth))
|
||||
{
|
||||
register header *np = hp->h.next;
|
||||
|
||||
free (hp); /* Collect garbage. */
|
||||
|
||||
hp = np; /* -> next header. */
|
||||
}
|
||||
else
|
||||
break; /* Rest are not deeper. */
|
||||
|
||||
last_alloca_header = hp; /* -> last valid storage. */
|
||||
|
||||
# ifdef emacs
|
||||
UNBLOCK_INPUT;
|
||||
# endif
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
return NULL; /* No allocation required. */
|
||||
|
||||
/* Allocate combined header + user data storage. */
|
||||
|
||||
{
|
||||
/* Address of header. */
|
||||
register header *new;
|
||||
|
||||
size_t combined_size = sizeof (header) + size;
|
||||
if (combined_size < sizeof (header))
|
||||
memory_full ();
|
||||
|
||||
new = malloc (combined_size);
|
||||
|
||||
if (! new)
|
||||
memory_full ();
|
||||
|
||||
new->h.next = last_alloca_header;
|
||||
new->h.deep = depth;
|
||||
|
||||
last_alloca_header = new;
|
||||
|
||||
/* User storage begins just after header. */
|
||||
|
||||
return (void *) (new + 1);
|
||||
}
|
||||
}
|
||||
|
||||
# if defined (CRAY) && defined (CRAY_STACKSEG_END)
|
||||
|
||||
# ifdef DEBUG_I00AFUNC
|
||||
# include <stdio.h>
|
||||
# endif
|
||||
|
||||
# ifndef CRAY_STACK
|
||||
# define CRAY_STACK
|
||||
# ifndef CRAY2
|
||||
/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
|
||||
struct stack_control_header
|
||||
{
|
||||
long shgrow:32; /* Number of times stack has grown. */
|
||||
long shaseg:32; /* Size of increments to stack. */
|
||||
long shhwm:32; /* High water mark of stack. */
|
||||
long shsize:32; /* Current size of stack (all segments). */
|
||||
};
|
||||
|
||||
/* The stack segment linkage control information occurs at
|
||||
the high-address end of a stack segment. (The stack
|
||||
grows from low addresses to high addresses.) The initial
|
||||
part of the stack segment linkage control information is
|
||||
0200 (octal) words. This provides for register storage
|
||||
for the routine which overflows the stack. */
|
||||
|
||||
struct stack_segment_linkage
|
||||
{
|
||||
long ss[0200]; /* 0200 overflow words. */
|
||||
long sssize:32; /* Number of words in this segment. */
|
||||
long ssbase:32; /* Offset to stack base. */
|
||||
long:32;
|
||||
long sspseg:32; /* Offset to linkage control of previous
|
||||
segment of stack. */
|
||||
long:32;
|
||||
long sstcpt:32; /* Pointer to task common address block. */
|
||||
long sscsnm; /* Private control structure number for
|
||||
microtasking. */
|
||||
long ssusr1; /* Reserved for user. */
|
||||
long ssusr2; /* Reserved for user. */
|
||||
long sstpid; /* Process ID for pid based multi-tasking. */
|
||||
long ssgvup; /* Pointer to multitasking thread giveup. */
|
||||
long sscray[7]; /* Reserved for Cray Research. */
|
||||
long ssa0;
|
||||
long ssa1;
|
||||
long ssa2;
|
||||
long ssa3;
|
||||
long ssa4;
|
||||
long ssa5;
|
||||
long ssa6;
|
||||
long ssa7;
|
||||
long sss0;
|
||||
long sss1;
|
||||
long sss2;
|
||||
long sss3;
|
||||
long sss4;
|
||||
long sss5;
|
||||
long sss6;
|
||||
long sss7;
|
||||
};
|
||||
|
||||
# else /* CRAY2 */
|
||||
/* The following structure defines the vector of words
|
||||
returned by the STKSTAT library routine. */
|
||||
struct stk_stat
|
||||
{
|
||||
long now; /* Current total stack size. */
|
||||
long maxc; /* Amount of contiguous space which would
|
||||
be required to satisfy the maximum
|
||||
stack demand to date. */
|
||||
long high_water; /* Stack high-water mark. */
|
||||
long overflows; /* Number of stack overflow ($STKOFEN) calls. */
|
||||
long hits; /* Number of internal buffer hits. */
|
||||
long extends; /* Number of block extensions. */
|
||||
long stko_mallocs; /* Block allocations by $STKOFEN. */
|
||||
long underflows; /* Number of stack underflow calls ($STKRETN). */
|
||||
long stko_free; /* Number of deallocations by $STKRETN. */
|
||||
long stkm_free; /* Number of deallocations by $STKMRET. */
|
||||
long segments; /* Current number of stack segments. */
|
||||
long maxs; /* Maximum number of stack segments so far. */
|
||||
long pad_size; /* Stack pad size. */
|
||||
long current_address; /* Current stack segment address. */
|
||||
long current_size; /* Current stack segment size. This
|
||||
number is actually corrupted by STKSTAT to
|
||||
include the fifteen word trailer area. */
|
||||
long initial_address; /* Address of initial segment. */
|
||||
long initial_size; /* Size of initial segment. */
|
||||
};
|
||||
|
||||
/* The following structure describes the data structure which trails
|
||||
any stack segment. I think that the description in 'asdef' is
|
||||
out of date. I only describe the parts that I am sure about. */
|
||||
|
||||
struct stk_trailer
|
||||
{
|
||||
long this_address; /* Address of this block. */
|
||||
long this_size; /* Size of this block (does not include
|
||||
this trailer). */
|
||||
long unknown2;
|
||||
long unknown3;
|
||||
long link; /* Address of trailer block of previous
|
||||
segment. */
|
||||
long unknown5;
|
||||
long unknown6;
|
||||
long unknown7;
|
||||
long unknown8;
|
||||
long unknown9;
|
||||
long unknown10;
|
||||
long unknown11;
|
||||
long unknown12;
|
||||
long unknown13;
|
||||
long unknown14;
|
||||
};
|
||||
|
||||
# endif /* CRAY2 */
|
||||
# endif /* not CRAY_STACK */
|
||||
|
||||
# ifdef CRAY2
|
||||
/* Determine a "stack measure" for an arbitrary ADDRESS.
|
||||
I doubt that "lint" will like this much. */
|
||||
|
||||
static long
|
||||
i00afunc (long *address)
|
||||
{
|
||||
struct stk_stat status;
|
||||
struct stk_trailer *trailer;
|
||||
long *block, size;
|
||||
long result = 0;
|
||||
|
||||
/* We want to iterate through all of the segments. The first
|
||||
step is to get the stack status structure. We could do this
|
||||
more quickly and more directly, perhaps, by referencing the
|
||||
$LM00 common block, but I know that this works. */
|
||||
|
||||
STKSTAT (&status);
|
||||
|
||||
/* Set up the iteration. */
|
||||
|
||||
trailer = (struct stk_trailer *) (status.current_address
|
||||
+ status.current_size
|
||||
- 15);
|
||||
|
||||
/* There must be at least one stack segment. Therefore it is
|
||||
a fatal error if "trailer" is null. */
|
||||
|
||||
if (trailer == NULL)
|
||||
abort ();
|
||||
|
||||
/* Discard segments that do not contain our argument address. */
|
||||
|
||||
while (trailer != NULL)
|
||||
{
|
||||
block = (long *) trailer->this_address;
|
||||
size = trailer->this_size;
|
||||
if (block == NULL || size == 0)
|
||||
abort ();
|
||||
trailer = (struct stk_trailer *) trailer->link;
|
||||
if ((block <= address) && (address < (block + size)))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the result to the offset in this segment and add the sizes
|
||||
of all predecessor segments. */
|
||||
|
||||
result = address - block;
|
||||
|
||||
if (trailer == NULL)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (trailer->this_size <= 0)
|
||||
abort ();
|
||||
result += trailer->this_size;
|
||||
trailer = (struct stk_trailer *) trailer->link;
|
||||
}
|
||||
while (trailer != NULL);
|
||||
|
||||
/* We are done. Note that if you present a bogus address (one
|
||||
not in any segment), you will get a different number back, formed
|
||||
from subtracting the address of the first block. This is probably
|
||||
not what you want. */
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
# else /* not CRAY2 */
|
||||
/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
|
||||
Determine the number of the cell within the stack,
|
||||
given the address of the cell. The purpose of this
|
||||
routine is to linearize, in some sense, stack addresses
|
||||
for alloca. */
|
||||
|
||||
static long
|
||||
i00afunc (long address)
|
||||
{
|
||||
long stkl = 0;
|
||||
|
||||
long size, pseg, this_segment, stack;
|
||||
long result = 0;
|
||||
|
||||
struct stack_segment_linkage *ssptr;
|
||||
|
||||
/* Register B67 contains the address of the end of the
|
||||
current stack segment. If you (as a subprogram) store
|
||||
your registers on the stack and find that you are past
|
||||
the contents of B67, you have overflowed the segment.
|
||||
|
||||
B67 also points to the stack segment linkage control
|
||||
area, which is what we are really interested in. */
|
||||
|
||||
stkl = CRAY_STACKSEG_END ();
|
||||
ssptr = (struct stack_segment_linkage *) stkl;
|
||||
|
||||
/* If one subtracts 'size' from the end of the segment,
|
||||
one has the address of the first word of the segment.
|
||||
|
||||
If this is not the first segment, 'pseg' will be
|
||||
nonzero. */
|
||||
|
||||
pseg = ssptr->sspseg;
|
||||
size = ssptr->sssize;
|
||||
|
||||
this_segment = stkl - size;
|
||||
|
||||
/* It is possible that calling this routine itself caused
|
||||
a stack overflow. Discard stack segments which do not
|
||||
contain the target address. */
|
||||
|
||||
while (!(this_segment <= address && address <= stkl))
|
||||
{
|
||||
# ifdef DEBUG_I00AFUNC
|
||||
fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
|
||||
# endif
|
||||
if (pseg == 0)
|
||||
break;
|
||||
stkl = stkl - pseg;
|
||||
ssptr = (struct stack_segment_linkage *) stkl;
|
||||
size = ssptr->sssize;
|
||||
pseg = ssptr->sspseg;
|
||||
this_segment = stkl - size;
|
||||
}
|
||||
|
||||
result = address - this_segment;
|
||||
|
||||
/* If you subtract pseg from the current end of the stack,
|
||||
you get the address of the previous stack segment's end.
|
||||
This seems a little convoluted to me, but I'll bet you save
|
||||
a cycle somewhere. */
|
||||
|
||||
while (pseg != 0)
|
||||
{
|
||||
# ifdef DEBUG_I00AFUNC
|
||||
fprintf (stderr, "%011o %011o\n", pseg, size);
|
||||
# endif
|
||||
stkl = stkl - pseg;
|
||||
ssptr = (struct stack_segment_linkage *) stkl;
|
||||
size = ssptr->sssize;
|
||||
pseg = ssptr->sspseg;
|
||||
result += size;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
# endif /* not CRAY2 */
|
||||
# endif /* CRAY */
|
||||
|
||||
# endif /* no alloca */
|
||||
#endif /* not GCC 2 */
|
||||
72
lib/alloca.h
Normal file
72
lib/alloca.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||||
/* Memory allocation on the stack.
|
||||
|
||||
Copyright (C) 1995, 1999, 2001-2004, 2006-2020 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; if not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Avoid using the symbol _ALLOCA_H here, as Bison assumes _ALLOCA_H
|
||||
means there is a real alloca function. */
|
||||
#ifndef _GL_ALLOCA_H
|
||||
#define _GL_ALLOCA_H
|
||||
|
||||
/* alloca (N) returns a pointer to N bytes of memory
|
||||
allocated on the stack, which will last until the function returns.
|
||||
Use of alloca should be avoided:
|
||||
- inside arguments of function calls - undefined behaviour,
|
||||
- in inline functions - the allocation may actually last until the
|
||||
calling function returns,
|
||||
- for huge N (say, N >= 65536) - you never know how large (or small)
|
||||
the stack is, and when the stack cannot fulfill the memory allocation
|
||||
request, the program just crashes.
|
||||
*/
|
||||
|
||||
#ifndef alloca
|
||||
# ifdef __GNUC__
|
||||
/* Some version of mingw have an <alloca.h> that causes trouble when
|
||||
included after 'alloca' gets defined as a macro. As a workaround, include
|
||||
this <alloca.h> first and define 'alloca' as a macro afterwards. */
|
||||
# if (defined _WIN32 && ! defined __CYGWIN__) && 1
|
||||
# include_next <alloca.h>
|
||||
# endif
|
||||
# define alloca __builtin_alloca
|
||||
# elif defined _AIX
|
||||
# define alloca __alloca
|
||||
# elif defined _MSC_VER
|
||||
# include <malloc.h>
|
||||
# define alloca _alloca
|
||||
# elif defined __DECC && defined __VMS
|
||||
# define alloca __ALLOCA
|
||||
# elif defined __TANDEM && defined _TNS_E_TARGET
|
||||
# ifdef __cplusplus
|
||||
extern "C"
|
||||
# endif
|
||||
void *_alloca (unsigned short);
|
||||
# pragma intrinsic (_alloca)
|
||||
# define alloca _alloca
|
||||
# elif defined __MVS__
|
||||
# include <stdlib.h>
|
||||
# else
|
||||
# include <stddef.h>
|
||||
# ifdef __cplusplus
|
||||
extern "C"
|
||||
# endif
|
||||
void *alloca (size_t);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* _GL_ALLOCA_H */
|
||||
71
lib/alloca.in.h
Normal file
71
lib/alloca.in.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* Memory allocation on the stack.
|
||||
|
||||
Copyright (C) 1995, 1999, 2001-2004, 2006-2020 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; if not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Avoid using the symbol _ALLOCA_H here, as Bison assumes _ALLOCA_H
|
||||
means there is a real alloca function. */
|
||||
#ifndef _GL_ALLOCA_H
|
||||
#define _GL_ALLOCA_H
|
||||
|
||||
/* alloca (N) returns a pointer to N bytes of memory
|
||||
allocated on the stack, which will last until the function returns.
|
||||
Use of alloca should be avoided:
|
||||
- inside arguments of function calls - undefined behaviour,
|
||||
- in inline functions - the allocation may actually last until the
|
||||
calling function returns,
|
||||
- for huge N (say, N >= 65536) - you never know how large (or small)
|
||||
the stack is, and when the stack cannot fulfill the memory allocation
|
||||
request, the program just crashes.
|
||||
*/
|
||||
|
||||
#ifndef alloca
|
||||
# ifdef __GNUC__
|
||||
/* Some version of mingw have an <alloca.h> that causes trouble when
|
||||
included after 'alloca' gets defined as a macro. As a workaround, include
|
||||
this <alloca.h> first and define 'alloca' as a macro afterwards. */
|
||||
# if (defined _WIN32 && ! defined __CYGWIN__) && @HAVE_ALLOCA_H@
|
||||
# include_next <alloca.h>
|
||||
# endif
|
||||
# define alloca __builtin_alloca
|
||||
# elif defined _AIX
|
||||
# define alloca __alloca
|
||||
# elif defined _MSC_VER
|
||||
# include <malloc.h>
|
||||
# define alloca _alloca
|
||||
# elif defined __DECC && defined __VMS
|
||||
# define alloca __ALLOCA
|
||||
# elif defined __TANDEM && defined _TNS_E_TARGET
|
||||
# ifdef __cplusplus
|
||||
extern "C"
|
||||
# endif
|
||||
void *_alloca (unsigned short);
|
||||
# pragma intrinsic (_alloca)
|
||||
# define alloca _alloca
|
||||
# elif defined __MVS__
|
||||
# include <stdlib.h>
|
||||
# else
|
||||
# include <stddef.h>
|
||||
# ifdef __cplusplus
|
||||
extern "C"
|
||||
# endif
|
||||
void *alloca (size_t);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* _GL_ALLOCA_H */
|
||||
5
lib/allocator.c
Normal file
5
lib/allocator.c
Normal file
@@ -0,0 +1,5 @@
|
||||
#define _GL_USE_STDLIB_ALLOC 1
|
||||
#include <config.h>
|
||||
#include "allocator.h"
|
||||
#include <stdlib.h>
|
||||
struct allocator const stdlib_allocator = { malloc, realloc, free, NULL };
|
||||
58
lib/allocator.h
Normal file
58
lib/allocator.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* Memory allocators such as malloc+free.
|
||||
|
||||
Copyright (C) 2011-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Paul Eggert. */
|
||||
|
||||
#ifndef _GL_ALLOCATOR_H
|
||||
#define _GL_ALLOCATOR_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* An object describing a memory allocator family. */
|
||||
|
||||
struct allocator
|
||||
{
|
||||
/* Do not use GCC attributes such as __attribute__ ((malloc)) with
|
||||
the function types pointed at by these members, because these
|
||||
attributes do not work with pointers to functions. See
|
||||
<https://lists.gnu.org/r/bug-gnulib/2011-04/msg00007.html>. */
|
||||
|
||||
/* Call ALLOCATE to allocate memory, like 'malloc'. On failure ALLOCATE
|
||||
should return NULL, though not necessarily set errno. When given
|
||||
a zero size it may return NULL even if successful. */
|
||||
void *(*allocate) (size_t);
|
||||
|
||||
/* If nonnull, call REALLOCATE to reallocate memory, like 'realloc'.
|
||||
On failure REALLOCATE should return NULL, though not necessarily set
|
||||
errno. When given a zero size it may return NULL even if
|
||||
successful. */
|
||||
void *(*reallocate) (void *, size_t);
|
||||
|
||||
/* Call FREE to free memory, like 'free'. */
|
||||
void (*free) (void *);
|
||||
|
||||
/* If nonnull, call DIE (SIZE) if MALLOC (SIZE) or REALLOC (...,
|
||||
SIZE) fails. DIE should not return. SIZE should equal SIZE_MAX
|
||||
if size_t overflow was detected while calculating sizes to be
|
||||
passed to MALLOC or REALLOC. */
|
||||
void (*die) (size_t);
|
||||
};
|
||||
|
||||
/* An allocator using the stdlib functions and a null DIE function. */
|
||||
extern struct allocator const stdlib_allocator;
|
||||
|
||||
#endif /* _GL_ALLOCATOR_H */
|
||||
57
lib/anytostr.c
Normal file
57
lib/anytostr.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/* anytostr.c -- convert integers to printable strings
|
||||
|
||||
Copyright (C) 2001, 2006, 2008-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Paul Eggert */
|
||||
|
||||
/* Tell gcc not to warn about the (i < 0) test, below. */
|
||||
#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wtype-limits"
|
||||
#elif defined __clang__
|
||||
# pragma clang diagnostic ignored "-Wtautological-compare"
|
||||
#endif
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "inttostr.h"
|
||||
|
||||
/* Convert I to a printable string in BUF, which must be at least
|
||||
INT_BUFSIZE_BOUND (INTTYPE) bytes long. Return the address of the
|
||||
printable string, which need not start at BUF. */
|
||||
|
||||
char * __attribute_warn_unused_result__
|
||||
anytostr (inttype i, char *buf)
|
||||
{
|
||||
char *p = buf + INT_STRLEN_BOUND (inttype);
|
||||
*p = 0;
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
do
|
||||
*--p = '0' - i % 10;
|
||||
while ((i /= 10) != 0);
|
||||
|
||||
*--p = '-';
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
*--p = '0' + i % 10;
|
||||
while ((i /= 10) != 0);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
128
lib/areadlink-with-size.c
Normal file
128
lib/areadlink-with-size.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/* readlink wrapper to return the link name in malloc'd storage.
|
||||
Unlike xreadlink and xreadlink_with_size, don't ever call exit.
|
||||
|
||||
Copyright (C) 2001, 2003-2007, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Jim Meyering <jim@meyering.net> */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "areadlink.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef SSIZE_MAX
|
||||
# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
|
||||
#endif
|
||||
|
||||
/* SYMLINK_MAX is used only for an initial memory-allocation sanity
|
||||
check, so it's OK to guess too small on hosts where there is no
|
||||
arbitrary limit to symbolic link length. */
|
||||
#ifndef SYMLINK_MAX
|
||||
# define SYMLINK_MAX 1024
|
||||
#endif
|
||||
|
||||
#define MAXSIZE (SIZE_MAX < SSIZE_MAX ? SIZE_MAX : SSIZE_MAX)
|
||||
|
||||
/* Call readlink to get the symbolic link value of FILE.
|
||||
SIZE is a hint as to how long the link is expected to be;
|
||||
typically it is taken from st_size. It need not be correct.
|
||||
Return a pointer to that NUL-terminated string in malloc'd storage.
|
||||
If readlink fails, malloc fails, or if the link value is longer
|
||||
than SSIZE_MAX, return NULL (caller may use errno to diagnose). */
|
||||
|
||||
char *
|
||||
areadlink_with_size (char const *file, size_t size)
|
||||
{
|
||||
/* Some buggy file systems report garbage in st_size. Defend
|
||||
against them by ignoring outlandish st_size values in the initial
|
||||
memory allocation. */
|
||||
size_t symlink_max = SYMLINK_MAX;
|
||||
size_t INITIAL_LIMIT_BOUND = 8 * 1024;
|
||||
size_t initial_limit = (symlink_max < INITIAL_LIMIT_BOUND
|
||||
? symlink_max + 1
|
||||
: INITIAL_LIMIT_BOUND);
|
||||
|
||||
enum { stackbuf_size = 128 };
|
||||
|
||||
/* The initial buffer size for the link value. */
|
||||
size_t buf_size = (size == 0 ? stackbuf_size
|
||||
: size < initial_limit ? size + 1 : initial_limit);
|
||||
|
||||
while (1)
|
||||
{
|
||||
ssize_t r;
|
||||
size_t link_length;
|
||||
char stackbuf[stackbuf_size];
|
||||
char *buf = stackbuf;
|
||||
char *buffer = NULL;
|
||||
|
||||
if (! (size == 0 && buf_size == stackbuf_size))
|
||||
{
|
||||
buf = buffer = malloc (buf_size);
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = readlink (file, buf, buf_size);
|
||||
link_length = r;
|
||||
|
||||
/* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink returns -1
|
||||
with errno == ERANGE if the buffer is too small. */
|
||||
if (r < 0 && errno != ERANGE)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
free (buffer);
|
||||
errno = saved_errno;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (link_length < buf_size)
|
||||
{
|
||||
buf[link_length] = 0;
|
||||
if (!buffer)
|
||||
{
|
||||
buffer = malloc (link_length + 1);
|
||||
if (buffer)
|
||||
return memcpy (buffer, buf, link_length + 1);
|
||||
}
|
||||
else if (link_length + 1 < buf_size)
|
||||
{
|
||||
/* Shrink BUFFER before returning it. */
|
||||
char *shrinked_buffer = realloc (buffer, link_length + 1);
|
||||
if (shrinked_buffer != NULL)
|
||||
buffer = shrinked_buffer;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
free (buffer);
|
||||
if (buf_size <= MAXSIZE / 2)
|
||||
buf_size *= 2;
|
||||
else if (buf_size < MAXSIZE)
|
||||
buf_size = MAXSIZE;
|
||||
else
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
56
lib/areadlink.c
Normal file
56
lib/areadlink.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/* areadlink.c -- readlink wrapper to return the link name in malloc'd storage
|
||||
Unlike xreadlink and xreadlink_with_size, don't ever call exit.
|
||||
|
||||
Copyright (C) 2001, 2003-2007, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Jim Meyering <jim@meyering.net>
|
||||
and Bruno Haible <bruno@clisp.org>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include "areadlink.h"
|
||||
|
||||
#include "careadlinkat.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Get the symbolic link value of FILENAME and put it into BUFFER, with
|
||||
size BUFFER_SIZE. This function acts like readlink but has
|
||||
readlinkat's signature. */
|
||||
static ssize_t
|
||||
careadlinkatcwd (int fd, char const *filename, char *buffer,
|
||||
size_t buffer_size)
|
||||
{
|
||||
/* FD must be AT_FDCWD here, otherwise the caller is using this
|
||||
function in contexts it was not meant for. */
|
||||
if (fd != AT_FDCWD)
|
||||
abort ();
|
||||
return readlink (filename, buffer, buffer_size);
|
||||
}
|
||||
|
||||
/* Call readlink to get the symbolic link value of FILENAME.
|
||||
Return a pointer to that NUL-terminated string in malloc'd storage.
|
||||
If readlink fails, return NULL and set errno.
|
||||
If allocation fails, or if the link value is longer than SIZE_MAX :-),
|
||||
return NULL and set errno to ENOMEM. */
|
||||
|
||||
char *
|
||||
areadlink (char const *filename)
|
||||
{
|
||||
return careadlinkat (AT_FDCWD, filename, NULL, 0, NULL, careadlinkatcwd);
|
||||
}
|
||||
33
lib/areadlink.h
Normal file
33
lib/areadlink.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/* Read symbolic links without size limitation.
|
||||
|
||||
Copyright (C) 2001, 2003-2004, 2007, 2009-2020 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Jim Meyering <jim@meyering.net> */
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
extern char *areadlink (char const *filename);
|
||||
extern char *areadlink_with_size (char const *filename, size_t size_hint);
|
||||
|
||||
#if GNULIB_AREADLINKAT
|
||||
extern char *areadlinkat (int fd, char const *filename);
|
||||
#endif
|
||||
|
||||
#if GNULIB_AREADLINKAT_WITH_SIZE
|
||||
extern char *areadlinkat_with_size (int fd, char const *filename,
|
||||
size_t size_hint);
|
||||
#endif
|
||||
67
lib/areadlinkat.c
Normal file
67
lib/areadlinkat.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/* areadlinkat.c -- readlinkat wrapper to return malloc'd link name
|
||||
Unlike xreadlinkat, only call exit on failure to change directory.
|
||||
|
||||
Copyright (C) 2001, 2003-2007, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Jim Meyering <jim@meyering.net>,
|
||||
and Bruno Haible <bruno@clisp.org>,
|
||||
and Eric Blake <ebb9@byu.net>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include "areadlink.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "careadlinkat.h"
|
||||
|
||||
#if HAVE_READLINKAT
|
||||
|
||||
/* Call readlinkat to get the symbolic link value of FILENAME relative to FD.
|
||||
Return a pointer to that NUL-terminated string in malloc'd storage.
|
||||
If readlinkat fails, return NULL and set errno (although failure to
|
||||
change directory will issue a diagnostic and exit).
|
||||
If allocation fails, or if the link value is longer than SIZE_MAX :-),
|
||||
return NULL and set errno to ENOMEM. */
|
||||
|
||||
char *
|
||||
areadlinkat (int fd, char const *filename)
|
||||
{
|
||||
return careadlinkat (fd, filename, NULL, 0, NULL, readlinkat);
|
||||
}
|
||||
|
||||
#else /* !HAVE_READLINKAT */
|
||||
|
||||
/* It is more efficient to change directories only once and call
|
||||
areadlink, rather than repeatedly call the replacement
|
||||
readlinkat. */
|
||||
|
||||
# define AT_FUNC_NAME areadlinkat
|
||||
# define AT_FUNC_F1 areadlink
|
||||
# define AT_FUNC_POST_FILE_PARAM_DECLS /* empty */
|
||||
# define AT_FUNC_POST_FILE_ARGS /* empty */
|
||||
# define AT_FUNC_RESULT char *
|
||||
# define AT_FUNC_FAIL NULL
|
||||
# include "at-func.c"
|
||||
# undef AT_FUNC_NAME
|
||||
# undef AT_FUNC_F1
|
||||
# undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
# undef AT_FUNC_POST_FILE_ARGS
|
||||
# undef AT_FUNC_RESULT
|
||||
# undef AT_FUNC_FAIL
|
||||
|
||||
#endif /* !HAVE_READLINKAT */
|
||||
26
lib/arg-nonnull.h
Normal file
26
lib/arg-nonnull.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* A C macro for declaring that specific arguments must not be NULL.
|
||||
Copyright (C) 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* _GL_ARG_NONNULL((n,...,m)) tells the compiler and static analyzer tools
|
||||
that the values passed as arguments n, ..., m must be non-NULL pointers.
|
||||
n = 1 stands for the first argument, n = 2 for the second argument etc. */
|
||||
#ifndef _GL_ARG_NONNULL
|
||||
# if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ > 3
|
||||
# define _GL_ARG_NONNULL(params) __attribute__ ((__nonnull__ params))
|
||||
# else
|
||||
# define _GL_ARG_NONNULL(params)
|
||||
# endif
|
||||
#endif
|
||||
273
lib/argmatch.c
Normal file
273
lib/argmatch.c
Normal file
@@ -0,0 +1,273 @@
|
||||
/* argmatch.c -- find a match for a string in an array
|
||||
|
||||
Copyright (C) 1990, 1998-1999, 2001-2007, 2009-2020 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by David MacKenzie <djm@ai.mit.edu>
|
||||
Modified by Akim Demaille <demaille@inf.enst.fr> */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include "argmatch.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define _(msgid) gettext (msgid)
|
||||
|
||||
#include "error.h"
|
||||
#include "quotearg.h"
|
||||
#include "getprogname.h"
|
||||
|
||||
#if USE_UNLOCKED_IO
|
||||
# include "unlocked-io.h"
|
||||
#endif
|
||||
|
||||
/* When reporting an invalid argument, show nonprinting characters
|
||||
by using the quoting style ARGMATCH_QUOTING_STYLE. Do not use
|
||||
literal_quoting_style. */
|
||||
#ifndef ARGMATCH_QUOTING_STYLE
|
||||
# define ARGMATCH_QUOTING_STYLE locale_quoting_style
|
||||
#endif
|
||||
|
||||
/* Non failing version of argmatch call this function after failing. */
|
||||
#ifndef ARGMATCH_DIE
|
||||
# include "exitfail.h"
|
||||
# define ARGMATCH_DIE exit (exit_failure)
|
||||
#endif
|
||||
|
||||
#ifdef ARGMATCH_DIE_DECL
|
||||
ARGMATCH_DIE_DECL;
|
||||
#endif
|
||||
|
||||
static void
|
||||
__argmatch_die (void)
|
||||
{
|
||||
ARGMATCH_DIE;
|
||||
}
|
||||
|
||||
/* Used by XARGMATCH and XARGCASEMATCH. See description in argmatch.h.
|
||||
Default to __argmatch_die, but allow caller to change this at run-time. */
|
||||
argmatch_exit_fn argmatch_die = __argmatch_die;
|
||||
|
||||
|
||||
/* If ARG is an unambiguous match for an element of the
|
||||
NULL-terminated array ARGLIST, return the index in ARGLIST
|
||||
of the matched element, else -1 if it does not match any element
|
||||
or -2 if it is ambiguous (is a prefix of more than one element).
|
||||
|
||||
If VALLIST is none null, use it to resolve ambiguities limited to
|
||||
synonyms, i.e., for
|
||||
"yes", "yop" -> 0
|
||||
"no", "nope" -> 1
|
||||
"y" is a valid argument, for 0, and "n" for 1. */
|
||||
|
||||
ptrdiff_t
|
||||
argmatch (const char *arg, const char *const *arglist,
|
||||
const void *vallist, size_t valsize)
|
||||
{
|
||||
size_t i; /* Temporary index in ARGLIST. */
|
||||
size_t arglen; /* Length of ARG. */
|
||||
ptrdiff_t matchind = -1; /* Index of first nonexact match. */
|
||||
bool ambiguous = false; /* If true, multiple nonexact match(es). */
|
||||
|
||||
arglen = strlen (arg);
|
||||
|
||||
/* Test all elements for either exact match or abbreviated matches. */
|
||||
for (i = 0; arglist[i]; i++)
|
||||
{
|
||||
if (!strncmp (arglist[i], arg, arglen))
|
||||
{
|
||||
if (strlen (arglist[i]) == arglen)
|
||||
/* Exact match found. */
|
||||
return i;
|
||||
else if (matchind == -1)
|
||||
/* First nonexact match found. */
|
||||
matchind = i;
|
||||
else
|
||||
{
|
||||
/* Second nonexact match found. */
|
||||
if (vallist == NULL
|
||||
|| memcmp ((char const *) vallist + valsize * matchind,
|
||||
(char const *) vallist + valsize * i, valsize))
|
||||
{
|
||||
/* There is a real ambiguity, or we could not
|
||||
disambiguate. */
|
||||
ambiguous = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ambiguous)
|
||||
return -2;
|
||||
else
|
||||
return matchind;
|
||||
}
|
||||
|
||||
/* Error reporting for argmatch.
|
||||
CONTEXT is a description of the type of entity that was being matched.
|
||||
VALUE is the invalid value that was given.
|
||||
PROBLEM is the return value from argmatch. */
|
||||
|
||||
void
|
||||
argmatch_invalid (const char *context, const char *value, ptrdiff_t problem)
|
||||
{
|
||||
char const *format = (problem == -1
|
||||
? _("invalid argument %s for %s")
|
||||
: _("ambiguous argument %s for %s"));
|
||||
|
||||
error (0, 0, format, quotearg_n_style (0, ARGMATCH_QUOTING_STYLE, value),
|
||||
quote_n (1, context));
|
||||
}
|
||||
|
||||
/* List the valid arguments for argmatch.
|
||||
ARGLIST is the same as in argmatch.
|
||||
VALLIST is a pointer to an array of values.
|
||||
VALSIZE is the size of the elements of VALLIST */
|
||||
void
|
||||
argmatch_valid (const char *const *arglist,
|
||||
const void *vallist, size_t valsize)
|
||||
{
|
||||
size_t i;
|
||||
const char *last_val = NULL;
|
||||
|
||||
/* We try to put synonyms on the same line. The assumption is that
|
||||
synonyms follow each other */
|
||||
fputs (_("Valid arguments are:"), stderr);
|
||||
for (i = 0; arglist[i]; i++)
|
||||
if ((i == 0)
|
||||
|| memcmp (last_val, (char const *) vallist + valsize * i, valsize))
|
||||
{
|
||||
fprintf (stderr, "\n - %s", quote (arglist[i]));
|
||||
last_val = (char const *) vallist + valsize * i;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, ", %s", quote (arglist[i]));
|
||||
}
|
||||
putc ('\n', stderr);
|
||||
}
|
||||
|
||||
/* Never failing versions of the previous functions.
|
||||
|
||||
CONTEXT is the context for which argmatch is called (e.g.,
|
||||
"--version-control", or "$VERSION_CONTROL" etc.). Upon failure,
|
||||
calls the (supposed never to return) function EXIT_FN. */
|
||||
|
||||
ptrdiff_t
|
||||
__xargmatch_internal (const char *context,
|
||||
const char *arg, const char *const *arglist,
|
||||
const void *vallist, size_t valsize,
|
||||
argmatch_exit_fn exit_fn)
|
||||
{
|
||||
ptrdiff_t res = argmatch (arg, arglist, vallist, valsize);
|
||||
if (res >= 0)
|
||||
/* Success. */
|
||||
return res;
|
||||
|
||||
/* We failed. Explain why. */
|
||||
argmatch_invalid (context, arg, res);
|
||||
argmatch_valid (arglist, vallist, valsize);
|
||||
(*exit_fn) ();
|
||||
|
||||
return -1; /* To please the compilers. */
|
||||
}
|
||||
|
||||
/* Look for VALUE in VALLIST, an array of objects of size VALSIZE and
|
||||
return the first corresponding argument in ARGLIST */
|
||||
const char *
|
||||
argmatch_to_argument (const void *value,
|
||||
const char *const *arglist,
|
||||
const void *vallist, size_t valsize)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; arglist[i]; i++)
|
||||
if (!memcmp (value, (char const *) vallist + valsize * i, valsize))
|
||||
return arglist[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
/*
|
||||
* Based on "getversion.c" by David MacKenzie <djm@gnu.ai.mit.edu>
|
||||
*/
|
||||
|
||||
/* When to make backup files. */
|
||||
enum backup_type
|
||||
{
|
||||
/* Never make backups. */
|
||||
no_backups,
|
||||
|
||||
/* Make simple backups of every file. */
|
||||
simple_backups,
|
||||
|
||||
/* Make numbered backups of files that already have numbered backups,
|
||||
and simple backups of the others. */
|
||||
numbered_existing_backups,
|
||||
|
||||
/* Make numbered backups of every file. */
|
||||
numbered_backups
|
||||
};
|
||||
|
||||
/* Two tables describing arguments (keys) and their corresponding
|
||||
values */
|
||||
static const char *const backup_args[] =
|
||||
{
|
||||
"no", "none", "off",
|
||||
"simple", "never",
|
||||
"existing", "nil",
|
||||
"numbered", "t",
|
||||
0
|
||||
};
|
||||
|
||||
static const enum backup_type backup_vals[] =
|
||||
{
|
||||
no_backups, no_backups, no_backups,
|
||||
simple_backups, simple_backups,
|
||||
numbered_existing_backups, numbered_existing_backups,
|
||||
numbered_backups, numbered_backups
|
||||
};
|
||||
|
||||
int
|
||||
main (int argc, const char *const *argv)
|
||||
{
|
||||
const char *cp;
|
||||
enum backup_type backup_type = no_backups;
|
||||
|
||||
if (argc > 2)
|
||||
{
|
||||
fprintf (stderr, "Usage: %s [VERSION_CONTROL]\n", getprogname ());
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if ((cp = getenv ("VERSION_CONTROL")))
|
||||
backup_type = XARGMATCH ("$VERSION_CONTROL", cp,
|
||||
backup_args, backup_vals);
|
||||
|
||||
if (argc == 2)
|
||||
backup_type = XARGMATCH (getprogname (), argv[1],
|
||||
backup_args, backup_vals);
|
||||
|
||||
printf ("The version control is '%s'\n",
|
||||
ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
331
lib/argmatch.h
Normal file
331
lib/argmatch.h
Normal file
@@ -0,0 +1,331 @@
|
||||
/* argmatch.h -- definitions and prototypes for argmatch.c
|
||||
|
||||
Copyright (C) 1990, 1998-1999, 2001-2002, 2004-2005, 2009-2020 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by David MacKenzie <djm@ai.mit.edu>
|
||||
Modified by Akim Demaille <demaille@inf.enst.fr> */
|
||||
|
||||
#ifndef ARGMATCH_H_
|
||||
# define ARGMATCH_H_ 1
|
||||
|
||||
# include <limits.h>
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdio.h>
|
||||
# include <string.h> /* memcmp */
|
||||
|
||||
# include "gettext.h"
|
||||
# include "quote.h"
|
||||
# include "verify.h"
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
# define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
|
||||
|
||||
/* Assert there are as many real arguments as there are values
|
||||
(argument list ends with a NULL guard). */
|
||||
|
||||
# define ARGMATCH_VERIFY(Arglist, Vallist) \
|
||||
verify (ARRAY_CARDINALITY (Arglist) == ARRAY_CARDINALITY (Vallist) + 1)
|
||||
|
||||
/* Return the index of the element of ARGLIST (NULL terminated) that
|
||||
matches with ARG. If VALLIST is not NULL, then use it to resolve
|
||||
false ambiguities (i.e., different matches of ARG but corresponding
|
||||
to the same values in VALLIST). */
|
||||
|
||||
ptrdiff_t argmatch (char const *arg, char const *const *arglist,
|
||||
void const *vallist, size_t valsize) _GL_ATTRIBUTE_PURE;
|
||||
|
||||
# define ARGMATCH(Arg, Arglist, Vallist) \
|
||||
argmatch (Arg, Arglist, (void const *) (Vallist), sizeof *(Vallist))
|
||||
|
||||
/* xargmatch calls this function when it fails. This function should not
|
||||
return. By default, this is a function that calls ARGMATCH_DIE which
|
||||
in turn defaults to 'exit (exit_failure)'. */
|
||||
typedef void (*argmatch_exit_fn) (void);
|
||||
extern argmatch_exit_fn argmatch_die;
|
||||
|
||||
/* Report on stderr why argmatch failed. Report correct values. */
|
||||
|
||||
void argmatch_invalid (char const *context, char const *value,
|
||||
ptrdiff_t problem);
|
||||
|
||||
/* Left for compatibility with the old name invalid_arg */
|
||||
|
||||
# define invalid_arg(Context, Value, Problem) \
|
||||
argmatch_invalid (Context, Value, Problem)
|
||||
|
||||
|
||||
|
||||
/* Report on stderr the list of possible arguments. */
|
||||
|
||||
void argmatch_valid (char const *const *arglist,
|
||||
void const *vallist, size_t valsize);
|
||||
|
||||
# define ARGMATCH_VALID(Arglist, Vallist) \
|
||||
argmatch_valid (Arglist, (void const *) (Vallist), sizeof *(Vallist))
|
||||
|
||||
|
||||
|
||||
/* Same as argmatch, but upon failure, report an explanation of the
|
||||
failure, and exit using the function EXIT_FN. */
|
||||
|
||||
ptrdiff_t __xargmatch_internal (char const *context,
|
||||
char const *arg, char const *const *arglist,
|
||||
void const *vallist, size_t valsize,
|
||||
argmatch_exit_fn exit_fn);
|
||||
|
||||
/* Programmer friendly interface to __xargmatch_internal. */
|
||||
|
||||
# define XARGMATCH(Context, Arg, Arglist, Vallist) \
|
||||
((Vallist) [__xargmatch_internal (Context, Arg, Arglist, \
|
||||
(void const *) (Vallist), \
|
||||
sizeof *(Vallist), \
|
||||
argmatch_die)])
|
||||
|
||||
/* Convert a value into a corresponding argument. */
|
||||
|
||||
char const *argmatch_to_argument (void const *value,
|
||||
char const *const *arglist,
|
||||
void const *vallist, size_t valsize)
|
||||
_GL_ATTRIBUTE_PURE;
|
||||
|
||||
# define ARGMATCH_TO_ARGUMENT(Value, Arglist, Vallist) \
|
||||
argmatch_to_argument (Value, Arglist, \
|
||||
(void const *) (Vallist), sizeof *(Vallist))
|
||||
|
||||
# define ARGMATCH_DEFINE_GROUP(Name, Type) \
|
||||
/* The type of the values of this group. */ \
|
||||
typedef Type argmatch_##Name##_type; \
|
||||
\
|
||||
/* The size of the type of the values of this group. */ \
|
||||
enum argmatch_##Name##_size_enum \
|
||||
{ \
|
||||
argmatch_##Name##_size = sizeof (argmatch_##Name##_type) \
|
||||
}; \
|
||||
\
|
||||
/* Argument mapping of this group. */ \
|
||||
typedef struct \
|
||||
{ \
|
||||
/* Argument (e.g., "simple"). */ \
|
||||
const char *arg; \
|
||||
/* Value (e.g., simple_backups). */ \
|
||||
const argmatch_##Name##_type val; \
|
||||
} argmatch_##Name##_arg; \
|
||||
\
|
||||
/* Documentation of this group. */ \
|
||||
typedef struct \
|
||||
{ \
|
||||
/* Argument (e.g., "simple"). */ \
|
||||
const char *arg; \
|
||||
/* Documentation (e.g., N_("always make simple backups")). */ \
|
||||
const char *doc; \
|
||||
} argmatch_##Name##_doc; \
|
||||
\
|
||||
/* All the features of an argmatch group. */ \
|
||||
typedef struct \
|
||||
{ \
|
||||
const argmatch_##Name##_arg* args; \
|
||||
const argmatch_##Name##_doc* docs; \
|
||||
\
|
||||
/* Printed before the usage message. */ \
|
||||
const char *doc_pre; \
|
||||
/* Printed after the usage message. */ \
|
||||
const char *doc_post; \
|
||||
} argmatch_##Name##_group_type; \
|
||||
\
|
||||
/* The structure the user must build. */ \
|
||||
extern const argmatch_##Name##_group_type argmatch_##Name##_group; \
|
||||
\
|
||||
/* Print the documentation of this group. */ \
|
||||
void argmatch_##Name##_usage (FILE *out); \
|
||||
\
|
||||
/* If nonnegative, the index I of ARG in ARGS, i.e, \
|
||||
ARGS[I] == ARG. \
|
||||
Return -1 for invalid argument, -2 for ambiguous argument. */ \
|
||||
ptrdiff_t argmatch_##Name##_choice (const char *arg); \
|
||||
\
|
||||
/* A pointer to the corresponding value if it exists, or \
|
||||
report an error and exit with failure if the argument was \
|
||||
not recognized. */ \
|
||||
const argmatch_##Name##_type* \
|
||||
argmatch_##Name##_value (const char *context, const char *arg); \
|
||||
\
|
||||
/* The first argument in ARGS that matches this value, or NULL. */ \
|
||||
const char * \
|
||||
argmatch_##Name##_argument (const argmatch_##Name##_type *val); \
|
||||
\
|
||||
ptrdiff_t \
|
||||
argmatch_##Name##_choice (const char *arg) \
|
||||
{ \
|
||||
const argmatch_##Name##_group_type *g = &argmatch_##Name##_group; \
|
||||
size_t size = argmatch_##Name##_size; \
|
||||
ptrdiff_t res = -1; /* Index of first nonexact match. */ \
|
||||
bool ambiguous = false; /* Whether multiple nonexact match(es). */ \
|
||||
size_t arglen = strlen (arg); \
|
||||
\
|
||||
/* Test all elements for either exact match or abbreviated \
|
||||
matches. */ \
|
||||
for (size_t i = 0; g->args[i].arg; i++) \
|
||||
if (!strncmp (g->args[i].arg, arg, arglen)) \
|
||||
{ \
|
||||
if (strlen (g->args[i].arg) == arglen) \
|
||||
/* Exact match found. */ \
|
||||
return i; \
|
||||
else if (res == -1) \
|
||||
/* First nonexact match found. */ \
|
||||
res = i; \
|
||||
else if (memcmp (&g->args[res].val, &g->args[i].val, size)) \
|
||||
/* Second nonexact match found. */ \
|
||||
/* There is a real ambiguity, or we could not \
|
||||
disambiguate. */ \
|
||||
ambiguous = true; \
|
||||
} \
|
||||
return ambiguous ? -2 : res; \
|
||||
} \
|
||||
\
|
||||
const char * \
|
||||
argmatch_##Name##_argument (const argmatch_##Name##_type *val) \
|
||||
{ \
|
||||
const argmatch_##Name##_group_type *g = &argmatch_##Name##_group; \
|
||||
size_t size = argmatch_##Name##_size; \
|
||||
for (size_t i = 0; g->args[i].arg; i++) \
|
||||
if (!memcmp (val, &g->args[i].val, size)) \
|
||||
return g->args[i].arg; \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
/* List the valid values of this group. */ \
|
||||
static void \
|
||||
argmatch_##Name##_valid (FILE *out) \
|
||||
{ \
|
||||
const argmatch_##Name##_group_type *g = &argmatch_##Name##_group; \
|
||||
size_t size = argmatch_##Name##_size; \
|
||||
\
|
||||
/* Try to put synonyms on the same line. Synonyms are expected \
|
||||
to follow each other. */ \
|
||||
fputs (gettext ("Valid arguments are:"), out); \
|
||||
for (int i = 0; g->args[i].arg; i++) \
|
||||
if (i == 0 \
|
||||
|| memcmp (&g->args[i-1].val, &g->args[i].val, size)) \
|
||||
fprintf (out, "\n - %s", quote (g->args[i].arg)); \
|
||||
else \
|
||||
fprintf (out, ", %s", quote (g->args[i].arg)); \
|
||||
putc ('\n', out); \
|
||||
} \
|
||||
\
|
||||
const argmatch_##Name##_type* \
|
||||
argmatch_##Name##_value (const char *context, const char *arg) \
|
||||
{ \
|
||||
const argmatch_##Name##_group_type *g = &argmatch_##Name##_group; \
|
||||
ptrdiff_t res = argmatch_##Name##_choice (arg); \
|
||||
if (res < 0) \
|
||||
{ \
|
||||
argmatch_invalid (context, arg, res); \
|
||||
argmatch_##Name##_valid (stderr); \
|
||||
argmatch_die (); \
|
||||
} \
|
||||
return &g->args[res].val; \
|
||||
} \
|
||||
\
|
||||
/* The column in which the documentation is displayed. \
|
||||
The leftmost possible, but no more than 20. */ \
|
||||
static int \
|
||||
argmatch_##Name##_doc_col (void) \
|
||||
{ \
|
||||
const argmatch_##Name##_group_type *g = &argmatch_##Name##_group; \
|
||||
size_t size = argmatch_##Name##_size; \
|
||||
int res = 0; \
|
||||
for (int i = 0; g->docs[i].arg; ++i) \
|
||||
{ \
|
||||
int col = 4; \
|
||||
int ival = argmatch_##Name##_choice (g->docs[i].arg); \
|
||||
if (ival < 0) \
|
||||
/* Pseudo argument, display it. */ \
|
||||
col += strlen (g->docs[i].arg); \
|
||||
else \
|
||||
/* Genuine argument, display it with its synonyms. */ \
|
||||
for (int j = 0; g->args[j].arg; ++j) \
|
||||
if (! memcmp (&g->args[ival].val, &g->args[j].val, size)) \
|
||||
col += (col == 4 ? 0 : 2) + strlen (g->args[j].arg); \
|
||||
if (res <= col) \
|
||||
res = col <= 20 ? col : 20; \
|
||||
} \
|
||||
return res ? res : 20; \
|
||||
} \
|
||||
\
|
||||
void \
|
||||
argmatch_##Name##_usage (FILE *out) \
|
||||
{ \
|
||||
const argmatch_##Name##_group_type *g = &argmatch_##Name##_group; \
|
||||
size_t size = argmatch_##Name##_size; \
|
||||
/* Width of the screen. Help2man does not seem to support \
|
||||
arguments on several lines, so in that case pretend a very \
|
||||
large width. */ \
|
||||
const int screen_width = getenv ("HELP2MAN") ? INT_MAX : 80; \
|
||||
if (g->doc_pre) \
|
||||
fprintf (out, "%s\n", gettext (g->doc_pre)); \
|
||||
int doc_col = argmatch_##Name##_doc_col (); \
|
||||
for (int i = 0; g->docs[i].arg; ++i) \
|
||||
{ \
|
||||
int col = 0; \
|
||||
bool first = true; \
|
||||
int ival = argmatch_##Name##_choice (g->docs[i].arg); \
|
||||
if (ival < 0) \
|
||||
/* Pseudo argument, display it. */ \
|
||||
col += fprintf (out, " %s", g->docs[i].arg); \
|
||||
else \
|
||||
/* Genuine argument, display it with its synonyms. */ \
|
||||
for (int j = 0; g->args[j].arg; ++j) \
|
||||
if (! memcmp (&g->args[ival].val, &g->args[j].val, size)) \
|
||||
{ \
|
||||
if (!first \
|
||||
&& screen_width < col + 2 + strlen (g->args[j].arg)) \
|
||||
{ \
|
||||
fprintf (out, ",\n"); \
|
||||
col = 0; \
|
||||
first = true; \
|
||||
} \
|
||||
if (first) \
|
||||
{ \
|
||||
col += fprintf (out, " "); \
|
||||
first = false; \
|
||||
} \
|
||||
else \
|
||||
col += fprintf (out, ","); \
|
||||
col += fprintf (out, " %s", g->args[j].arg); \
|
||||
} \
|
||||
/* The doc. Separated by at least two spaces. */ \
|
||||
if (doc_col < col + 2) \
|
||||
{ \
|
||||
fprintf (out, "\n"); \
|
||||
col = 0; \
|
||||
} \
|
||||
fprintf (out, "%*s%s\n", \
|
||||
doc_col - col, "", gettext (g->docs[i].doc)); \
|
||||
} \
|
||||
if (g->doc_post) \
|
||||
fprintf (out, "%s\n", gettext (g->doc_post)); \
|
||||
}
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif /* ARGMATCH_H_ */
|
||||
111
lib/argv-iter.c
Normal file
111
lib/argv-iter.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/* Iterate over arguments from argv or --files0-from=FILE
|
||||
Copyright (C) 2008-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Jim Meyering. */
|
||||
|
||||
#include <config.h>
|
||||
#include "argv-iter.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct argv_iterator
|
||||
{
|
||||
/* Test FP to determine whether in read-mode or argv-mode. */
|
||||
/* file-mode: fp records position */
|
||||
FILE *fp;
|
||||
size_t item_idx;
|
||||
char *tok;
|
||||
size_t buf_len;
|
||||
|
||||
/* argv-mode: record just argv and current pointer */
|
||||
char **arg_list;
|
||||
char **p;
|
||||
};
|
||||
|
||||
struct argv_iterator *
|
||||
argv_iter_init_argv (char **argv)
|
||||
{
|
||||
struct argv_iterator *ai = malloc (sizeof *ai);
|
||||
if (!ai)
|
||||
return NULL;
|
||||
ai->fp = NULL;
|
||||
ai->arg_list = argv;
|
||||
ai->p = argv;
|
||||
return ai;
|
||||
}
|
||||
|
||||
/* Initialize to read from the stream, FP.
|
||||
The input is expected to contain a list of NUL-delimited tokens. */
|
||||
struct argv_iterator *
|
||||
argv_iter_init_stream (FILE *fp)
|
||||
{
|
||||
struct argv_iterator *ai = malloc (sizeof *ai);
|
||||
if (!ai)
|
||||
return NULL;
|
||||
ai->fp = fp;
|
||||
ai->tok = NULL;
|
||||
ai->buf_len = 0;
|
||||
|
||||
ai->item_idx = 0;
|
||||
ai->arg_list = NULL;
|
||||
return ai;
|
||||
}
|
||||
|
||||
char *
|
||||
argv_iter (struct argv_iterator *ai, enum argv_iter_err *err)
|
||||
{
|
||||
if (ai->fp)
|
||||
{
|
||||
ssize_t len = getdelim (&ai->tok, &ai->buf_len, '\0', ai->fp);
|
||||
if (len < 0)
|
||||
{
|
||||
*err = feof (ai->fp) ? AI_ERR_EOF : AI_ERR_READ;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*err = AI_ERR_OK;
|
||||
ai->item_idx++;
|
||||
return ai->tok;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*(ai->p) == NULL)
|
||||
{
|
||||
*err = AI_ERR_EOF;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*err = AI_ERR_OK;
|
||||
return *(ai->p++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
argv_iter_n_args (struct argv_iterator const *ai)
|
||||
{
|
||||
return ai->fp ? ai->item_idx : ai->p - ai->arg_list;
|
||||
}
|
||||
|
||||
void
|
||||
argv_iter_free (struct argv_iterator *ai)
|
||||
{
|
||||
if (ai->fp)
|
||||
free (ai->tok);
|
||||
free (ai);
|
||||
}
|
||||
42
lib/argv-iter.h
Normal file
42
lib/argv-iter.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* Iterate over arguments from argv or --files0-from=FILE
|
||||
Copyright (C) 2008-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Definition of _GL_ARG_NONNULL. */
|
||||
#include "arg-nonnull.h"
|
||||
|
||||
struct argv_iterator;
|
||||
|
||||
enum argv_iter_err
|
||||
{
|
||||
AI_ERR_OK = 1,
|
||||
AI_ERR_EOF,
|
||||
AI_ERR_MEM,
|
||||
AI_ERR_READ
|
||||
};
|
||||
|
||||
struct argv_iterator *argv_iter_init_argv (char **argv)
|
||||
_GL_ARG_NONNULL ((1));
|
||||
struct argv_iterator *argv_iter_init_stream (FILE *fp)
|
||||
_GL_ARG_NONNULL ((1));
|
||||
char *argv_iter (struct argv_iterator *, enum argv_iter_err *)
|
||||
_GL_ARG_NONNULL ((1, 2));
|
||||
size_t argv_iter_n_args (struct argv_iterator const *)
|
||||
_GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1));
|
||||
void argv_iter_free (struct argv_iterator *)
|
||||
_GL_ARG_NONNULL ((1));
|
||||
621
lib/arpa/inet.h
Normal file
621
lib/arpa/inet.h
Normal file
@@ -0,0 +1,621 @@
|
||||
/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||||
/* A GNU-like <arpa/inet.h>.
|
||||
|
||||
Copyright (C) 2005-2006, 2008-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _GL_ARPA_INET_H
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
|
||||
#if 1
|
||||
# include <features.h> /* for __GLIBC__ */
|
||||
#endif
|
||||
|
||||
/* Gnulib's sys/socket.h is responsible for defining socklen_t (used below) and
|
||||
for pulling in winsock2.h etc. under MinGW.
|
||||
But avoid namespace pollution on glibc systems. */
|
||||
#ifndef __GLIBC__
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
/* On NonStop Kernel, inet_ntop and inet_pton are declared in <netdb.h>.
|
||||
But avoid namespace pollution on glibc systems. */
|
||||
#if defined __TANDEM && !defined __GLIBC__
|
||||
# include <netdb.h>
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
|
||||
/* The include_next requires a split double-inclusion guard. */
|
||||
# include_next <arpa/inet.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef _GL_ARPA_INET_H
|
||||
#define _GL_ARPA_INET_H
|
||||
|
||||
/* Get all possible declarations of inet_ntop() and inet_pton(). */
|
||||
#if (1 || IN_COREUTILS_GNULIB_TESTS || defined GNULIB_POSIXCHECK) \
|
||||
&& 0
|
||||
# include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
|
||||
/* C++ compatible function declaration macros.
|
||||
Copyright (C) 2010-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _GL_CXXDEFS_H
|
||||
#define _GL_CXXDEFS_H
|
||||
|
||||
/* Begin/end the GNULIB_NAMESPACE namespace. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_BEGIN_NAMESPACE namespace GNULIB_NAMESPACE {
|
||||
# define _GL_END_NAMESPACE }
|
||||
#else
|
||||
# define _GL_BEGIN_NAMESPACE
|
||||
# define _GL_END_NAMESPACE
|
||||
#endif
|
||||
|
||||
/* The three most frequent use cases of these macros are:
|
||||
|
||||
* For providing a substitute for a function that is missing on some
|
||||
platforms, but is declared and works fine on the platforms on which
|
||||
it exists:
|
||||
|
||||
#if @GNULIB_FOO@
|
||||
# if !@HAVE_FOO@
|
||||
_GL_FUNCDECL_SYS (foo, ...);
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (foo, ...);
|
||||
_GL_CXXALIASWARN (foo);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
...
|
||||
#endif
|
||||
|
||||
* For providing a replacement for a function that exists on all platforms,
|
||||
but is broken/insufficient and needs to be replaced on some platforms:
|
||||
|
||||
#if @GNULIB_FOO@
|
||||
# if @REPLACE_FOO@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef foo
|
||||
# define foo rpl_foo
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (foo, ...);
|
||||
_GL_CXXALIAS_RPL (foo, ...);
|
||||
# else
|
||||
_GL_CXXALIAS_SYS (foo, ...);
|
||||
# endif
|
||||
_GL_CXXALIASWARN (foo);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
...
|
||||
#endif
|
||||
|
||||
* For providing a replacement for a function that exists on some platforms
|
||||
but is broken/insufficient and needs to be replaced on some of them and
|
||||
is additionally either missing or undeclared on some other platforms:
|
||||
|
||||
#if @GNULIB_FOO@
|
||||
# if @REPLACE_FOO@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef foo
|
||||
# define foo rpl_foo
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (foo, ...);
|
||||
_GL_CXXALIAS_RPL (foo, ...);
|
||||
# else
|
||||
# if !@HAVE_FOO@ or if !@HAVE_DECL_FOO@
|
||||
_GL_FUNCDECL_SYS (foo, ...);
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (foo, ...);
|
||||
# endif
|
||||
_GL_CXXALIASWARN (foo);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
...
|
||||
#endif
|
||||
*/
|
||||
|
||||
/* _GL_EXTERN_C declaration;
|
||||
performs the declaration with C linkage. */
|
||||
#if defined __cplusplus
|
||||
# define _GL_EXTERN_C extern "C"
|
||||
#else
|
||||
# define _GL_EXTERN_C extern
|
||||
#endif
|
||||
|
||||
/* _GL_FUNCDECL_RPL (func, rettype, parameters_and_attributes);
|
||||
declares a replacement function, named rpl_func, with the given prototype,
|
||||
consisting of return type, parameters, and attributes.
|
||||
Example:
|
||||
_GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...)
|
||||
_GL_ARG_NONNULL ((1)));
|
||||
*/
|
||||
#define _GL_FUNCDECL_RPL(func,rettype,parameters_and_attributes) \
|
||||
_GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters_and_attributes)
|
||||
#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters_and_attributes) \
|
||||
_GL_EXTERN_C rettype rpl_func parameters_and_attributes
|
||||
|
||||
/* _GL_FUNCDECL_SYS (func, rettype, parameters_and_attributes);
|
||||
declares the system function, named func, with the given prototype,
|
||||
consisting of return type, parameters, and attributes.
|
||||
Example:
|
||||
_GL_FUNCDECL_SYS (open, int, (const char *filename, int flags, ...)
|
||||
_GL_ARG_NONNULL ((1)));
|
||||
*/
|
||||
#define _GL_FUNCDECL_SYS(func,rettype,parameters_and_attributes) \
|
||||
_GL_EXTERN_C rettype func parameters_and_attributes
|
||||
|
||||
/* _GL_CXXALIAS_RPL (func, rettype, parameters);
|
||||
declares a C++ alias called GNULIB_NAMESPACE::func
|
||||
that redirects to rpl_func, if GNULIB_NAMESPACE is defined.
|
||||
Example:
|
||||
_GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...));
|
||||
|
||||
Wrapping rpl_func in an object with an inline conversion operator
|
||||
avoids a reference to rpl_func unless GNULIB_NAMESPACE::func is
|
||||
actually used in the program. */
|
||||
#define _GL_CXXALIAS_RPL(func,rettype,parameters) \
|
||||
_GL_CXXALIAS_RPL_1 (func, rpl_##func, rettype, parameters)
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return ::rpl_func; \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIAS_RPL_CAST_1 (func, rpl_func, rettype, parameters);
|
||||
is like _GL_CXXALIAS_RPL_1 (func, rpl_func, rettype, parameters);
|
||||
except that the C function rpl_func may have a slightly different
|
||||
declaration. A cast is used to silence the "invalid conversion" error
|
||||
that would otherwise occur. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return reinterpret_cast<type>(::rpl_func); \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIAS_SYS (func, rettype, parameters);
|
||||
declares a C++ alias called GNULIB_NAMESPACE::func
|
||||
that redirects to the system provided function func, if GNULIB_NAMESPACE
|
||||
is defined.
|
||||
Example:
|
||||
_GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));
|
||||
|
||||
Wrapping func in an object with an inline conversion operator
|
||||
avoids a reference to func unless GNULIB_NAMESPACE::func is
|
||||
actually used in the program. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return ::func; \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIAS_SYS_CAST (func, rettype, parameters);
|
||||
is like _GL_CXXALIAS_SYS (func, rettype, parameters);
|
||||
except that the C function func may have a slightly different declaration.
|
||||
A cast is used to silence the "invalid conversion" error that would
|
||||
otherwise occur. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return reinterpret_cast<type>(::func); \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIAS_SYS_CAST2 (func, rettype, parameters, rettype2, parameters2);
|
||||
is like _GL_CXXALIAS_SYS (func, rettype, parameters);
|
||||
except that the C function is picked among a set of overloaded functions,
|
||||
namely the one with rettype2 and parameters2. Two consecutive casts
|
||||
are used to silence the "cannot find a match" and "invalid conversion"
|
||||
errors that would otherwise occur. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
/* The outer cast must be a reinterpret_cast.
|
||||
The inner cast: When the function is defined as a set of overloaded
|
||||
functions, it works as a static_cast<>, choosing the designated variant.
|
||||
When the function is defined as a single variant, it works as a
|
||||
reinterpret_cast<>. The parenthesized cast syntax works both ways. */
|
||||
# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return reinterpret_cast<type>((rettype2 (*) parameters2)(::func)); \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIASWARN (func);
|
||||
causes a warning to be emitted when ::func is used but not when
|
||||
GNULIB_NAMESPACE::func is used. func must be defined without overloaded
|
||||
variants. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIASWARN(func) \
|
||||
_GL_CXXALIASWARN_1 (func, GNULIB_NAMESPACE)
|
||||
# define _GL_CXXALIASWARN_1(func,namespace) \
|
||||
_GL_CXXALIASWARN_2 (func, namespace)
|
||||
/* To work around GCC bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43881>,
|
||||
we enable the warning only when not optimizing. */
|
||||
# if !__OPTIMIZE__
|
||||
# define _GL_CXXALIASWARN_2(func,namespace) \
|
||||
_GL_WARN_ON_USE (func, \
|
||||
"The symbol ::" #func " refers to the system function. " \
|
||||
"Use " #namespace "::" #func " instead.")
|
||||
# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
|
||||
# define _GL_CXXALIASWARN_2(func,namespace) \
|
||||
extern __typeof__ (func) func
|
||||
# else
|
||||
# define _GL_CXXALIASWARN_2(func,namespace) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
# endif
|
||||
#else
|
||||
# define _GL_CXXALIASWARN(func) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIASWARN1 (func, rettype, parameters_and_attributes);
|
||||
causes a warning to be emitted when the given overloaded variant of ::func
|
||||
is used but not when GNULIB_NAMESPACE::func is used. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
|
||||
_GL_CXXALIASWARN1_1 (func, rettype, parameters_and_attributes, \
|
||||
GNULIB_NAMESPACE)
|
||||
# define _GL_CXXALIASWARN1_1(func,rettype,parameters_and_attributes,namespace) \
|
||||
_GL_CXXALIASWARN1_2 (func, rettype, parameters_and_attributes, namespace)
|
||||
/* To work around GCC bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43881>,
|
||||
we enable the warning only when not optimizing. */
|
||||
# if !__OPTIMIZE__
|
||||
# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
|
||||
_GL_WARN_ON_USE_CXX (func, rettype, parameters_and_attributes, \
|
||||
"The symbol ::" #func " refers to the system function. " \
|
||||
"Use " #namespace "::" #func " instead.")
|
||||
# else
|
||||
# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
# endif
|
||||
#else
|
||||
# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
#endif /* _GL_CXXDEFS_H */
|
||||
|
||||
/* The definition of _GL_ARG_NONNULL is copied here. */
|
||||
/* A C macro for declaring that specific arguments must not be NULL.
|
||||
Copyright (C) 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* _GL_ARG_NONNULL((n,...,m)) tells the compiler and static analyzer tools
|
||||
that the values passed as arguments n, ..., m must be non-NULL pointers.
|
||||
n = 1 stands for the first argument, n = 2 for the second argument etc. */
|
||||
#ifndef _GL_ARG_NONNULL
|
||||
# if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ > 3
|
||||
# define _GL_ARG_NONNULL(params) __attribute__ ((__nonnull__ params))
|
||||
# else
|
||||
# define _GL_ARG_NONNULL(params)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The definition of _GL_WARN_ON_USE is copied here. */
|
||||
/* A C macro for emitting warnings if a function is used.
|
||||
Copyright (C) 2010-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* _GL_WARN_ON_USE (function, "literal string") issues a declaration
|
||||
for FUNCTION which will then trigger a compiler warning containing
|
||||
the text of "literal string" anywhere that function is called, if
|
||||
supported by the compiler. If the compiler does not support this
|
||||
feature, the macro expands to an unused extern declaration.
|
||||
|
||||
_GL_WARN_ON_USE_ATTRIBUTE ("literal string") expands to the
|
||||
attribute used in _GL_WARN_ON_USE. If the compiler does not support
|
||||
this feature, it expands to empty.
|
||||
|
||||
These macros are useful for marking a function as a potential
|
||||
portability trap, with the intent that "literal string" include
|
||||
instructions on the replacement function that should be used
|
||||
instead.
|
||||
_GL_WARN_ON_USE is for functions with 'extern' linkage.
|
||||
_GL_WARN_ON_USE_ATTRIBUTE is for functions with 'static' or 'inline'
|
||||
linkage.
|
||||
|
||||
However, one of the reasons that a function is a portability trap is
|
||||
if it has the wrong signature. Declaring FUNCTION with a different
|
||||
signature in C is a compilation error, so this macro must use the
|
||||
same type as any existing declaration so that programs that avoid
|
||||
the problematic FUNCTION do not fail to compile merely because they
|
||||
included a header that poisoned the function. But this implies that
|
||||
_GL_WARN_ON_USE is only safe to use if FUNCTION is known to already
|
||||
have a declaration. Use of this macro implies that there must not
|
||||
be any other macro hiding the declaration of FUNCTION; but
|
||||
undefining FUNCTION first is part of the poisoning process anyway
|
||||
(although for symbols that are provided only via a macro, the result
|
||||
is a compilation error rather than a warning containing
|
||||
"literal string"). Also note that in C++, it is only safe to use if
|
||||
FUNCTION has no overloads.
|
||||
|
||||
For an example, it is possible to poison 'getline' by:
|
||||
- adding a call to gl_WARN_ON_USE_PREPARE([[#include <stdio.h>]],
|
||||
[getline]) in configure.ac, which potentially defines
|
||||
HAVE_RAW_DECL_GETLINE
|
||||
- adding this code to a header that wraps the system <stdio.h>:
|
||||
#undef getline
|
||||
#if HAVE_RAW_DECL_GETLINE
|
||||
_GL_WARN_ON_USE (getline, "getline is required by POSIX 2008, but"
|
||||
"not universally present; use the gnulib module getline");
|
||||
#endif
|
||||
|
||||
It is not possible to directly poison global variables. But it is
|
||||
possible to write a wrapper accessor function, and poison that
|
||||
(less common usage, like &environ, will cause a compilation error
|
||||
rather than issue the nice warning, but the end result of informing
|
||||
the developer about their portability problem is still achieved):
|
||||
#if HAVE_RAW_DECL_ENVIRON
|
||||
static char ***
|
||||
rpl_environ (void) { return &environ; }
|
||||
_GL_WARN_ON_USE (rpl_environ, "environ is not always properly declared");
|
||||
# undef environ
|
||||
# define environ (*rpl_environ ())
|
||||
#endif
|
||||
or better (avoiding contradictory use of 'static' and 'extern'):
|
||||
#if HAVE_RAW_DECL_ENVIRON
|
||||
static char ***
|
||||
_GL_WARN_ON_USE_ATTRIBUTE ("environ is not always properly declared")
|
||||
rpl_environ (void) { return &environ; }
|
||||
# undef environ
|
||||
# define environ (*rpl_environ ())
|
||||
#endif
|
||||
*/
|
||||
#ifndef _GL_WARN_ON_USE
|
||||
|
||||
# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)
|
||||
/* A compiler attribute is available in gcc versions 4.3.0 and later. */
|
||||
# define _GL_WARN_ON_USE(function, message) \
|
||||
extern __typeof__ (function) function __attribute__ ((__warning__ (message)))
|
||||
# define _GL_WARN_ON_USE_ATTRIBUTE(message) \
|
||||
__attribute__ ((__warning__ (message)))
|
||||
# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
|
||||
/* Verify the existence of the function. */
|
||||
# define _GL_WARN_ON_USE(function, message) \
|
||||
extern __typeof__ (function) function
|
||||
# define _GL_WARN_ON_USE_ATTRIBUTE(message)
|
||||
# else /* Unsupported. */
|
||||
# define _GL_WARN_ON_USE(function, message) \
|
||||
_GL_WARN_EXTERN_C int _gl_warn_on_use
|
||||
# define _GL_WARN_ON_USE_ATTRIBUTE(message)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* _GL_WARN_ON_USE_CXX (function, rettype, parameters_and_attributes, "string")
|
||||
is like _GL_WARN_ON_USE (function, "string"), except that the function is
|
||||
declared with the given prototype, consisting of return type, parameters,
|
||||
and attributes.
|
||||
This variant is useful for overloaded functions in C++. _GL_WARN_ON_USE does
|
||||
not work in this case. */
|
||||
#ifndef _GL_WARN_ON_USE_CXX
|
||||
# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)
|
||||
# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \
|
||||
extern rettype function parameters_and_attributes \
|
||||
__attribute__ ((__warning__ (msg)))
|
||||
# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
|
||||
/* Verify the existence of the function. */
|
||||
# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \
|
||||
extern rettype function parameters_and_attributes
|
||||
# else /* Unsupported. */
|
||||
# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \
|
||||
_GL_WARN_EXTERN_C int _gl_warn_on_use
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* _GL_WARN_EXTERN_C declaration;
|
||||
performs the declaration with C linkage. */
|
||||
#ifndef _GL_WARN_EXTERN_C
|
||||
# if defined __cplusplus
|
||||
# define _GL_WARN_EXTERN_C extern "C"
|
||||
# else
|
||||
# define _GL_WARN_EXTERN_C extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#if 1
|
||||
/* Converts an internet address from internal format to a printable,
|
||||
presentable format.
|
||||
AF is an internet address family, such as AF_INET or AF_INET6.
|
||||
SRC points to a 'struct in_addr' (for AF_INET) or 'struct in6_addr'
|
||||
(for AF_INET6).
|
||||
DST points to a buffer having room for CNT bytes.
|
||||
The printable representation of the address (in numeric form, not
|
||||
surrounded by [...], no reverse DNS is done) is placed in DST, and
|
||||
DST is returned. If an error occurs, the return value is NULL and
|
||||
errno is set. If CNT bytes are not sufficient to hold the result,
|
||||
the return value is NULL and errno is set to ENOSPC. A good value
|
||||
for CNT is 46.
|
||||
|
||||
For more details, see the POSIX:2008 specification
|
||||
<https://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_ntop.html>. */
|
||||
# if 0
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef inet_ntop
|
||||
# define inet_ntop rpl_inet_ntop
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (inet_ntop, const char *,
|
||||
(int af, const void *restrict src,
|
||||
char *restrict dst, socklen_t cnt)
|
||||
_GL_ARG_NONNULL ((2, 3)));
|
||||
_GL_CXXALIAS_RPL (inet_ntop, const char *,
|
||||
(int af, const void *restrict src,
|
||||
char *restrict dst, socklen_t cnt));
|
||||
# else
|
||||
# if !1
|
||||
_GL_FUNCDECL_SYS (inet_ntop, const char *,
|
||||
(int af, const void *restrict src,
|
||||
char *restrict dst, socklen_t cnt)
|
||||
_GL_ARG_NONNULL ((2, 3)));
|
||||
# endif
|
||||
/* Need to cast, because on NonStop Kernel, the fourth parameter is
|
||||
size_t cnt. */
|
||||
_GL_CXXALIAS_SYS_CAST (inet_ntop, const char *,
|
||||
(int af, const void *restrict src,
|
||||
char *restrict dst, socklen_t cnt));
|
||||
# endif
|
||||
# if __GLIBC__ >= 2
|
||||
_GL_CXXALIASWARN (inet_ntop);
|
||||
# endif
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef inet_ntop
|
||||
# if HAVE_RAW_DECL_INET_NTOP
|
||||
_GL_WARN_ON_USE (inet_ntop, "inet_ntop is unportable - "
|
||||
"use gnulib module inet_ntop for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if IN_COREUTILS_GNULIB_TESTS
|
||||
# if 0
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef inet_pton
|
||||
# define inet_pton rpl_inet_pton
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (inet_pton, int,
|
||||
(int af, const char *restrict src, void *restrict dst)
|
||||
_GL_ARG_NONNULL ((2, 3)));
|
||||
_GL_CXXALIAS_RPL (inet_pton, int,
|
||||
(int af, const char *restrict src, void *restrict dst));
|
||||
# else
|
||||
# if !1
|
||||
_GL_FUNCDECL_SYS (inet_pton, int,
|
||||
(int af, const char *restrict src, void *restrict dst)
|
||||
_GL_ARG_NONNULL ((2, 3)));
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (inet_pton, int,
|
||||
(int af, const char *restrict src, void *restrict dst));
|
||||
# endif
|
||||
# if __GLIBC__ >= 2
|
||||
_GL_CXXALIASWARN (inet_pton);
|
||||
# endif
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef inet_pton
|
||||
# if HAVE_RAW_DECL_INET_PTON
|
||||
_GL_WARN_ON_USE (inet_pton, "inet_pton is unportable - "
|
||||
"use gnulib module inet_pton for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _GL_ARPA_INET_H */
|
||||
#endif /* _GL_ARPA_INET_H */
|
||||
150
lib/arpa_inet.in.h
Normal file
150
lib/arpa_inet.in.h
Normal file
@@ -0,0 +1,150 @@
|
||||
/* A GNU-like <arpa/inet.h>.
|
||||
|
||||
Copyright (C) 2005-2006, 2008-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _@GUARD_PREFIX@_ARPA_INET_H
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
@PRAGMA_SYSTEM_HEADER@
|
||||
#endif
|
||||
@PRAGMA_COLUMNS@
|
||||
|
||||
#if @HAVE_FEATURES_H@
|
||||
# include <features.h> /* for __GLIBC__ */
|
||||
#endif
|
||||
|
||||
/* Gnulib's sys/socket.h is responsible for defining socklen_t (used below) and
|
||||
for pulling in winsock2.h etc. under MinGW.
|
||||
But avoid namespace pollution on glibc systems. */
|
||||
#ifndef __GLIBC__
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
/* On NonStop Kernel, inet_ntop and inet_pton are declared in <netdb.h>.
|
||||
But avoid namespace pollution on glibc systems. */
|
||||
#if defined __TANDEM && !defined __GLIBC__
|
||||
# include <netdb.h>
|
||||
#endif
|
||||
|
||||
#if @HAVE_ARPA_INET_H@
|
||||
|
||||
/* The include_next requires a split double-inclusion guard. */
|
||||
# @INCLUDE_NEXT@ @NEXT_ARPA_INET_H@
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef _@GUARD_PREFIX@_ARPA_INET_H
|
||||
#define _@GUARD_PREFIX@_ARPA_INET_H
|
||||
|
||||
/* Get all possible declarations of inet_ntop() and inet_pton(). */
|
||||
#if (@GNULIB_INET_NTOP@ || @GNULIB_INET_PTON@ || defined GNULIB_POSIXCHECK) \
|
||||
&& @HAVE_WS2TCPIP_H@
|
||||
# include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
|
||||
|
||||
/* The definition of _GL_ARG_NONNULL is copied here. */
|
||||
|
||||
/* The definition of _GL_WARN_ON_USE is copied here. */
|
||||
|
||||
|
||||
#if @GNULIB_INET_NTOP@
|
||||
/* Converts an internet address from internal format to a printable,
|
||||
presentable format.
|
||||
AF is an internet address family, such as AF_INET or AF_INET6.
|
||||
SRC points to a 'struct in_addr' (for AF_INET) or 'struct in6_addr'
|
||||
(for AF_INET6).
|
||||
DST points to a buffer having room for CNT bytes.
|
||||
The printable representation of the address (in numeric form, not
|
||||
surrounded by [...], no reverse DNS is done) is placed in DST, and
|
||||
DST is returned. If an error occurs, the return value is NULL and
|
||||
errno is set. If CNT bytes are not sufficient to hold the result,
|
||||
the return value is NULL and errno is set to ENOSPC. A good value
|
||||
for CNT is 46.
|
||||
|
||||
For more details, see the POSIX:2008 specification
|
||||
<https://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_ntop.html>. */
|
||||
# if @REPLACE_INET_NTOP@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef inet_ntop
|
||||
# define inet_ntop rpl_inet_ntop
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (inet_ntop, const char *,
|
||||
(int af, const void *restrict src,
|
||||
char *restrict dst, socklen_t cnt)
|
||||
_GL_ARG_NONNULL ((2, 3)));
|
||||
_GL_CXXALIAS_RPL (inet_ntop, const char *,
|
||||
(int af, const void *restrict src,
|
||||
char *restrict dst, socklen_t cnt));
|
||||
# else
|
||||
# if !@HAVE_DECL_INET_NTOP@
|
||||
_GL_FUNCDECL_SYS (inet_ntop, const char *,
|
||||
(int af, const void *restrict src,
|
||||
char *restrict dst, socklen_t cnt)
|
||||
_GL_ARG_NONNULL ((2, 3)));
|
||||
# endif
|
||||
/* Need to cast, because on NonStop Kernel, the fourth parameter is
|
||||
size_t cnt. */
|
||||
_GL_CXXALIAS_SYS_CAST (inet_ntop, const char *,
|
||||
(int af, const void *restrict src,
|
||||
char *restrict dst, socklen_t cnt));
|
||||
# endif
|
||||
# if __GLIBC__ >= 2
|
||||
_GL_CXXALIASWARN (inet_ntop);
|
||||
# endif
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef inet_ntop
|
||||
# if HAVE_RAW_DECL_INET_NTOP
|
||||
_GL_WARN_ON_USE (inet_ntop, "inet_ntop is unportable - "
|
||||
"use gnulib module inet_ntop for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if @GNULIB_INET_PTON@
|
||||
# if @REPLACE_INET_PTON@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef inet_pton
|
||||
# define inet_pton rpl_inet_pton
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (inet_pton, int,
|
||||
(int af, const char *restrict src, void *restrict dst)
|
||||
_GL_ARG_NONNULL ((2, 3)));
|
||||
_GL_CXXALIAS_RPL (inet_pton, int,
|
||||
(int af, const char *restrict src, void *restrict dst));
|
||||
# else
|
||||
# if !@HAVE_DECL_INET_PTON@
|
||||
_GL_FUNCDECL_SYS (inet_pton, int,
|
||||
(int af, const char *restrict src, void *restrict dst)
|
||||
_GL_ARG_NONNULL ((2, 3)));
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (inet_pton, int,
|
||||
(int af, const char *restrict src, void *restrict dst));
|
||||
# endif
|
||||
# if __GLIBC__ >= 2
|
||||
_GL_CXXALIASWARN (inet_pton);
|
||||
# endif
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef inet_pton
|
||||
# if HAVE_RAW_DECL_INET_PTON
|
||||
_GL_WARN_ON_USE (inet_pton, "inet_pton is unportable - "
|
||||
"use gnulib module inet_pton for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _@GUARD_PREFIX@_ARPA_INET_H */
|
||||
#endif /* _@GUARD_PREFIX@_ARPA_INET_H */
|
||||
34
lib/asnprintf.c
Normal file
34
lib/asnprintf.c
Normal file
@@ -0,0 +1,34 @@
|
||||
/* Formatted output to strings.
|
||||
Copyright (C) 1999, 2002, 2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include "vasnprintf.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
char *
|
||||
asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *result;
|
||||
|
||||
va_start (args, format);
|
||||
result = vasnprintf (resultbuf, lengthp, format, args);
|
||||
va_end (args);
|
||||
return result;
|
||||
}
|
||||
39
lib/asprintf.c
Normal file
39
lib/asprintf.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/* Formatted output to strings.
|
||||
Copyright (C) 1999, 2002, 2006-2007, 2009-2020 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#ifdef IN_LIBASPRINTF
|
||||
# include "vasprintf.h"
|
||||
#else
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
int
|
||||
asprintf (char **resultp, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int result;
|
||||
|
||||
va_start (args, format);
|
||||
result = vasprintf (resultp, format, args);
|
||||
va_end (args);
|
||||
return result;
|
||||
}
|
||||
37
lib/assure.h
Normal file
37
lib/assure.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Run-time assert-like macros.
|
||||
|
||||
Copyright (C) 2014-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Paul Eggert. */
|
||||
|
||||
#ifndef _GL_ASSURE_H
|
||||
#define _GL_ASSURE_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* Check E's value at runtime, and report an error and abort if not.
|
||||
However, do nothing if NDEBUG is defined.
|
||||
|
||||
Unlike standard 'assert', this macro always compiles E even when NDEBUG
|
||||
is defined, so as to catch typos and avoid some GCC warnings. */
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define assure(E) ((void) (0 && (E)))
|
||||
#else
|
||||
# define assure(E) assert (E)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
146
lib/at-func.c
Normal file
146
lib/at-func.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/* Define at-style functions like fstatat, unlinkat, fchownat, etc.
|
||||
Copyright (C) 2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Jim Meyering */
|
||||
|
||||
#include "dosname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
|
||||
|
||||
#ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD
|
||||
# include <errno.h>
|
||||
# ifndef ENOTSUP
|
||||
# define ENOTSUP EINVAL
|
||||
# endif
|
||||
#else
|
||||
# include "openat.h"
|
||||
# include "openat-priv.h"
|
||||
# include "save-cwd.h"
|
||||
#endif
|
||||
|
||||
#ifdef AT_FUNC_USE_F1_COND
|
||||
# define CALL_FUNC(F) \
|
||||
(flag == AT_FUNC_USE_F1_COND \
|
||||
? AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS) \
|
||||
: AT_FUNC_F2 (F AT_FUNC_POST_FILE_ARGS))
|
||||
# define VALIDATE_FLAG(F) \
|
||||
if (flag & ~AT_FUNC_USE_F1_COND) \
|
||||
{ \
|
||||
errno = EINVAL; \
|
||||
return FUNC_FAIL; \
|
||||
}
|
||||
#else
|
||||
# define CALL_FUNC(F) (AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS))
|
||||
# define VALIDATE_FLAG(F) /* empty */
|
||||
#endif
|
||||
|
||||
#ifdef AT_FUNC_RESULT
|
||||
# define FUNC_RESULT AT_FUNC_RESULT
|
||||
#else
|
||||
# define FUNC_RESULT int
|
||||
#endif
|
||||
|
||||
#ifdef AT_FUNC_FAIL
|
||||
# define FUNC_FAIL AT_FUNC_FAIL
|
||||
#else
|
||||
# define FUNC_FAIL -1
|
||||
#endif
|
||||
|
||||
/* Call AT_FUNC_F1 to operate on FILE, which is in the directory
|
||||
open on descriptor FD. If AT_FUNC_USE_F1_COND is defined to a value,
|
||||
AT_FUNC_POST_FILE_PARAM_DECLS must include a parameter named flag;
|
||||
call AT_FUNC_F2 if FLAG is 0 or fail if FLAG contains more bits than
|
||||
AT_FUNC_USE_F1_COND. Return int and fail with -1 unless AT_FUNC_RESULT
|
||||
or AT_FUNC_FAIL are defined. If possible, do it without changing the
|
||||
working directory. Otherwise, resort to using save_cwd/fchdir,
|
||||
then AT_FUNC_F?/restore_cwd. If either the save_cwd or the restore_cwd
|
||||
fails, then give a diagnostic and exit nonzero. */
|
||||
FUNC_RESULT
|
||||
AT_FUNC_NAME (int fd, char const *file AT_FUNC_POST_FILE_PARAM_DECLS)
|
||||
{
|
||||
VALIDATE_FLAG (flag);
|
||||
|
||||
if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
|
||||
return CALL_FUNC (file);
|
||||
|
||||
#ifdef GNULIB_SUPPORT_ONLY_AT_FDCWD
|
||||
errno = ENOTSUP;
|
||||
return FUNC_FAIL;
|
||||
#else
|
||||
{
|
||||
/* Be careful to choose names unlikely to conflict with
|
||||
AT_FUNC_POST_FILE_PARAM_DECLS. */
|
||||
struct saved_cwd saved_cwd;
|
||||
int saved_errno;
|
||||
FUNC_RESULT err;
|
||||
|
||||
{
|
||||
char proc_buf[OPENAT_BUFFER_SIZE];
|
||||
char *proc_file = openat_proc_name (proc_buf, fd, file);
|
||||
if (proc_file)
|
||||
{
|
||||
FUNC_RESULT proc_result = CALL_FUNC (proc_file);
|
||||
int proc_errno = errno;
|
||||
if (proc_file != proc_buf)
|
||||
free (proc_file);
|
||||
/* If the syscall succeeds, or if it fails with an unexpected
|
||||
errno value, then return right away. Otherwise, fall through
|
||||
and resort to using save_cwd/restore_cwd. */
|
||||
if (FUNC_FAIL != proc_result)
|
||||
return proc_result;
|
||||
if (! EXPECTED_ERRNO (proc_errno))
|
||||
{
|
||||
errno = proc_errno;
|
||||
return proc_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (save_cwd (&saved_cwd) != 0)
|
||||
openat_save_fail (errno);
|
||||
if (0 <= fd && fd == saved_cwd.desc)
|
||||
{
|
||||
/* If saving the working directory collides with the user's
|
||||
requested fd, then the user's fd must have been closed to
|
||||
begin with. */
|
||||
free_cwd (&saved_cwd);
|
||||
errno = EBADF;
|
||||
return FUNC_FAIL;
|
||||
}
|
||||
|
||||
if (fchdir (fd) != 0)
|
||||
{
|
||||
saved_errno = errno;
|
||||
free_cwd (&saved_cwd);
|
||||
errno = saved_errno;
|
||||
return FUNC_FAIL;
|
||||
}
|
||||
|
||||
err = CALL_FUNC (file);
|
||||
saved_errno = (err == FUNC_FAIL ? errno : 0);
|
||||
|
||||
if (restore_cwd (&saved_cwd) != 0)
|
||||
openat_restore_fail (errno);
|
||||
|
||||
free_cwd (&saved_cwd);
|
||||
|
||||
if (saved_errno)
|
||||
errno = saved_errno;
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#undef CALL_FUNC
|
||||
#undef FUNC_RESULT
|
||||
#undef FUNC_FAIL
|
||||
289
lib/at-func2.c
Normal file
289
lib/at-func2.c
Normal file
@@ -0,0 +1,289 @@
|
||||
/* Define 2-FD at-style functions like linkat or renameat.
|
||||
Copyright (C) 2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Jim Meyering and Eric Blake */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "openat-priv.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dosname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
|
||||
#include "filenamecat.h"
|
||||
#include "openat.h"
|
||||
#include "same-inode.h"
|
||||
#include "save-cwd.h"
|
||||
|
||||
/* Call FUNC to operate on a pair of files, where FILE1 is relative to FD1,
|
||||
and FILE2 is relative to FD2. If possible, do it without changing the
|
||||
working directory. Otherwise, resort to using save_cwd/fchdir,
|
||||
FUNC, restore_cwd (up to two times). If either the save_cwd or the
|
||||
restore_cwd fails, then give a diagnostic and exit nonzero. */
|
||||
int
|
||||
at_func2 (int fd1, char const *file1,
|
||||
int fd2, char const *file2,
|
||||
int (*func) (char const *file1, char const *file2))
|
||||
{
|
||||
struct saved_cwd saved_cwd;
|
||||
int saved_errno;
|
||||
int err;
|
||||
char *file1_alt;
|
||||
char *file2_alt;
|
||||
struct stat st1;
|
||||
struct stat st2;
|
||||
|
||||
/* There are 16 possible scenarios, based on whether an fd is
|
||||
AT_FDCWD or real, and whether a file is absolute or relative:
|
||||
|
||||
fd1 file1 fd2 file2 action
|
||||
0 cwd abs cwd abs direct call
|
||||
1 cwd abs cwd rel direct call
|
||||
2 cwd abs fd abs direct call
|
||||
3 cwd abs fd rel chdir to fd2
|
||||
4 cwd rel cwd abs direct call
|
||||
5 cwd rel cwd rel direct call
|
||||
6 cwd rel fd abs direct call
|
||||
7 cwd rel fd rel convert file1 to abs, then case 3
|
||||
8 fd abs cwd abs direct call
|
||||
9 fd abs cwd rel direct call
|
||||
10 fd abs fd abs direct call
|
||||
11 fd abs fd rel chdir to fd2
|
||||
12 fd rel cwd abs chdir to fd1
|
||||
13 fd rel cwd rel convert file2 to abs, then case 12
|
||||
14 fd rel fd abs chdir to fd1
|
||||
15a fd1 rel fd1 rel chdir to fd1
|
||||
15b fd1 rel fd2 rel chdir to fd1, then case 7
|
||||
|
||||
Try some optimizations to reduce fd to AT_FDCWD, or to at least
|
||||
avoid converting an absolute name or doing a double chdir. */
|
||||
|
||||
if ((fd1 == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file1))
|
||||
&& (fd2 == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file2)))
|
||||
return func (file1, file2); /* Case 0-2, 4-6, 8-10. */
|
||||
|
||||
/* If /proc/self/fd works, we don't need any stat or chdir. */
|
||||
{
|
||||
char proc_buf1[OPENAT_BUFFER_SIZE];
|
||||
char *proc_file1 = ((fd1 == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file1))
|
||||
? (char *) file1
|
||||
: openat_proc_name (proc_buf1, fd1, file1));
|
||||
if (proc_file1)
|
||||
{
|
||||
char proc_buf2[OPENAT_BUFFER_SIZE];
|
||||
char *proc_file2 = ((fd2 == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file2))
|
||||
? (char *) file2
|
||||
: openat_proc_name (proc_buf2, fd2, file2));
|
||||
if (proc_file2)
|
||||
{
|
||||
int proc_result = func (proc_file1, proc_file2);
|
||||
int proc_errno = errno;
|
||||
if (proc_file1 != proc_buf1 && proc_file1 != file1)
|
||||
free (proc_file1);
|
||||
if (proc_file2 != proc_buf2 && proc_file2 != file2)
|
||||
free (proc_file2);
|
||||
/* If the syscall succeeds, or if it fails with an unexpected
|
||||
errno value, then return right away. Otherwise, fall through
|
||||
and resort to using save_cwd/restore_cwd. */
|
||||
if (0 <= proc_result)
|
||||
return proc_result;
|
||||
if (! EXPECTED_ERRNO (proc_errno))
|
||||
{
|
||||
errno = proc_errno;
|
||||
return proc_result;
|
||||
}
|
||||
}
|
||||
else if (proc_file1 != proc_buf1 && proc_file1 != file1)
|
||||
free (proc_file1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Cases 3, 7, 11-15 remain. Time to normalize directory fds, if
|
||||
possible. */
|
||||
if (IS_ABSOLUTE_FILE_NAME (file1))
|
||||
fd1 = AT_FDCWD; /* Case 11 reduced to 3. */
|
||||
else if (IS_ABSOLUTE_FILE_NAME (file2))
|
||||
fd2 = AT_FDCWD; /* Case 14 reduced to 12. */
|
||||
|
||||
/* Cases 3, 7, 12, 13, 15 remain. */
|
||||
|
||||
if (fd1 == AT_FDCWD) /* Cases 3, 7. */
|
||||
{
|
||||
if (stat (".", &st1) == -1 || fstat (fd2, &st2) == -1)
|
||||
return -1;
|
||||
if (!S_ISDIR (st2.st_mode))
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
if (SAME_INODE (st1, st2)) /* Reduced to cases 1, 5. */
|
||||
return func (file1, file2);
|
||||
}
|
||||
else if (fd2 == AT_FDCWD) /* Cases 12, 13. */
|
||||
{
|
||||
if (stat (".", &st2) == -1 || fstat (fd1, &st1) == -1)
|
||||
return -1;
|
||||
if (!S_ISDIR (st1.st_mode))
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
if (SAME_INODE (st1, st2)) /* Reduced to cases 4, 5. */
|
||||
return func (file1, file2);
|
||||
}
|
||||
else if (fd1 != fd2) /* Case 15b. */
|
||||
{
|
||||
if (fstat (fd1, &st1) == -1 || fstat (fd2, &st2) == -1)
|
||||
return -1;
|
||||
if (!S_ISDIR (st1.st_mode) || !S_ISDIR (st2.st_mode))
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
if (SAME_INODE (st1, st2)) /* Reduced to case 15a. */
|
||||
{
|
||||
fd2 = fd1;
|
||||
if (stat (".", &st1) == 0 && SAME_INODE (st1, st2))
|
||||
return func (file1, file2); /* Further reduced to case 5. */
|
||||
}
|
||||
}
|
||||
else /* Case 15a. */
|
||||
{
|
||||
if (fstat (fd1, &st1) == -1)
|
||||
return -1;
|
||||
if (!S_ISDIR (st1.st_mode))
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
if (stat (".", &st2) == 0 && SAME_INODE (st1, st2))
|
||||
return func (file1, file2); /* Reduced to case 5. */
|
||||
}
|
||||
|
||||
/* Catch invalid arguments before changing directories. */
|
||||
if (file1[0] == '\0' || file2[0] == '\0')
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Cases 3, 7, 12, 13, 15a, 15b remain. With all reductions in
|
||||
place, it is time to start changing directories. */
|
||||
|
||||
if (save_cwd (&saved_cwd) != 0)
|
||||
openat_save_fail (errno);
|
||||
|
||||
if (fd1 != AT_FDCWD && fd2 != AT_FDCWD && fd1 != fd2) /* Case 15b. */
|
||||
{
|
||||
if (fchdir (fd1) != 0)
|
||||
{
|
||||
saved_errno = errno;
|
||||
free_cwd (&saved_cwd);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
fd1 = AT_FDCWD; /* Reduced to case 7. */
|
||||
}
|
||||
|
||||
/* Cases 3, 7, 12, 13, 15a remain. Convert one relative name to
|
||||
absolute, if necessary. */
|
||||
|
||||
file1_alt = (char *) file1;
|
||||
file2_alt = (char *) file2;
|
||||
|
||||
if (fd1 == AT_FDCWD && !IS_ABSOLUTE_FILE_NAME (file1)) /* Case 7. */
|
||||
{
|
||||
/* It would be nicer to use:
|
||||
file1_alt = file_name_concat (xgetcwd (), file1, NULL);
|
||||
but libraries should not call xalloc_die. */
|
||||
char *cwd = getcwd (NULL, 0);
|
||||
if (!cwd)
|
||||
{
|
||||
saved_errno = errno;
|
||||
free_cwd (&saved_cwd);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
file1_alt = mfile_name_concat (cwd, file1, NULL);
|
||||
if (!file1_alt)
|
||||
{
|
||||
saved_errno = errno;
|
||||
free (cwd);
|
||||
free_cwd (&saved_cwd);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
free (cwd); /* Reduced to case 3. */
|
||||
}
|
||||
else if (fd2 == AT_FDCWD && !IS_ABSOLUTE_FILE_NAME (file2)) /* Case 13. */
|
||||
{
|
||||
char *cwd = getcwd (NULL, 0);
|
||||
if (!cwd)
|
||||
{
|
||||
saved_errno = errno;
|
||||
free_cwd (&saved_cwd);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
file2_alt = mfile_name_concat (cwd, file2, NULL);
|
||||
if (!file2_alt)
|
||||
{
|
||||
saved_errno = errno;
|
||||
free (cwd);
|
||||
free_cwd (&saved_cwd);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
free (cwd); /* Reduced to case 12. */
|
||||
}
|
||||
|
||||
/* Cases 3, 12, 15a remain. Change to the correct directory. */
|
||||
if (fchdir (fd1 == AT_FDCWD ? fd2 : fd1) != 0)
|
||||
{
|
||||
saved_errno = errno;
|
||||
free_cwd (&saved_cwd);
|
||||
if (file1 != file1_alt)
|
||||
free (file1_alt);
|
||||
else if (file2 != file2_alt)
|
||||
free (file2_alt);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Finally safe to perform the user's function, then clean up. */
|
||||
|
||||
err = func (file1_alt, file2_alt);
|
||||
saved_errno = (err < 0 ? errno : 0);
|
||||
|
||||
if (file1 != file1_alt)
|
||||
free (file1_alt);
|
||||
else if (file2 != file2_alt)
|
||||
free (file2_alt);
|
||||
|
||||
if (restore_cwd (&saved_cwd) != 0)
|
||||
openat_restore_fail (errno);
|
||||
|
||||
free_cwd (&saved_cwd);
|
||||
|
||||
if (saved_errno)
|
||||
errno = saved_errno;
|
||||
return err;
|
||||
}
|
||||
#undef CALL_FUNC
|
||||
#undef FUNC_RESULT
|
||||
93
lib/backup-find.c
Normal file
93
lib/backup-find.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/* backupfile.c -- make Emacs style backup file names
|
||||
|
||||
Copyright 2017-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "backup-internal.h"
|
||||
|
||||
#include "argmatch.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Relative to DIR_FD, return the name of a backup file for the
|
||||
existing file FILE, allocated with malloc. Report an error and
|
||||
exit if out of memory. Do not call this function if
|
||||
backup_type == no_backups. */
|
||||
|
||||
char *
|
||||
find_backup_file_name (int dir_fd, char const *file,
|
||||
enum backup_type backup_type)
|
||||
{
|
||||
char *result = backupfile_internal (dir_fd, file, backup_type, false);
|
||||
if (!result)
|
||||
xalloc_die ();
|
||||
return result;
|
||||
}
|
||||
|
||||
static char const *const backup_args[] =
|
||||
{
|
||||
/* In a series of synonyms, present the most meaningful first, so
|
||||
that argmatch_valid be more readable. */
|
||||
"none", "off",
|
||||
"simple", "never",
|
||||
"existing", "nil",
|
||||
"numbered", "t",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const enum backup_type backup_types[] =
|
||||
{
|
||||
no_backups, no_backups,
|
||||
simple_backups, simple_backups,
|
||||
numbered_existing_backups, numbered_existing_backups,
|
||||
numbered_backups, numbered_backups
|
||||
};
|
||||
|
||||
/* Ensure that these two vectors have the same number of elements,
|
||||
not counting the final NULL in the first one. */
|
||||
ARGMATCH_VERIFY (backup_args, backup_types);
|
||||
|
||||
/* Return the type of backup specified by VERSION.
|
||||
If VERSION is NULL or the empty string, return numbered_existing_backups.
|
||||
If VERSION is invalid or ambiguous, fail with a diagnostic appropriate
|
||||
for the specified CONTEXT. Unambiguous abbreviations are accepted. */
|
||||
|
||||
enum backup_type
|
||||
get_version (char const *context, char const *version)
|
||||
{
|
||||
if (version == 0 || *version == 0)
|
||||
return numbered_existing_backups;
|
||||
else
|
||||
return XARGMATCH (context, version, backup_args, backup_types);
|
||||
}
|
||||
|
||||
|
||||
/* Return the type of backup specified by VERSION.
|
||||
If VERSION is NULL, use the value of the envvar VERSION_CONTROL.
|
||||
If the specified string is invalid or ambiguous, fail with a diagnostic
|
||||
appropriate for the specified CONTEXT.
|
||||
Unambiguous abbreviations are accepted. */
|
||||
|
||||
enum backup_type
|
||||
xget_version (char const *context, char const *version)
|
||||
{
|
||||
if (version && *version)
|
||||
return get_version (context, version);
|
||||
else
|
||||
return get_version ("$VERSION_CONTROL", getenv ("VERSION_CONTROL"));
|
||||
}
|
||||
3
lib/backup-internal.h
Normal file
3
lib/backup-internal.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "backupfile.h"
|
||||
#include <stdbool.h>
|
||||
extern char *backupfile_internal (int, char const *, enum backup_type, bool);
|
||||
31
lib/backup-rename.c
Normal file
31
lib/backup-rename.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/* Rename a file to a backup name, Emacs style.
|
||||
|
||||
Copyright 2017-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "backup-internal.h"
|
||||
|
||||
/* Relative to DIR_FD, rename the existing file FILE to a backup name,
|
||||
allocated with malloc, and return the backup name. On failure
|
||||
return a null pointer, setting errno. Do not call this function if
|
||||
backup_type == no_backups. */
|
||||
|
||||
char *
|
||||
backup_file_rename (int dir_fd, char const *file, enum backup_type backup_type)
|
||||
{
|
||||
return backupfile_internal (dir_fd, file, backup_type, true);
|
||||
}
|
||||
397
lib/backupfile.c
Normal file
397
lib/backupfile.c
Normal file
@@ -0,0 +1,397 @@
|
||||
/* backupfile.c -- make Emacs style backup file names
|
||||
|
||||
Copyright (C) 1990-2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Paul Eggert and David MacKenzie.
|
||||
Some algorithms adapted from GNU Emacs. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "backup-internal.h"
|
||||
|
||||
#include "dirname.h"
|
||||
#include "opendirat.h"
|
||||
#include "renameatu.h"
|
||||
#include "xalloc-oversized.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef FALLTHROUGH
|
||||
# if __GNUC__ < 7
|
||||
# define FALLTHROUGH ((void) 0)
|
||||
# else
|
||||
# define FALLTHROUGH __attribute__ ((__fallthrough__))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef _D_EXACT_NAMLEN
|
||||
# define _D_EXACT_NAMLEN(dp) strlen ((dp)->d_name)
|
||||
#endif
|
||||
|
||||
#if ! (HAVE_PATHCONF && defined _PC_NAME_MAX)
|
||||
# define pathconf(file, option) (errno = -1)
|
||||
#endif
|
||||
|
||||
#ifndef _POSIX_NAME_MAX
|
||||
# define _POSIX_NAME_MAX 14
|
||||
#endif
|
||||
|
||||
#if defined _XOPEN_NAME_MAX
|
||||
# define NAME_MAX_MINIMUM _XOPEN_NAME_MAX
|
||||
#else
|
||||
# define NAME_MAX_MINIMUM _POSIX_NAME_MAX
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DOS_FILE_NAMES
|
||||
# define HAVE_DOS_FILE_NAMES 0
|
||||
#endif
|
||||
#ifndef HAVE_LONG_FILE_NAMES
|
||||
# define HAVE_LONG_FILE_NAMES 0
|
||||
#endif
|
||||
|
||||
/* ISDIGIT differs from isdigit, as follows:
|
||||
- Its arg may be any int or unsigned int; it need not be an unsigned char
|
||||
or EOF.
|
||||
- It's typically faster.
|
||||
POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
|
||||
ISDIGIT unless it's important to use the locale's definition
|
||||
of "digit" even when the host does not conform to POSIX. */
|
||||
#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
|
||||
|
||||
/* The extension added to file names to produce a simple (as opposed
|
||||
to numbered) backup file name. */
|
||||
char const *simple_backup_suffix = NULL;
|
||||
|
||||
/* Set SIMPLE_BACKUP_SUFFIX to S, or to a default specified by the
|
||||
environment if S is null. If S or the environment does not specify
|
||||
a valid backup suffix, use "~". */
|
||||
void
|
||||
set_simple_backup_suffix (char const *s)
|
||||
{
|
||||
if (!s)
|
||||
s = getenv ("SIMPLE_BACKUP_SUFFIX");
|
||||
simple_backup_suffix = s && *s && s == last_component (s) ? s : "~";
|
||||
}
|
||||
|
||||
/* If FILE (which was of length FILELEN before an extension was
|
||||
appended to it) is too long, replace the extension with the single
|
||||
char E. If the result is still too long, remove the char just
|
||||
before E.
|
||||
|
||||
If DIR_FD is nonnegative, it is a file descriptor for FILE's parent.
|
||||
*NAME_MAX is either 0, or the cached result of a previous call for
|
||||
FILE's parent's _PC_NAME_MAX. */
|
||||
|
||||
static void
|
||||
check_extension (char *file, size_t filelen, char e,
|
||||
int dir_fd, size_t *base_max)
|
||||
{
|
||||
char *base = last_component (file);
|
||||
size_t baselen = base_len (base);
|
||||
size_t baselen_max = HAVE_LONG_FILE_NAMES ? 255 : NAME_MAX_MINIMUM;
|
||||
|
||||
if (HAVE_DOS_FILE_NAMES || NAME_MAX_MINIMUM < baselen)
|
||||
{
|
||||
/* The new base name is long enough to require a pathconf check. */
|
||||
if (*base_max == 0)
|
||||
{
|
||||
long name_max;
|
||||
if (dir_fd < 0)
|
||||
{
|
||||
/* Temporarily modify the buffer into its parent
|
||||
directory name, invoke pathconf on the directory, and
|
||||
then restore the buffer. */
|
||||
char tmp[sizeof "."];
|
||||
memcpy (tmp, base, sizeof ".");
|
||||
strcpy (base, ".");
|
||||
errno = 0;
|
||||
name_max = pathconf (file, _PC_NAME_MAX);
|
||||
name_max -= !errno;
|
||||
memcpy (base, tmp, sizeof ".");
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = 0;
|
||||
name_max = fpathconf (dir_fd, _PC_NAME_MAX);
|
||||
name_max -= !errno;
|
||||
}
|
||||
|
||||
*base_max = (0 <= name_max && name_max <= SIZE_MAX ? name_max
|
||||
: name_max < -1 ? NAME_MAX_MINIMUM : SIZE_MAX);
|
||||
}
|
||||
|
||||
baselen_max = *base_max;
|
||||
}
|
||||
|
||||
if (HAVE_DOS_FILE_NAMES && baselen_max <= 12)
|
||||
{
|
||||
/* Live within DOS's 8.3 limit. */
|
||||
char *dot = strchr (base, '.');
|
||||
if (!dot)
|
||||
baselen_max = 8;
|
||||
else
|
||||
{
|
||||
char const *second_dot = strchr (dot + 1, '.');
|
||||
baselen_max = (second_dot
|
||||
? second_dot - base
|
||||
: dot + 1 - base + 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (baselen_max < baselen)
|
||||
{
|
||||
baselen = file + filelen - base;
|
||||
if (baselen_max <= baselen)
|
||||
baselen = baselen_max - 1;
|
||||
base[baselen] = e;
|
||||
base[baselen + 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Returned values for NUMBERED_BACKUP. */
|
||||
|
||||
enum numbered_backup_result
|
||||
{
|
||||
/* The new backup name is the same length as an existing backup
|
||||
name, so it's valid for that directory. */
|
||||
BACKUP_IS_SAME_LENGTH,
|
||||
|
||||
/* Some backup names already exist, but the returned name is longer
|
||||
than any of them, and its length should be checked. */
|
||||
BACKUP_IS_LONGER,
|
||||
|
||||
/* There are no existing backup names. The new name's length
|
||||
should be checked. */
|
||||
BACKUP_IS_NEW,
|
||||
|
||||
/* Memory allocation failure. */
|
||||
BACKUP_NOMEM
|
||||
};
|
||||
|
||||
/* Relative to DIR_FD, *BUFFER contains a file name.
|
||||
Store into *BUFFER the next backup name for the named file,
|
||||
with a version number greater than all the
|
||||
existing numbered backups. Reallocate *BUFFER as necessary; its
|
||||
initial allocated size is BUFFER_SIZE, which must be at least 4
|
||||
bytes longer than the file name to make room for the initially
|
||||
appended ".~1". FILELEN is the length of the original file name.
|
||||
BASE_OFFSET is the offset of the basename in *BUFFER.
|
||||
The returned value indicates what kind of backup was found. If an
|
||||
I/O or other read error occurs, use the highest backup number that
|
||||
was found.
|
||||
|
||||
*DIRPP is the destination directory. If *DIRPP is null, open the
|
||||
destination directory and store the resulting stream into *DIRPP
|
||||
and its file descriptor into *PNEW_FD without closing the stream. */
|
||||
|
||||
static enum numbered_backup_result
|
||||
numbered_backup (int dir_fd, char **buffer, size_t buffer_size, size_t filelen,
|
||||
ptrdiff_t base_offset, DIR **dirpp, int *pnew_fd)
|
||||
{
|
||||
enum numbered_backup_result result = BACKUP_IS_NEW;
|
||||
DIR *dirp = *dirpp;
|
||||
struct dirent *dp;
|
||||
char *buf = *buffer;
|
||||
size_t versionlenmax = 1;
|
||||
char *base = buf + base_offset;
|
||||
size_t baselen = base_len (base);
|
||||
|
||||
if (dirp)
|
||||
rewinddir (dirp);
|
||||
else
|
||||
{
|
||||
/* Temporarily modify the buffer into its parent directory name,
|
||||
open the directory, and then restore the buffer. */
|
||||
char tmp[sizeof "."];
|
||||
memcpy (tmp, base, sizeof ".");
|
||||
strcpy (base, ".");
|
||||
dirp = opendirat (dir_fd, buf, 0, pnew_fd);
|
||||
if (!dirp && errno == ENOMEM)
|
||||
result = BACKUP_NOMEM;
|
||||
memcpy (base, tmp, sizeof ".");
|
||||
strcpy (base + baselen, ".~1~");
|
||||
if (!dirp)
|
||||
return result;
|
||||
*dirpp = dirp;
|
||||
}
|
||||
|
||||
while ((dp = readdir (dirp)) != NULL)
|
||||
{
|
||||
char const *p;
|
||||
char *q;
|
||||
bool all_9s;
|
||||
size_t versionlen;
|
||||
|
||||
if (_D_EXACT_NAMLEN (dp) < baselen + 4)
|
||||
continue;
|
||||
|
||||
if (memcmp (buf + base_offset, dp->d_name, baselen + 2) != 0)
|
||||
continue;
|
||||
|
||||
p = dp->d_name + baselen + 2;
|
||||
|
||||
/* Check whether this file has a version number and if so,
|
||||
whether it is larger. Use string operations rather than
|
||||
integer arithmetic, to avoid problems with integer overflow. */
|
||||
|
||||
if (! ('1' <= *p && *p <= '9'))
|
||||
continue;
|
||||
all_9s = (*p == '9');
|
||||
for (versionlen = 1; ISDIGIT (p[versionlen]); versionlen++)
|
||||
all_9s &= (p[versionlen] == '9');
|
||||
|
||||
if (! (p[versionlen] == '~' && !p[versionlen + 1]
|
||||
&& (versionlenmax < versionlen
|
||||
|| (versionlenmax == versionlen
|
||||
&& memcmp (buf + filelen + 2, p, versionlen) <= 0))))
|
||||
continue;
|
||||
|
||||
/* This entry has the largest version number seen so far.
|
||||
Append this highest numbered extension to the file name,
|
||||
prepending '0' to the number if it is all 9s. */
|
||||
|
||||
versionlenmax = all_9s + versionlen;
|
||||
result = (all_9s ? BACKUP_IS_LONGER : BACKUP_IS_SAME_LENGTH);
|
||||
size_t new_buffer_size = filelen + 2 + versionlenmax + 2;
|
||||
if (buffer_size < new_buffer_size)
|
||||
{
|
||||
if (! xalloc_oversized (new_buffer_size, 2))
|
||||
new_buffer_size *= 2;
|
||||
char *new_buf = realloc (buf, new_buffer_size);
|
||||
if (!new_buf)
|
||||
{
|
||||
*buffer = buf;
|
||||
return BACKUP_NOMEM;
|
||||
}
|
||||
buf = new_buf;
|
||||
buffer_size = new_buffer_size;
|
||||
}
|
||||
q = buf + filelen;
|
||||
*q++ = '.';
|
||||
*q++ = '~';
|
||||
*q = '0';
|
||||
q += all_9s;
|
||||
memcpy (q, p, versionlen + 2);
|
||||
|
||||
/* Add 1 to the version number. */
|
||||
|
||||
q += versionlen;
|
||||
while (*--q == '9')
|
||||
*q = '0';
|
||||
++*q;
|
||||
}
|
||||
|
||||
*buffer = buf;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Relative to DIR_FD, return the name of the new backup file for the
|
||||
existing file FILE, allocated with malloc.
|
||||
If RENAME, also rename FILE to the new name.
|
||||
On failure, return NULL and set errno.
|
||||
Do not call this function if backup_type == no_backups. */
|
||||
|
||||
char *
|
||||
backupfile_internal (int dir_fd, char const *file,
|
||||
enum backup_type backup_type, bool rename)
|
||||
{
|
||||
ptrdiff_t base_offset = last_component (file) - file;
|
||||
size_t filelen = base_offset + strlen (file + base_offset);
|
||||
|
||||
if (! simple_backup_suffix)
|
||||
set_simple_backup_suffix (NULL);
|
||||
|
||||
/* Allow room for simple or ".~N~" backups. The guess must be at
|
||||
least sizeof ".~1~", but otherwise will be adjusted as needed. */
|
||||
size_t simple_backup_suffix_size = strlen (simple_backup_suffix) + 1;
|
||||
size_t backup_suffix_size_guess = simple_backup_suffix_size;
|
||||
enum { GUESS = sizeof ".~12345~" };
|
||||
if (backup_suffix_size_guess < GUESS)
|
||||
backup_suffix_size_guess = GUESS;
|
||||
|
||||
ssize_t ssize = filelen + backup_suffix_size_guess + 1;
|
||||
char *s = malloc (ssize);
|
||||
if (!s)
|
||||
return s;
|
||||
|
||||
DIR *dirp = NULL;
|
||||
int sdir = -1;
|
||||
size_t base_max = 0;
|
||||
while (true)
|
||||
{
|
||||
memcpy (s, file, filelen + 1);
|
||||
|
||||
if (backup_type == simple_backups)
|
||||
memcpy (s + filelen, simple_backup_suffix, simple_backup_suffix_size);
|
||||
else
|
||||
switch (numbered_backup (dir_fd, &s, ssize, filelen, base_offset,
|
||||
&dirp, &sdir))
|
||||
{
|
||||
case BACKUP_IS_SAME_LENGTH:
|
||||
break;
|
||||
|
||||
case BACKUP_IS_NEW:
|
||||
if (backup_type == numbered_existing_backups)
|
||||
{
|
||||
backup_type = simple_backups;
|
||||
memcpy (s + filelen, simple_backup_suffix,
|
||||
simple_backup_suffix_size);
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case BACKUP_IS_LONGER:
|
||||
check_extension (s, filelen, '~', sdir, &base_max);
|
||||
break;
|
||||
|
||||
case BACKUP_NOMEM:
|
||||
if (dirp)
|
||||
closedir (dirp);
|
||||
free (s);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (! rename)
|
||||
break;
|
||||
|
||||
if (sdir < 0)
|
||||
{
|
||||
sdir = AT_FDCWD;
|
||||
base_offset = 0;
|
||||
}
|
||||
unsigned flags = backup_type == simple_backups ? 0 : RENAME_NOREPLACE;
|
||||
if (renameatu (AT_FDCWD, file, sdir, s + base_offset, flags) == 0)
|
||||
break;
|
||||
int e = errno;
|
||||
if (e != EEXIST)
|
||||
{
|
||||
if (dirp)
|
||||
closedir (dirp);
|
||||
free (s);
|
||||
errno = e;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (dirp)
|
||||
closedir (dirp);
|
||||
return s;
|
||||
}
|
||||
62
lib/backupfile.h
Normal file
62
lib/backupfile.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/* backupfile.h -- declarations for making Emacs style backup file names
|
||||
|
||||
Copyright (C) 1990-1992, 1997-1999, 2003-2004, 2009-2020 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef BACKUPFILE_H_
|
||||
#define BACKUPFILE_H_
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* When to make backup files. */
|
||||
enum backup_type
|
||||
{
|
||||
/* Never make backups. */
|
||||
no_backups,
|
||||
|
||||
/* Make simple backups of every file. */
|
||||
simple_backups,
|
||||
|
||||
/* Make numbered backups of files that already have numbered backups,
|
||||
and simple backups of the others. */
|
||||
numbered_existing_backups,
|
||||
|
||||
/* Make numbered backups of every file. */
|
||||
numbered_backups
|
||||
};
|
||||
|
||||
#define VALID_BACKUP_TYPE(Type) \
|
||||
((unsigned int) (Type) <= numbered_backups)
|
||||
|
||||
extern char const *simple_backup_suffix;
|
||||
|
||||
void set_simple_backup_suffix (char const *);
|
||||
char *backup_file_rename (int, char const *, enum backup_type);
|
||||
char *find_backup_file_name (int, char const *, enum backup_type);
|
||||
enum backup_type get_version (char const *context, char const *arg);
|
||||
enum backup_type xget_version (char const *context, char const *arg);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ! BACKUPFILE_H_ */
|
||||
587
lib/base32.c
Normal file
587
lib/base32.c
Normal file
@@ -0,0 +1,587 @@
|
||||
/* base32.c -- Encode binary data using printable characters.
|
||||
Copyright (C) 1999-2001, 2004-2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Adapted from Simon Josefsson's base64 code by Gijs van Tulder.
|
||||
*
|
||||
* See also RFC 4648 <https://www.ietf.org/rfc/rfc4648.txt>.
|
||||
*
|
||||
* Be careful with error checking. Here is how you would typically
|
||||
* use these functions:
|
||||
*
|
||||
* bool ok = base32_decode_alloc (in, inlen, &out, &outlen);
|
||||
* if (!ok)
|
||||
* FAIL: input was not valid base32
|
||||
* if (out == NULL)
|
||||
* FAIL: memory allocation error
|
||||
* OK: data in OUT/OUTLEN
|
||||
*
|
||||
* size_t outlen = base32_encode_alloc (in, inlen, &out);
|
||||
* if (out == NULL && outlen == 0 && inlen != 0)
|
||||
* FAIL: input too long
|
||||
* if (out == NULL)
|
||||
* FAIL: memory allocation error
|
||||
* OK: data in OUT/OUTLEN.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Get prototype. */
|
||||
#include "base32.h"
|
||||
|
||||
/* Get malloc. */
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Get UCHAR_MAX. */
|
||||
#include <limits.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* C89 compliant way to cast 'char' to 'unsigned char'. */
|
||||
static unsigned char
|
||||
to_uchar (char ch)
|
||||
{
|
||||
return ch;
|
||||
}
|
||||
|
||||
/* Base32 encode IN array of size INLEN into OUT array of size OUTLEN.
|
||||
If OUTLEN is less than BASE32_LENGTH(INLEN), write as many bytes as
|
||||
possible. If OUTLEN is larger than BASE32_LENGTH(INLEN), also zero
|
||||
terminate the output buffer. */
|
||||
void
|
||||
base32_encode (const char *restrict in, size_t inlen,
|
||||
char *restrict out, size_t outlen)
|
||||
{
|
||||
static const char b32str[32] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
|
||||
while (inlen && outlen)
|
||||
{
|
||||
*out++ = b32str[(to_uchar (in[0]) >> 3) & 0x1f];
|
||||
if (!--outlen)
|
||||
break;
|
||||
*out++ = b32str[((to_uchar (in[0]) << 2)
|
||||
+ (--inlen ? to_uchar (in[1]) >> 6 : 0))
|
||||
& 0x1f];
|
||||
if (!--outlen)
|
||||
break;
|
||||
*out++ =
|
||||
(inlen
|
||||
? b32str[(to_uchar (in[1]) >> 1) & 0x1f]
|
||||
: '=');
|
||||
if (!--outlen)
|
||||
break;
|
||||
*out++ =
|
||||
(inlen
|
||||
? b32str[((to_uchar (in[1]) << 4)
|
||||
+ (--inlen ? to_uchar (in[2]) >> 4 : 0))
|
||||
& 0x1f]
|
||||
: '=');
|
||||
if (!--outlen)
|
||||
break;
|
||||
*out++ =
|
||||
(inlen
|
||||
? b32str[((to_uchar (in[2]) << 1)
|
||||
+ (--inlen ? to_uchar (in[3]) >> 7 : 0))
|
||||
& 0x1f]
|
||||
: '=');
|
||||
if (!--outlen)
|
||||
break;
|
||||
*out++ =
|
||||
(inlen
|
||||
? b32str[(to_uchar (in[3]) >> 2) & 0x1f]
|
||||
: '=');
|
||||
if (!--outlen)
|
||||
break;
|
||||
*out++ =
|
||||
(inlen
|
||||
? b32str[((to_uchar (in[3]) << 3)
|
||||
+ (--inlen ? to_uchar (in[4]) >> 5 : 0))
|
||||
& 0x1f]
|
||||
: '=');
|
||||
if (!--outlen)
|
||||
break;
|
||||
*out++ = inlen ? b32str[to_uchar (in[4]) & 0x1f] : '=';
|
||||
if (!--outlen)
|
||||
break;
|
||||
if (inlen)
|
||||
inlen--;
|
||||
if (inlen)
|
||||
in += 5;
|
||||
}
|
||||
|
||||
if (outlen)
|
||||
*out = '\0';
|
||||
}
|
||||
|
||||
/* Allocate a buffer and store zero terminated base32 encoded data
|
||||
from array IN of size INLEN, returning BASE32_LENGTH(INLEN), i.e.,
|
||||
the length of the encoded data, excluding the terminating zero. On
|
||||
return, the OUT variable will hold a pointer to newly allocated
|
||||
memory that must be deallocated by the caller. If output string
|
||||
length would overflow, 0 is returned and OUT is set to NULL. If
|
||||
memory allocation failed, OUT is set to NULL, and the return value
|
||||
indicates length of the requested memory block, i.e.,
|
||||
BASE32_LENGTH(inlen) + 1. */
|
||||
size_t
|
||||
base32_encode_alloc (const char *in, size_t inlen, char **out)
|
||||
{
|
||||
size_t outlen = 1 + BASE32_LENGTH (inlen);
|
||||
|
||||
/* Check for overflow in outlen computation.
|
||||
*
|
||||
* If there is no overflow, outlen >= inlen.
|
||||
*
|
||||
* TODO Is this a sufficient check? (See the notes in base64.c.)
|
||||
*/
|
||||
if (inlen > outlen)
|
||||
{
|
||||
*out = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out = malloc (outlen);
|
||||
if (!*out)
|
||||
return outlen;
|
||||
|
||||
base32_encode (in, inlen, *out, outlen);
|
||||
|
||||
return outlen - 1;
|
||||
}
|
||||
|
||||
/* With this approach this file works independent of the charset used
|
||||
(think EBCDIC). However, it does assume that the characters in the
|
||||
Base32 alphabet (A-Z2-7) are encoded in 0..255. POSIX
|
||||
1003.1-2001 require that char and unsigned char are 8-bit
|
||||
quantities, though, taking care of that problem. But this may be a
|
||||
potential problem on non-POSIX C99 platforms.
|
||||
|
||||
IBM C V6 for AIX mishandles "#define B32(x) ...'x'...", so use "_"
|
||||
as the formal parameter rather than "x". */
|
||||
#define B32(_) \
|
||||
((_) == 'A' ? 0 \
|
||||
: (_) == 'B' ? 1 \
|
||||
: (_) == 'C' ? 2 \
|
||||
: (_) == 'D' ? 3 \
|
||||
: (_) == 'E' ? 4 \
|
||||
: (_) == 'F' ? 5 \
|
||||
: (_) == 'G' ? 6 \
|
||||
: (_) == 'H' ? 7 \
|
||||
: (_) == 'I' ? 8 \
|
||||
: (_) == 'J' ? 9 \
|
||||
: (_) == 'K' ? 10 \
|
||||
: (_) == 'L' ? 11 \
|
||||
: (_) == 'M' ? 12 \
|
||||
: (_) == 'N' ? 13 \
|
||||
: (_) == 'O' ? 14 \
|
||||
: (_) == 'P' ? 15 \
|
||||
: (_) == 'Q' ? 16 \
|
||||
: (_) == 'R' ? 17 \
|
||||
: (_) == 'S' ? 18 \
|
||||
: (_) == 'T' ? 19 \
|
||||
: (_) == 'U' ? 20 \
|
||||
: (_) == 'V' ? 21 \
|
||||
: (_) == 'W' ? 22 \
|
||||
: (_) == 'X' ? 23 \
|
||||
: (_) == 'Y' ? 24 \
|
||||
: (_) == 'Z' ? 25 \
|
||||
: (_) == '2' ? 26 \
|
||||
: (_) == '3' ? 27 \
|
||||
: (_) == '4' ? 28 \
|
||||
: (_) == '5' ? 29 \
|
||||
: (_) == '6' ? 30 \
|
||||
: (_) == '7' ? 31 \
|
||||
: -1)
|
||||
|
||||
static const signed char b32[0x100] = {
|
||||
B32 (0), B32 (1), B32 (2), B32 (3),
|
||||
B32 (4), B32 (5), B32 (6), B32 (7),
|
||||
B32 (8), B32 (9), B32 (10), B32 (11),
|
||||
B32 (12), B32 (13), B32 (14), B32 (15),
|
||||
B32 (16), B32 (17), B32 (18), B32 (19),
|
||||
B32 (20), B32 (21), B32 (22), B32 (23),
|
||||
B32 (24), B32 (25), B32 (26), B32 (27),
|
||||
B32 (28), B32 (29), B32 (30), B32 (31),
|
||||
B32 (32), B32 (33), B32 (34), B32 (35),
|
||||
B32 (36), B32 (37), B32 (38), B32 (39),
|
||||
B32 (40), B32 (41), B32 (42), B32 (43),
|
||||
B32 (44), B32 (45), B32 (46), B32 (47),
|
||||
B32 (48), B32 (49), B32 (50), B32 (51),
|
||||
B32 (52), B32 (53), B32 (54), B32 (55),
|
||||
B32 (56), B32 (57), B32 (58), B32 (59),
|
||||
B32 (60), B32 (61), B32 (62), B32 (63),
|
||||
B32 (32), B32 (65), B32 (66), B32 (67),
|
||||
B32 (68), B32 (69), B32 (70), B32 (71),
|
||||
B32 (72), B32 (73), B32 (74), B32 (75),
|
||||
B32 (76), B32 (77), B32 (78), B32 (79),
|
||||
B32 (80), B32 (81), B32 (82), B32 (83),
|
||||
B32 (84), B32 (85), B32 (86), B32 (87),
|
||||
B32 (88), B32 (89), B32 (90), B32 (91),
|
||||
B32 (92), B32 (93), B32 (94), B32 (95),
|
||||
B32 (96), B32 (97), B32 (98), B32 (99),
|
||||
B32 (100), B32 (101), B32 (102), B32 (103),
|
||||
B32 (104), B32 (105), B32 (106), B32 (107),
|
||||
B32 (108), B32 (109), B32 (110), B32 (111),
|
||||
B32 (112), B32 (113), B32 (114), B32 (115),
|
||||
B32 (116), B32 (117), B32 (118), B32 (119),
|
||||
B32 (120), B32 (121), B32 (122), B32 (123),
|
||||
B32 (124), B32 (125), B32 (126), B32 (127),
|
||||
B32 (128), B32 (129), B32 (130), B32 (131),
|
||||
B32 (132), B32 (133), B32 (134), B32 (135),
|
||||
B32 (136), B32 (137), B32 (138), B32 (139),
|
||||
B32 (140), B32 (141), B32 (142), B32 (143),
|
||||
B32 (144), B32 (145), B32 (146), B32 (147),
|
||||
B32 (148), B32 (149), B32 (150), B32 (151),
|
||||
B32 (152), B32 (153), B32 (154), B32 (155),
|
||||
B32 (156), B32 (157), B32 (158), B32 (159),
|
||||
B32 (160), B32 (161), B32 (162), B32 (163),
|
||||
B32 (132), B32 (165), B32 (166), B32 (167),
|
||||
B32 (168), B32 (169), B32 (170), B32 (171),
|
||||
B32 (172), B32 (173), B32 (174), B32 (175),
|
||||
B32 (176), B32 (177), B32 (178), B32 (179),
|
||||
B32 (180), B32 (181), B32 (182), B32 (183),
|
||||
B32 (184), B32 (185), B32 (186), B32 (187),
|
||||
B32 (188), B32 (189), B32 (190), B32 (191),
|
||||
B32 (192), B32 (193), B32 (194), B32 (195),
|
||||
B32 (196), B32 (197), B32 (198), B32 (199),
|
||||
B32 (200), B32 (201), B32 (202), B32 (203),
|
||||
B32 (204), B32 (205), B32 (206), B32 (207),
|
||||
B32 (208), B32 (209), B32 (210), B32 (211),
|
||||
B32 (212), B32 (213), B32 (214), B32 (215),
|
||||
B32 (216), B32 (217), B32 (218), B32 (219),
|
||||
B32 (220), B32 (221), B32 (222), B32 (223),
|
||||
B32 (224), B32 (225), B32 (226), B32 (227),
|
||||
B32 (228), B32 (229), B32 (230), B32 (231),
|
||||
B32 (232), B32 (233), B32 (234), B32 (235),
|
||||
B32 (236), B32 (237), B32 (238), B32 (239),
|
||||
B32 (240), B32 (241), B32 (242), B32 (243),
|
||||
B32 (244), B32 (245), B32 (246), B32 (247),
|
||||
B32 (248), B32 (249), B32 (250), B32 (251),
|
||||
B32 (252), B32 (253), B32 (254), B32 (255)
|
||||
};
|
||||
|
||||
#if UCHAR_MAX == 255
|
||||
# define uchar_in_range(c) true
|
||||
#else
|
||||
# define uchar_in_range(c) ((c) <= 255)
|
||||
#endif
|
||||
|
||||
/* Return true if CH is a character from the Base32 alphabet, and
|
||||
false otherwise. Note that '=' is padding and not considered to be
|
||||
part of the alphabet. */
|
||||
bool
|
||||
isbase32 (char ch)
|
||||
{
|
||||
return uchar_in_range (to_uchar (ch)) && 0 <= b32[to_uchar (ch)];
|
||||
}
|
||||
|
||||
/* Initialize decode-context buffer, CTX. */
|
||||
void
|
||||
base32_decode_ctx_init (struct base32_decode_context *ctx)
|
||||
{
|
||||
ctx->i = 0;
|
||||
}
|
||||
|
||||
/* If CTX->i is 0 or 8, there are eight or more bytes in [*IN..IN_END), and
|
||||
none of those eight is a newline, then return *IN. Otherwise, copy up to
|
||||
4 - CTX->i non-newline bytes from that range into CTX->buf, starting at
|
||||
index CTX->i and setting CTX->i to reflect the number of bytes copied,
|
||||
and return CTX->buf. In either case, advance *IN to point to the byte
|
||||
after the last one processed, and set *N_NON_NEWLINE to the number of
|
||||
verified non-newline bytes accessible through the returned pointer. */
|
||||
static char *
|
||||
get_8 (struct base32_decode_context *ctx,
|
||||
char const *restrict *in, char const *restrict in_end,
|
||||
size_t *n_non_newline)
|
||||
{
|
||||
if (ctx->i == 8)
|
||||
ctx->i = 0;
|
||||
|
||||
if (ctx->i == 0)
|
||||
{
|
||||
char const *t = *in;
|
||||
if (8 <= in_end - *in && memchr (t, '\n', 8) == NULL)
|
||||
{
|
||||
/* This is the common case: no newline. */
|
||||
*in += 8;
|
||||
*n_non_newline = 8;
|
||||
return (char *) t;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
/* Copy non-newline bytes into BUF. */
|
||||
char const *p = *in;
|
||||
while (p < in_end)
|
||||
{
|
||||
char c = *p++;
|
||||
if (c != '\n')
|
||||
{
|
||||
ctx->buf[ctx->i++] = c;
|
||||
if (ctx->i == 8)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*in = p;
|
||||
*n_non_newline = ctx->i;
|
||||
return ctx->buf;
|
||||
}
|
||||
}
|
||||
|
||||
#define return_false \
|
||||
do \
|
||||
{ \
|
||||
*outp = out; \
|
||||
return false; \
|
||||
} \
|
||||
while (false)
|
||||
|
||||
/* Decode eight bytes of base32-encoded data, IN, of length INLEN
|
||||
into the output buffer, *OUT, of size *OUTLEN bytes. Return true if
|
||||
decoding is successful, false otherwise. If *OUTLEN is too small,
|
||||
as many bytes as possible are written to *OUT. On return, advance
|
||||
*OUT to point to the byte after the last one written, and decrement
|
||||
*OUTLEN to reflect the number of bytes remaining in *OUT. */
|
||||
static bool
|
||||
decode_8 (char const *restrict in, size_t inlen,
|
||||
char *restrict *outp, size_t *outleft)
|
||||
{
|
||||
char *out = *outp;
|
||||
if (inlen < 8)
|
||||
return false;
|
||||
|
||||
if (!isbase32 (in[0]) || !isbase32 (in[1]) )
|
||||
return false;
|
||||
|
||||
if (*outleft)
|
||||
{
|
||||
*out++ = ((b32[to_uchar (in[0])] << 3)
|
||||
| (b32[to_uchar (in[1])] >> 2));
|
||||
--*outleft;
|
||||
}
|
||||
|
||||
if (in[2] == '=')
|
||||
{
|
||||
if (in[3] != '=' || in[4] != '=' || in[5] != '='
|
||||
|| in[6] != '=' || in[7] != '=')
|
||||
return_false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isbase32 (in[2]) || !isbase32 (in[3]))
|
||||
return_false;
|
||||
|
||||
if (*outleft)
|
||||
{
|
||||
*out++ = ((b32[to_uchar (in[1])] << 6)
|
||||
| (b32[to_uchar (in[2])] << 1)
|
||||
| (b32[to_uchar (in[3])] >> 4));
|
||||
--*outleft;
|
||||
}
|
||||
|
||||
if (in[4] == '=')
|
||||
{
|
||||
if (in[5] != '=' || in[6] != '=' || in[7] != '=')
|
||||
return_false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isbase32 (in[4]))
|
||||
return_false;
|
||||
|
||||
if (*outleft)
|
||||
{
|
||||
*out++ = ((b32[to_uchar (in[3])] << 4)
|
||||
| (b32[to_uchar (in[4])] >> 1));
|
||||
--*outleft;
|
||||
}
|
||||
|
||||
if (in[5] == '=')
|
||||
{
|
||||
if (in[6] != '=' || in[7] != '=')
|
||||
return_false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isbase32 (in[5]) || !isbase32 (in[6]))
|
||||
return_false;
|
||||
|
||||
if (*outleft)
|
||||
{
|
||||
*out++ = ((b32[to_uchar (in[4])] << 7)
|
||||
| (b32[to_uchar (in[5])] << 2)
|
||||
| (b32[to_uchar (in[6])] >> 3));
|
||||
--*outleft;
|
||||
}
|
||||
|
||||
if (in[7] != '=')
|
||||
{
|
||||
if (!isbase32 (in[7]))
|
||||
return_false;
|
||||
|
||||
if (*outleft)
|
||||
{
|
||||
*out++ = ((b32[to_uchar (in[6])] << 5)
|
||||
| (b32[to_uchar (in[7])]));
|
||||
--*outleft;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*outp = out;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Decode base32-encoded input array IN of length INLEN to output array
|
||||
OUT that can hold *OUTLEN bytes. The input data may be interspersed
|
||||
with newlines. Return true if decoding was successful, i.e. if the
|
||||
input was valid base32 data, false otherwise. If *OUTLEN is too
|
||||
small, as many bytes as possible will be written to OUT. On return,
|
||||
*OUTLEN holds the length of decoded bytes in OUT. Note that as soon
|
||||
as any non-alphabet, non-newline character is encountered, decoding
|
||||
is stopped and false is returned. If INLEN is zero, then process
|
||||
only whatever data is stored in CTX.
|
||||
|
||||
Initially, CTX must have been initialized via base32_decode_ctx_init.
|
||||
Subsequent calls to this function must reuse whatever state is recorded
|
||||
in that buffer. It is necessary for when a octuple of base32 input
|
||||
bytes spans two input buffers.
|
||||
|
||||
If CTX is NULL then newlines are treated as garbage and the input
|
||||
buffer is processed as a unit. */
|
||||
|
||||
bool
|
||||
base32_decode_ctx (struct base32_decode_context *ctx,
|
||||
const char *restrict in, size_t inlen,
|
||||
char *restrict out, size_t *outlen)
|
||||
{
|
||||
size_t outleft = *outlen;
|
||||
bool ignore_newlines = ctx != NULL;
|
||||
bool flush_ctx = false;
|
||||
unsigned int ctx_i = 0;
|
||||
|
||||
if (ignore_newlines)
|
||||
{
|
||||
ctx_i = ctx->i;
|
||||
flush_ctx = inlen == 0;
|
||||
}
|
||||
|
||||
|
||||
while (true)
|
||||
{
|
||||
size_t outleft_save = outleft;
|
||||
if (ctx_i == 0 && !flush_ctx)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
/* Save a copy of outleft, in case we need to re-parse this
|
||||
block of four bytes. */
|
||||
outleft_save = outleft;
|
||||
if (!decode_8 (in, inlen, &out, &outleft))
|
||||
break;
|
||||
|
||||
in += 8;
|
||||
inlen -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (inlen == 0 && !flush_ctx)
|
||||
break;
|
||||
|
||||
/* Handle the common case of 72-byte wrapped lines.
|
||||
This also handles any other multiple-of-8-byte wrapping. */
|
||||
if (inlen && *in == '\n' && ignore_newlines)
|
||||
{
|
||||
++in;
|
||||
--inlen;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Restore OUT and OUTLEFT. */
|
||||
out -= outleft_save - outleft;
|
||||
outleft = outleft_save;
|
||||
|
||||
{
|
||||
char const *in_end = in + inlen;
|
||||
char const *non_nl;
|
||||
|
||||
if (ignore_newlines)
|
||||
non_nl = get_8 (ctx, &in, in_end, &inlen);
|
||||
else
|
||||
non_nl = in; /* Might have nl in this case. */
|
||||
|
||||
/* If the input is empty or consists solely of newlines (0 non-newlines),
|
||||
then we're done. Likewise if there are fewer than 8 bytes when not
|
||||
flushing context and not treating newlines as garbage. */
|
||||
if (inlen == 0 || (inlen < 8 && !flush_ctx && ignore_newlines))
|
||||
{
|
||||
inlen = 0;
|
||||
break;
|
||||
}
|
||||
if (!decode_8 (non_nl, inlen, &out, &outleft))
|
||||
break;
|
||||
|
||||
inlen = in_end - in;
|
||||
}
|
||||
}
|
||||
|
||||
*outlen -= outleft;
|
||||
|
||||
return inlen == 0;
|
||||
}
|
||||
|
||||
/* Allocate an output buffer in *OUT, and decode the base32 encoded
|
||||
data stored in IN of size INLEN to the *OUT buffer. On return, the
|
||||
size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL,
|
||||
if the caller is not interested in the decoded length. *OUT may be
|
||||
NULL to indicate an out of memory error, in which case *OUTLEN
|
||||
contains the size of the memory block needed. The function returns
|
||||
true on successful decoding and memory allocation errors. (Use the
|
||||
*OUT and *OUTLEN parameters to differentiate between successful
|
||||
decoding and memory error.) The function returns false if the
|
||||
input was invalid, in which case *OUT is NULL and *OUTLEN is
|
||||
undefined. */
|
||||
bool
|
||||
base32_decode_alloc_ctx (struct base32_decode_context *ctx,
|
||||
const char *in, size_t inlen, char **out,
|
||||
size_t *outlen)
|
||||
{
|
||||
/* This may allocate a few bytes too many, depending on input,
|
||||
but it's not worth the extra CPU time to compute the exact size.
|
||||
The exact size is 5 * inlen / 8, minus one or more bytes if the
|
||||
input is padded with one or more "=".
|
||||
Dividing before multiplying avoids the possibility of overflow. */
|
||||
size_t needlen = 5 * (inlen / 8) + 5;
|
||||
|
||||
*out = malloc (needlen);
|
||||
if (!*out)
|
||||
return true;
|
||||
|
||||
if (!base32_decode_ctx (ctx, in, inlen, *out, &needlen))
|
||||
{
|
||||
free (*out);
|
||||
*out = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outlen)
|
||||
*outlen = needlen;
|
||||
|
||||
return true;
|
||||
}
|
||||
60
lib/base32.h
Normal file
60
lib/base32.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* base32.h -- Encode binary data using printable characters.
|
||||
Copyright (C) 2004-2006, 2009-2020 Free Software Foundation, Inc.
|
||||
Adapted from Simon Josefsson's base64 code by Gijs van Tulder.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef BASE32_H
|
||||
# define BASE32_H
|
||||
|
||||
/* Get size_t. */
|
||||
# include <stddef.h>
|
||||
|
||||
/* Get bool. */
|
||||
# include <stdbool.h>
|
||||
|
||||
/* This uses that the expression (n+(k-1))/k means the smallest
|
||||
integer >= n/k, i.e., the ceiling of n/k. */
|
||||
# define BASE32_LENGTH(inlen) ((((inlen) + 4) / 5) * 8)
|
||||
|
||||
struct base32_decode_context
|
||||
{
|
||||
unsigned int i;
|
||||
char buf[8];
|
||||
};
|
||||
|
||||
extern bool isbase32 (char ch) _GL_ATTRIBUTE_CONST;
|
||||
|
||||
extern void base32_encode (const char *restrict in, size_t inlen,
|
||||
char *restrict out, size_t outlen);
|
||||
|
||||
extern size_t base32_encode_alloc (const char *in, size_t inlen, char **out);
|
||||
|
||||
extern void base32_decode_ctx_init (struct base32_decode_context *ctx);
|
||||
|
||||
extern bool base32_decode_ctx (struct base32_decode_context *ctx,
|
||||
const char *restrict in, size_t inlen,
|
||||
char *restrict out, size_t *outlen);
|
||||
|
||||
extern bool base32_decode_alloc_ctx (struct base32_decode_context *ctx,
|
||||
const char *in, size_t inlen,
|
||||
char **out, size_t *outlen);
|
||||
|
||||
#define base32_decode(in, inlen, out, outlen) \
|
||||
base32_decode_ctx (NULL, in, inlen, out, outlen)
|
||||
|
||||
#define base32_decode_alloc(in, inlen, out, outlen) \
|
||||
base32_decode_alloc_ctx (NULL, in, inlen, out, outlen)
|
||||
|
||||
#endif /* BASE32_H */
|
||||
605
lib/base64.c
Normal file
605
lib/base64.c
Normal file
@@ -0,0 +1,605 @@
|
||||
/* base64.c -- Encode binary data using printable characters.
|
||||
Copyright (C) 1999-2001, 2004-2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Simon Josefsson. Partially adapted from GNU MailUtils
|
||||
* (mailbox/filter_trans.c, as of 2004-11-28). Improved by review
|
||||
* from Paul Eggert, Bruno Haible, and Stepan Kasal.
|
||||
*
|
||||
* See also RFC 4648 <https://www.ietf.org/rfc/rfc4648.txt>.
|
||||
*
|
||||
* Be careful with error checking. Here is how you would typically
|
||||
* use these functions:
|
||||
*
|
||||
* bool ok = base64_decode_alloc (in, inlen, &out, &outlen);
|
||||
* if (!ok)
|
||||
* FAIL: input was not valid base64
|
||||
* if (out == NULL)
|
||||
* FAIL: memory allocation error
|
||||
* OK: data in OUT/OUTLEN
|
||||
*
|
||||
* size_t outlen = base64_encode_alloc (in, inlen, &out);
|
||||
* if (out == NULL && outlen == 0 && inlen != 0)
|
||||
* FAIL: input too long
|
||||
* if (out == NULL)
|
||||
* FAIL: memory allocation error
|
||||
* OK: data in OUT/OUTLEN.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Get prototype. */
|
||||
#include "base64.h"
|
||||
|
||||
/* Get malloc. */
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Get UCHAR_MAX. */
|
||||
#include <limits.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* C89 compliant way to cast 'char' to 'unsigned char'. */
|
||||
static unsigned char
|
||||
to_uchar (char ch)
|
||||
{
|
||||
return ch;
|
||||
}
|
||||
|
||||
static const char b64c[64] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
/* Base64 encode IN array of size INLEN into OUT array. OUT needs
|
||||
to be of length >= BASE64_LENGTH(INLEN), and INLEN needs to be
|
||||
a multiple of 3. */
|
||||
static void
|
||||
base64_encode_fast (const char *restrict in, size_t inlen, char *restrict out)
|
||||
{
|
||||
while (inlen)
|
||||
{
|
||||
*out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
|
||||
*out++ = b64c[((to_uchar (in[0]) << 4) + (to_uchar (in[1]) >> 4)) & 0x3f];
|
||||
*out++ = b64c[((to_uchar (in[1]) << 2) + (to_uchar (in[2]) >> 6)) & 0x3f];
|
||||
*out++ = b64c[to_uchar (in[2]) & 0x3f];
|
||||
|
||||
inlen -= 3;
|
||||
in += 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
|
||||
If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as
|
||||
possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero
|
||||
terminate the output buffer. */
|
||||
void
|
||||
base64_encode (const char *restrict in, size_t inlen,
|
||||
char *restrict out, size_t outlen)
|
||||
{
|
||||
/* Note this outlen constraint can be enforced at compile time.
|
||||
I.E. that the output buffer is exactly large enough to hold
|
||||
the encoded inlen bytes. The inlen constraints (of corresponding
|
||||
to outlen, and being a multiple of 3) can change at runtime
|
||||
at the end of input. However the common case when reading
|
||||
large inputs is to have both constraints satisfied, so we depend
|
||||
on both in base_encode_fast(). */
|
||||
if (outlen % 4 == 0 && inlen == outlen / 4 * 3)
|
||||
{
|
||||
base64_encode_fast (in, inlen, out);
|
||||
return;
|
||||
}
|
||||
|
||||
while (inlen && outlen)
|
||||
{
|
||||
*out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
|
||||
if (!--outlen)
|
||||
break;
|
||||
*out++ = b64c[((to_uchar (in[0]) << 4)
|
||||
+ (--inlen ? to_uchar (in[1]) >> 4 : 0))
|
||||
& 0x3f];
|
||||
if (!--outlen)
|
||||
break;
|
||||
*out++ =
|
||||
(inlen
|
||||
? b64c[((to_uchar (in[1]) << 2)
|
||||
+ (--inlen ? to_uchar (in[2]) >> 6 : 0))
|
||||
& 0x3f]
|
||||
: '=');
|
||||
if (!--outlen)
|
||||
break;
|
||||
*out++ = inlen ? b64c[to_uchar (in[2]) & 0x3f] : '=';
|
||||
if (!--outlen)
|
||||
break;
|
||||
if (inlen)
|
||||
inlen--;
|
||||
if (inlen)
|
||||
in += 3;
|
||||
}
|
||||
|
||||
if (outlen)
|
||||
*out = '\0';
|
||||
}
|
||||
|
||||
/* Allocate a buffer and store zero terminated base64 encoded data
|
||||
from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e.,
|
||||
the length of the encoded data, excluding the terminating zero. On
|
||||
return, the OUT variable will hold a pointer to newly allocated
|
||||
memory that must be deallocated by the caller. If output string
|
||||
length would overflow, 0 is returned and OUT is set to NULL. If
|
||||
memory allocation failed, OUT is set to NULL, and the return value
|
||||
indicates length of the requested memory block, i.e.,
|
||||
BASE64_LENGTH(inlen) + 1. */
|
||||
size_t
|
||||
base64_encode_alloc (const char *in, size_t inlen, char **out)
|
||||
{
|
||||
size_t outlen = 1 + BASE64_LENGTH (inlen);
|
||||
|
||||
/* Check for overflow in outlen computation.
|
||||
*
|
||||
* If there is no overflow, outlen >= inlen.
|
||||
*
|
||||
* If the operation (inlen + 2) overflows then it yields at most +1, so
|
||||
* outlen is 0.
|
||||
*
|
||||
* If the multiplication overflows, we lose at least half of the
|
||||
* correct value, so the result is < ((inlen + 2) / 3) * 2, which is
|
||||
* less than (inlen + 2) * 0.66667, which is less than inlen as soon as
|
||||
* (inlen > 4).
|
||||
*/
|
||||
if (inlen > outlen)
|
||||
{
|
||||
*out = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out = malloc (outlen);
|
||||
if (!*out)
|
||||
return outlen;
|
||||
|
||||
base64_encode (in, inlen, *out, outlen);
|
||||
|
||||
return outlen - 1;
|
||||
}
|
||||
|
||||
/* With this approach this file works independent of the charset used
|
||||
(think EBCDIC). However, it does assume that the characters in the
|
||||
Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255. POSIX
|
||||
1003.1-2001 require that char and unsigned char are 8-bit
|
||||
quantities, though, taking care of that problem. But this may be a
|
||||
potential problem on non-POSIX C99 platforms.
|
||||
|
||||
IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_"
|
||||
as the formal parameter rather than "x". */
|
||||
#define B64(_) \
|
||||
((_) == 'A' ? 0 \
|
||||
: (_) == 'B' ? 1 \
|
||||
: (_) == 'C' ? 2 \
|
||||
: (_) == 'D' ? 3 \
|
||||
: (_) == 'E' ? 4 \
|
||||
: (_) == 'F' ? 5 \
|
||||
: (_) == 'G' ? 6 \
|
||||
: (_) == 'H' ? 7 \
|
||||
: (_) == 'I' ? 8 \
|
||||
: (_) == 'J' ? 9 \
|
||||
: (_) == 'K' ? 10 \
|
||||
: (_) == 'L' ? 11 \
|
||||
: (_) == 'M' ? 12 \
|
||||
: (_) == 'N' ? 13 \
|
||||
: (_) == 'O' ? 14 \
|
||||
: (_) == 'P' ? 15 \
|
||||
: (_) == 'Q' ? 16 \
|
||||
: (_) == 'R' ? 17 \
|
||||
: (_) == 'S' ? 18 \
|
||||
: (_) == 'T' ? 19 \
|
||||
: (_) == 'U' ? 20 \
|
||||
: (_) == 'V' ? 21 \
|
||||
: (_) == 'W' ? 22 \
|
||||
: (_) == 'X' ? 23 \
|
||||
: (_) == 'Y' ? 24 \
|
||||
: (_) == 'Z' ? 25 \
|
||||
: (_) == 'a' ? 26 \
|
||||
: (_) == 'b' ? 27 \
|
||||
: (_) == 'c' ? 28 \
|
||||
: (_) == 'd' ? 29 \
|
||||
: (_) == 'e' ? 30 \
|
||||
: (_) == 'f' ? 31 \
|
||||
: (_) == 'g' ? 32 \
|
||||
: (_) == 'h' ? 33 \
|
||||
: (_) == 'i' ? 34 \
|
||||
: (_) == 'j' ? 35 \
|
||||
: (_) == 'k' ? 36 \
|
||||
: (_) == 'l' ? 37 \
|
||||
: (_) == 'm' ? 38 \
|
||||
: (_) == 'n' ? 39 \
|
||||
: (_) == 'o' ? 40 \
|
||||
: (_) == 'p' ? 41 \
|
||||
: (_) == 'q' ? 42 \
|
||||
: (_) == 'r' ? 43 \
|
||||
: (_) == 's' ? 44 \
|
||||
: (_) == 't' ? 45 \
|
||||
: (_) == 'u' ? 46 \
|
||||
: (_) == 'v' ? 47 \
|
||||
: (_) == 'w' ? 48 \
|
||||
: (_) == 'x' ? 49 \
|
||||
: (_) == 'y' ? 50 \
|
||||
: (_) == 'z' ? 51 \
|
||||
: (_) == '0' ? 52 \
|
||||
: (_) == '1' ? 53 \
|
||||
: (_) == '2' ? 54 \
|
||||
: (_) == '3' ? 55 \
|
||||
: (_) == '4' ? 56 \
|
||||
: (_) == '5' ? 57 \
|
||||
: (_) == '6' ? 58 \
|
||||
: (_) == '7' ? 59 \
|
||||
: (_) == '8' ? 60 \
|
||||
: (_) == '9' ? 61 \
|
||||
: (_) == '+' ? 62 \
|
||||
: (_) == '/' ? 63 \
|
||||
: -1)
|
||||
|
||||
static const signed char b64[0x100] = {
|
||||
B64 (0), B64 (1), B64 (2), B64 (3),
|
||||
B64 (4), B64 (5), B64 (6), B64 (7),
|
||||
B64 (8), B64 (9), B64 (10), B64 (11),
|
||||
B64 (12), B64 (13), B64 (14), B64 (15),
|
||||
B64 (16), B64 (17), B64 (18), B64 (19),
|
||||
B64 (20), B64 (21), B64 (22), B64 (23),
|
||||
B64 (24), B64 (25), B64 (26), B64 (27),
|
||||
B64 (28), B64 (29), B64 (30), B64 (31),
|
||||
B64 (32), B64 (33), B64 (34), B64 (35),
|
||||
B64 (36), B64 (37), B64 (38), B64 (39),
|
||||
B64 (40), B64 (41), B64 (42), B64 (43),
|
||||
B64 (44), B64 (45), B64 (46), B64 (47),
|
||||
B64 (48), B64 (49), B64 (50), B64 (51),
|
||||
B64 (52), B64 (53), B64 (54), B64 (55),
|
||||
B64 (56), B64 (57), B64 (58), B64 (59),
|
||||
B64 (60), B64 (61), B64 (62), B64 (63),
|
||||
B64 (64), B64 (65), B64 (66), B64 (67),
|
||||
B64 (68), B64 (69), B64 (70), B64 (71),
|
||||
B64 (72), B64 (73), B64 (74), B64 (75),
|
||||
B64 (76), B64 (77), B64 (78), B64 (79),
|
||||
B64 (80), B64 (81), B64 (82), B64 (83),
|
||||
B64 (84), B64 (85), B64 (86), B64 (87),
|
||||
B64 (88), B64 (89), B64 (90), B64 (91),
|
||||
B64 (92), B64 (93), B64 (94), B64 (95),
|
||||
B64 (96), B64 (97), B64 (98), B64 (99),
|
||||
B64 (100), B64 (101), B64 (102), B64 (103),
|
||||
B64 (104), B64 (105), B64 (106), B64 (107),
|
||||
B64 (108), B64 (109), B64 (110), B64 (111),
|
||||
B64 (112), B64 (113), B64 (114), B64 (115),
|
||||
B64 (116), B64 (117), B64 (118), B64 (119),
|
||||
B64 (120), B64 (121), B64 (122), B64 (123),
|
||||
B64 (124), B64 (125), B64 (126), B64 (127),
|
||||
B64 (128), B64 (129), B64 (130), B64 (131),
|
||||
B64 (132), B64 (133), B64 (134), B64 (135),
|
||||
B64 (136), B64 (137), B64 (138), B64 (139),
|
||||
B64 (140), B64 (141), B64 (142), B64 (143),
|
||||
B64 (144), B64 (145), B64 (146), B64 (147),
|
||||
B64 (148), B64 (149), B64 (150), B64 (151),
|
||||
B64 (152), B64 (153), B64 (154), B64 (155),
|
||||
B64 (156), B64 (157), B64 (158), B64 (159),
|
||||
B64 (160), B64 (161), B64 (162), B64 (163),
|
||||
B64 (164), B64 (165), B64 (166), B64 (167),
|
||||
B64 (168), B64 (169), B64 (170), B64 (171),
|
||||
B64 (172), B64 (173), B64 (174), B64 (175),
|
||||
B64 (176), B64 (177), B64 (178), B64 (179),
|
||||
B64 (180), B64 (181), B64 (182), B64 (183),
|
||||
B64 (184), B64 (185), B64 (186), B64 (187),
|
||||
B64 (188), B64 (189), B64 (190), B64 (191),
|
||||
B64 (192), B64 (193), B64 (194), B64 (195),
|
||||
B64 (196), B64 (197), B64 (198), B64 (199),
|
||||
B64 (200), B64 (201), B64 (202), B64 (203),
|
||||
B64 (204), B64 (205), B64 (206), B64 (207),
|
||||
B64 (208), B64 (209), B64 (210), B64 (211),
|
||||
B64 (212), B64 (213), B64 (214), B64 (215),
|
||||
B64 (216), B64 (217), B64 (218), B64 (219),
|
||||
B64 (220), B64 (221), B64 (222), B64 (223),
|
||||
B64 (224), B64 (225), B64 (226), B64 (227),
|
||||
B64 (228), B64 (229), B64 (230), B64 (231),
|
||||
B64 (232), B64 (233), B64 (234), B64 (235),
|
||||
B64 (236), B64 (237), B64 (238), B64 (239),
|
||||
B64 (240), B64 (241), B64 (242), B64 (243),
|
||||
B64 (244), B64 (245), B64 (246), B64 (247),
|
||||
B64 (248), B64 (249), B64 (250), B64 (251),
|
||||
B64 (252), B64 (253), B64 (254), B64 (255)
|
||||
};
|
||||
|
||||
#if UCHAR_MAX == 255
|
||||
# define uchar_in_range(c) true
|
||||
#else
|
||||
# define uchar_in_range(c) ((c) <= 255)
|
||||
#endif
|
||||
|
||||
/* Return true if CH is a character from the Base64 alphabet, and
|
||||
false otherwise. Note that '=' is padding and not considered to be
|
||||
part of the alphabet. */
|
||||
bool
|
||||
isbase64 (char ch)
|
||||
{
|
||||
return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)];
|
||||
}
|
||||
|
||||
/* Initialize decode-context buffer, CTX. */
|
||||
void
|
||||
base64_decode_ctx_init (struct base64_decode_context *ctx)
|
||||
{
|
||||
ctx->i = 0;
|
||||
}
|
||||
|
||||
/* If CTX->i is 0 or 4, there are four or more bytes in [*IN..IN_END), and
|
||||
none of those four is a newline, then return *IN. Otherwise, copy up to
|
||||
4 - CTX->i non-newline bytes from that range into CTX->buf, starting at
|
||||
index CTX->i and setting CTX->i to reflect the number of bytes copied,
|
||||
and return CTX->buf. In either case, advance *IN to point to the byte
|
||||
after the last one processed, and set *N_NON_NEWLINE to the number of
|
||||
verified non-newline bytes accessible through the returned pointer. */
|
||||
static char *
|
||||
get_4 (struct base64_decode_context *ctx,
|
||||
char const *restrict *in, char const *restrict in_end,
|
||||
size_t *n_non_newline)
|
||||
{
|
||||
if (ctx->i == 4)
|
||||
ctx->i = 0;
|
||||
|
||||
if (ctx->i == 0)
|
||||
{
|
||||
char const *t = *in;
|
||||
if (4 <= in_end - *in && memchr (t, '\n', 4) == NULL)
|
||||
{
|
||||
/* This is the common case: no newline. */
|
||||
*in += 4;
|
||||
*n_non_newline = 4;
|
||||
return (char *) t;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
/* Copy non-newline bytes into BUF. */
|
||||
char const *p = *in;
|
||||
while (p < in_end)
|
||||
{
|
||||
char c = *p++;
|
||||
if (c != '\n')
|
||||
{
|
||||
ctx->buf[ctx->i++] = c;
|
||||
if (ctx->i == 4)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*in = p;
|
||||
*n_non_newline = ctx->i;
|
||||
return ctx->buf;
|
||||
}
|
||||
}
|
||||
|
||||
#define return_false \
|
||||
do \
|
||||
{ \
|
||||
*outp = out; \
|
||||
return false; \
|
||||
} \
|
||||
while (false)
|
||||
|
||||
/* Decode up to four bytes of base64-encoded data, IN, of length INLEN
|
||||
into the output buffer, *OUT, of size *OUTLEN bytes. Return true if
|
||||
decoding is successful, false otherwise. If *OUTLEN is too small,
|
||||
as many bytes as possible are written to *OUT. On return, advance
|
||||
*OUT to point to the byte after the last one written, and decrement
|
||||
*OUTLEN to reflect the number of bytes remaining in *OUT. */
|
||||
static bool
|
||||
decode_4 (char const *restrict in, size_t inlen,
|
||||
char *restrict *outp, size_t *outleft)
|
||||
{
|
||||
char *out = *outp;
|
||||
if (inlen < 2)
|
||||
return false;
|
||||
|
||||
if (!isbase64 (in[0]) || !isbase64 (in[1]))
|
||||
return false;
|
||||
|
||||
if (*outleft)
|
||||
{
|
||||
*out++ = ((b64[to_uchar (in[0])] << 2)
|
||||
| (b64[to_uchar (in[1])] >> 4));
|
||||
--*outleft;
|
||||
}
|
||||
|
||||
if (inlen == 2)
|
||||
return_false;
|
||||
|
||||
if (in[2] == '=')
|
||||
{
|
||||
if (inlen != 4)
|
||||
return_false;
|
||||
|
||||
if (in[3] != '=')
|
||||
return_false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isbase64 (in[2]))
|
||||
return_false;
|
||||
|
||||
if (*outleft)
|
||||
{
|
||||
*out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0)
|
||||
| (b64[to_uchar (in[2])] >> 2));
|
||||
--*outleft;
|
||||
}
|
||||
|
||||
if (inlen == 3)
|
||||
return_false;
|
||||
|
||||
if (in[3] == '=')
|
||||
{
|
||||
if (inlen != 4)
|
||||
return_false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isbase64 (in[3]))
|
||||
return_false;
|
||||
|
||||
if (*outleft)
|
||||
{
|
||||
*out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0)
|
||||
| b64[to_uchar (in[3])]);
|
||||
--*outleft;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*outp = out;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Decode base64-encoded input array IN of length INLEN to output array
|
||||
OUT that can hold *OUTLEN bytes. The input data may be interspersed
|
||||
with newlines. Return true if decoding was successful, i.e. if the
|
||||
input was valid base64 data, false otherwise. If *OUTLEN is too
|
||||
small, as many bytes as possible will be written to OUT. On return,
|
||||
*OUTLEN holds the length of decoded bytes in OUT. Note that as soon
|
||||
as any non-alphabet, non-newline character is encountered, decoding
|
||||
is stopped and false is returned. If INLEN is zero, then process
|
||||
only whatever data is stored in CTX.
|
||||
|
||||
Initially, CTX must have been initialized via base64_decode_ctx_init.
|
||||
Subsequent calls to this function must reuse whatever state is recorded
|
||||
in that buffer. It is necessary for when a quadruple of base64 input
|
||||
bytes spans two input buffers.
|
||||
|
||||
If CTX is NULL then newlines are treated as garbage and the input
|
||||
buffer is processed as a unit. */
|
||||
|
||||
bool
|
||||
base64_decode_ctx (struct base64_decode_context *ctx,
|
||||
const char *restrict in, size_t inlen,
|
||||
char *restrict out, size_t *outlen)
|
||||
{
|
||||
size_t outleft = *outlen;
|
||||
bool ignore_newlines = ctx != NULL;
|
||||
bool flush_ctx = false;
|
||||
unsigned int ctx_i = 0;
|
||||
|
||||
if (ignore_newlines)
|
||||
{
|
||||
ctx_i = ctx->i;
|
||||
flush_ctx = inlen == 0;
|
||||
}
|
||||
|
||||
|
||||
while (true)
|
||||
{
|
||||
size_t outleft_save = outleft;
|
||||
if (ctx_i == 0 && !flush_ctx)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
/* Save a copy of outleft, in case we need to re-parse this
|
||||
block of four bytes. */
|
||||
outleft_save = outleft;
|
||||
if (!decode_4 (in, inlen, &out, &outleft))
|
||||
break;
|
||||
|
||||
in += 4;
|
||||
inlen -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (inlen == 0 && !flush_ctx)
|
||||
break;
|
||||
|
||||
/* Handle the common case of 72-byte wrapped lines.
|
||||
This also handles any other multiple-of-4-byte wrapping. */
|
||||
if (inlen && *in == '\n' && ignore_newlines)
|
||||
{
|
||||
++in;
|
||||
--inlen;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Restore OUT and OUTLEFT. */
|
||||
out -= outleft_save - outleft;
|
||||
outleft = outleft_save;
|
||||
|
||||
{
|
||||
char const *in_end = in + inlen;
|
||||
char const *non_nl;
|
||||
|
||||
if (ignore_newlines)
|
||||
non_nl = get_4 (ctx, &in, in_end, &inlen);
|
||||
else
|
||||
non_nl = in; /* Might have nl in this case. */
|
||||
|
||||
/* If the input is empty or consists solely of newlines (0 non-newlines),
|
||||
then we're done. Likewise if there are fewer than 4 bytes when not
|
||||
flushing context and not treating newlines as garbage. */
|
||||
if (inlen == 0 || (inlen < 4 && !flush_ctx && ignore_newlines))
|
||||
{
|
||||
inlen = 0;
|
||||
break;
|
||||
}
|
||||
if (!decode_4 (non_nl, inlen, &out, &outleft))
|
||||
break;
|
||||
|
||||
inlen = in_end - in;
|
||||
}
|
||||
}
|
||||
|
||||
*outlen -= outleft;
|
||||
|
||||
return inlen == 0;
|
||||
}
|
||||
|
||||
/* Allocate an output buffer in *OUT, and decode the base64 encoded
|
||||
data stored in IN of size INLEN to the *OUT buffer. On return, the
|
||||
size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL,
|
||||
if the caller is not interested in the decoded length. *OUT may be
|
||||
NULL to indicate an out of memory error, in which case *OUTLEN
|
||||
contains the size of the memory block needed. The function returns
|
||||
true on successful decoding and memory allocation errors. (Use the
|
||||
*OUT and *OUTLEN parameters to differentiate between successful
|
||||
decoding and memory error.) The function returns false if the
|
||||
input was invalid, in which case *OUT is NULL and *OUTLEN is
|
||||
undefined. */
|
||||
bool
|
||||
base64_decode_alloc_ctx (struct base64_decode_context *ctx,
|
||||
const char *in, size_t inlen, char **out,
|
||||
size_t *outlen)
|
||||
{
|
||||
/* This may allocate a few bytes too many, depending on input,
|
||||
but it's not worth the extra CPU time to compute the exact size.
|
||||
The exact size is 3 * (inlen + (ctx ? ctx->i : 0)) / 4, minus 1 if the
|
||||
input ends with "=" and minus another 1 if the input ends with "==".
|
||||
Dividing before multiplying avoids the possibility of overflow. */
|
||||
size_t needlen = 3 * (inlen / 4) + 3;
|
||||
|
||||
*out = malloc (needlen);
|
||||
if (!*out)
|
||||
return true;
|
||||
|
||||
if (!base64_decode_ctx (ctx, in, inlen, *out, &needlen))
|
||||
{
|
||||
free (*out);
|
||||
*out = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outlen)
|
||||
*outlen = needlen;
|
||||
|
||||
return true;
|
||||
}
|
||||
68
lib/base64.h
Normal file
68
lib/base64.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* base64.h -- Encode binary data using printable characters.
|
||||
Copyright (C) 2004-2006, 2009-2020 Free Software Foundation, Inc.
|
||||
Written by Simon Josefsson.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef BASE64_H
|
||||
# define BASE64_H
|
||||
|
||||
/* Get size_t. */
|
||||
# include <stddef.h>
|
||||
|
||||
/* Get bool. */
|
||||
# include <stdbool.h>
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
/* This uses that the expression (n+(k-1))/k means the smallest
|
||||
integer >= n/k, i.e., the ceiling of n/k. */
|
||||
# define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4)
|
||||
|
||||
struct base64_decode_context
|
||||
{
|
||||
unsigned int i;
|
||||
char buf[4];
|
||||
};
|
||||
|
||||
extern bool isbase64 (char ch) _GL_ATTRIBUTE_CONST;
|
||||
|
||||
extern void base64_encode (const char *restrict in, size_t inlen,
|
||||
char *restrict out, size_t outlen);
|
||||
|
||||
extern size_t base64_encode_alloc (const char *in, size_t inlen, char **out);
|
||||
|
||||
extern void base64_decode_ctx_init (struct base64_decode_context *ctx);
|
||||
|
||||
extern bool base64_decode_ctx (struct base64_decode_context *ctx,
|
||||
const char *restrict in, size_t inlen,
|
||||
char *restrict out, size_t *outlen);
|
||||
|
||||
extern bool base64_decode_alloc_ctx (struct base64_decode_context *ctx,
|
||||
const char *in, size_t inlen,
|
||||
char **out, size_t *outlen);
|
||||
|
||||
#define base64_decode(in, inlen, out, outlen) \
|
||||
base64_decode_ctx (NULL, in, inlen, out, outlen)
|
||||
|
||||
#define base64_decode_alloc(in, inlen, out, outlen) \
|
||||
base64_decode_alloc_ctx (NULL, in, inlen, out, outlen)
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif /* BASE64_H */
|
||||
75
lib/basename-lgpl.c
Normal file
75
lib/basename-lgpl.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/* basename.c -- return the last element in a file name
|
||||
|
||||
Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2020 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "dirname.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Return the address of the last file name component of NAME. If
|
||||
NAME has no relative file name components because it is a file
|
||||
system root, return the empty string. */
|
||||
|
||||
char *
|
||||
last_component (char const *name)
|
||||
{
|
||||
char const *base = name + FILE_SYSTEM_PREFIX_LEN (name);
|
||||
char const *p;
|
||||
bool saw_slash = false;
|
||||
|
||||
while (ISSLASH (*base))
|
||||
base++;
|
||||
|
||||
for (p = base; *p; p++)
|
||||
{
|
||||
if (ISSLASH (*p))
|
||||
saw_slash = true;
|
||||
else if (saw_slash)
|
||||
{
|
||||
base = p;
|
||||
saw_slash = false;
|
||||
}
|
||||
}
|
||||
|
||||
return (char *) base;
|
||||
}
|
||||
|
||||
/* Return the length of the basename NAME. Typically NAME is the
|
||||
value returned by base_name or last_component. Act like strlen
|
||||
(NAME), except omit all trailing slashes. */
|
||||
|
||||
size_t
|
||||
base_len (char const *name)
|
||||
{
|
||||
size_t len;
|
||||
size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
|
||||
|
||||
for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--)
|
||||
continue;
|
||||
|
||||
if (DOUBLE_SLASH_IS_DISTINCT_ROOT && len == 1
|
||||
&& ISSLASH (name[0]) && ISSLASH (name[1]) && ! name[2])
|
||||
return 2;
|
||||
|
||||
if (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE && prefix_len
|
||||
&& len == prefix_len && ISSLASH (name[prefix_len]))
|
||||
return prefix_len + 1;
|
||||
|
||||
return len;
|
||||
}
|
||||
58
lib/basename.c
Normal file
58
lib/basename.c
Normal file
@@ -0,0 +1,58 @@
|
||||
/* basename.c -- return the last element in a file name
|
||||
|
||||
Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2020 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "dirname.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "xalloc.h"
|
||||
#include "xstrndup.h"
|
||||
|
||||
char *
|
||||
base_name (char const *name)
|
||||
{
|
||||
char const *base = last_component (name);
|
||||
size_t length;
|
||||
|
||||
/* If there is no last component, then name is a file system root or the
|
||||
empty string. */
|
||||
if (! *base)
|
||||
return xstrndup (name, base_len (name));
|
||||
|
||||
/* Collapse a sequence of trailing slashes into one. */
|
||||
length = base_len (base);
|
||||
if (ISSLASH (base[length]))
|
||||
length++;
|
||||
|
||||
/* On systems with drive letters, "a/b:c" must return "./b:c" rather
|
||||
than "b:c" to avoid confusion with a drive letter. On systems
|
||||
with pure POSIX semantics, this is not an issue. */
|
||||
if (FILE_SYSTEM_PREFIX_LEN (base))
|
||||
{
|
||||
char *p = xmalloc (length + 3);
|
||||
p[0] = '.';
|
||||
p[1] = '/';
|
||||
memcpy (p + 2, base, length);
|
||||
p[length + 2] = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Finally, copy the basename. */
|
||||
return xstrndup (base, length);
|
||||
}
|
||||
39
lib/binary-io.c
Normal file
39
lib/binary-io.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/* Binary mode I/O.
|
||||
Copyright 2017-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#define BINARY_IO_INLINE _GL_EXTERN_INLINE
|
||||
#include "binary-io.h"
|
||||
|
||||
#if defined __DJGPP__ || defined __EMX__
|
||||
# include <unistd.h>
|
||||
|
||||
int
|
||||
set_binary_mode (int fd, int mode)
|
||||
{
|
||||
if (isatty (fd))
|
||||
/* If FD refers to a console (not a pipe, not a regular file),
|
||||
O_TEXT is the only reasonable mode, both on input and on output.
|
||||
Silently ignore the request. If we were to return -1 here,
|
||||
all programs that use xset_binary_mode would fail when run
|
||||
with console input or console output. */
|
||||
return O_TEXT;
|
||||
else
|
||||
return __gl_setmode (fd, mode);
|
||||
}
|
||||
|
||||
#endif
|
||||
77
lib/binary-io.h
Normal file
77
lib/binary-io.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* Binary mode I/O.
|
||||
Copyright (C) 2001, 2003, 2005, 2008-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _BINARY_H
|
||||
#define _BINARY_H
|
||||
|
||||
/* For systems that distinguish between text and binary I/O.
|
||||
O_BINARY is guaranteed by the gnulib <fcntl.h>. */
|
||||
#include <fcntl.h>
|
||||
|
||||
/* The MSVC7 <stdio.h> doesn't like to be included after '#define fileno ...',
|
||||
so we include it here first. */
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef _GL_INLINE_HEADER_BEGIN
|
||||
#error "Please include config.h first."
|
||||
#endif
|
||||
_GL_INLINE_HEADER_BEGIN
|
||||
#ifndef BINARY_IO_INLINE
|
||||
# define BINARY_IO_INLINE _GL_INLINE
|
||||
#endif
|
||||
|
||||
#if O_BINARY
|
||||
# if defined __EMX__ || defined __DJGPP__ || defined __CYGWIN__
|
||||
# include <io.h> /* declares setmode() */
|
||||
# define __gl_setmode setmode
|
||||
# else
|
||||
# define __gl_setmode _setmode
|
||||
# undef fileno
|
||||
# define fileno _fileno
|
||||
# endif
|
||||
#else
|
||||
/* On reasonable systems, binary I/O is the only choice. */
|
||||
/* Use a function rather than a macro, to avoid gcc warnings
|
||||
"warning: statement with no effect". */
|
||||
BINARY_IO_INLINE int
|
||||
__gl_setmode (int fd _GL_UNUSED, int mode _GL_UNUSED)
|
||||
{
|
||||
return O_BINARY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set FD's mode to MODE, which should be either O_TEXT or O_BINARY.
|
||||
Return the old mode if successful, -1 (setting errno) on failure.
|
||||
Ordinarily this function would be called 'setmode', since that is
|
||||
its name on MS-Windows, but it is called 'set_binary_mode' here
|
||||
to avoid colliding with a BSD function of another name. */
|
||||
|
||||
#if defined __DJGPP__ || defined __EMX__
|
||||
extern int set_binary_mode (int fd, int mode);
|
||||
#else
|
||||
BINARY_IO_INLINE int
|
||||
set_binary_mode (int fd, int mode)
|
||||
{
|
||||
return __gl_setmode (fd, mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This macro is obsolescent. */
|
||||
#define SET_BINARY(fd) ((void) set_binary_mode (fd, O_BINARY))
|
||||
|
||||
_GL_INLINE_HEADER_END
|
||||
|
||||
#endif /* _BINARY_H */
|
||||
3
lib/bitrotate.c
Normal file
3
lib/bitrotate.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#include <config.h>
|
||||
#define BITROTATE_INLINE _GL_EXTERN_INLINE
|
||||
#include "bitrotate.h"
|
||||
138
lib/bitrotate.h
Normal file
138
lib/bitrotate.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/* bitrotate.h - Rotate bits in integers
|
||||
Copyright (C) 2008-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Simon Josefsson <simon@josefsson.org>, 2008. */
|
||||
|
||||
#ifndef _GL_BITROTATE_H
|
||||
#define _GL_BITROTATE_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef _GL_INLINE_HEADER_BEGIN
|
||||
#error "Please include config.h first."
|
||||
#endif
|
||||
_GL_INLINE_HEADER_BEGIN
|
||||
#ifndef BITROTATE_INLINE
|
||||
# define BITROTATE_INLINE _GL_INLINE
|
||||
#endif
|
||||
|
||||
#ifdef UINT64_MAX
|
||||
/* Given an unsigned 64-bit argument X, return the value corresponding
|
||||
to rotating the bits N steps to the left. N must be between 1 and
|
||||
63 inclusive. */
|
||||
BITROTATE_INLINE uint64_t
|
||||
rotl64 (uint64_t x, int n)
|
||||
{
|
||||
return ((x << n) | (x >> (64 - n))) & UINT64_MAX;
|
||||
}
|
||||
|
||||
/* Given an unsigned 64-bit argument X, return the value corresponding
|
||||
to rotating the bits N steps to the right. N must be between 1 to
|
||||
63 inclusive.*/
|
||||
BITROTATE_INLINE uint64_t
|
||||
rotr64 (uint64_t x, int n)
|
||||
{
|
||||
return ((x >> n) | (x << (64 - n))) & UINT64_MAX;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Given an unsigned 32-bit argument X, return the value corresponding
|
||||
to rotating the bits N steps to the left. N must be between 1 and
|
||||
31 inclusive. */
|
||||
BITROTATE_INLINE uint32_t
|
||||
rotl32 (uint32_t x, int n)
|
||||
{
|
||||
return ((x << n) | (x >> (32 - n))) & UINT32_MAX;
|
||||
}
|
||||
|
||||
/* Given an unsigned 32-bit argument X, return the value corresponding
|
||||
to rotating the bits N steps to the right. N must be between 1 to
|
||||
31 inclusive.*/
|
||||
BITROTATE_INLINE uint32_t
|
||||
rotr32 (uint32_t x, int n)
|
||||
{
|
||||
return ((x >> n) | (x << (32 - n))) & UINT32_MAX;
|
||||
}
|
||||
|
||||
/* Given a size_t argument X, return the value corresponding
|
||||
to rotating the bits N steps to the left. N must be between 1 and
|
||||
(CHAR_BIT * sizeof (size_t) - 1) inclusive. */
|
||||
BITROTATE_INLINE size_t
|
||||
rotl_sz (size_t x, int n)
|
||||
{
|
||||
return ((x << n) | (x >> ((CHAR_BIT * sizeof x) - n))) & SIZE_MAX;
|
||||
}
|
||||
|
||||
/* Given a size_t argument X, return the value corresponding
|
||||
to rotating the bits N steps to the right. N must be between 1 to
|
||||
(CHAR_BIT * sizeof (size_t) - 1) inclusive. */
|
||||
BITROTATE_INLINE size_t
|
||||
rotr_sz (size_t x, int n)
|
||||
{
|
||||
return ((x >> n) | (x << ((CHAR_BIT * sizeof x) - n))) & SIZE_MAX;
|
||||
}
|
||||
|
||||
/* Given an unsigned 16-bit argument X, return the value corresponding
|
||||
to rotating the bits N steps to the left. N must be between 1 to
|
||||
15 inclusive, but on most relevant targets N can also be 0 and 16
|
||||
because 'int' is at least 32 bits and the arguments must widen
|
||||
before shifting. */
|
||||
BITROTATE_INLINE uint16_t
|
||||
rotl16 (uint16_t x, int n)
|
||||
{
|
||||
return (((unsigned int) x << n) | ((unsigned int) x >> (16 - n)))
|
||||
& UINT16_MAX;
|
||||
}
|
||||
|
||||
/* Given an unsigned 16-bit argument X, return the value corresponding
|
||||
to rotating the bits N steps to the right. N must be in 1 to 15
|
||||
inclusive, but on most relevant targets N can also be 0 and 16
|
||||
because 'int' is at least 32 bits and the arguments must widen
|
||||
before shifting. */
|
||||
BITROTATE_INLINE uint16_t
|
||||
rotr16 (uint16_t x, int n)
|
||||
{
|
||||
return (((unsigned int) x >> n) | ((unsigned int) x << (16 - n)))
|
||||
& UINT16_MAX;
|
||||
}
|
||||
|
||||
/* Given an unsigned 8-bit argument X, return the value corresponding
|
||||
to rotating the bits N steps to the left. N must be between 1 to 7
|
||||
inclusive, but on most relevant targets N can also be 0 and 8
|
||||
because 'int' is at least 32 bits and the arguments must widen
|
||||
before shifting. */
|
||||
BITROTATE_INLINE uint8_t
|
||||
rotl8 (uint8_t x, int n)
|
||||
{
|
||||
return (((unsigned int) x << n) | ((unsigned int) x >> (8 - n))) & UINT8_MAX;
|
||||
}
|
||||
|
||||
/* Given an unsigned 8-bit argument X, return the value corresponding
|
||||
to rotating the bits N steps to the right. N must be in 1 to 7
|
||||
inclusive, but on most relevant targets N can also be 0 and 8
|
||||
because 'int' is at least 32 bits and the arguments must widen
|
||||
before shifting. */
|
||||
BITROTATE_INLINE uint8_t
|
||||
rotr8 (uint8_t x, int n)
|
||||
{
|
||||
return (((unsigned int) x >> n) | ((unsigned int) x << (8 - n))) & UINT8_MAX;
|
||||
}
|
||||
|
||||
_GL_INLINE_HEADER_END
|
||||
|
||||
#endif /* _GL_BITROTATE_H */
|
||||
39
lib/btowc.c
Normal file
39
lib/btowc.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/* Convert unibyte character to wide character.
|
||||
Copyright (C) 2008, 2010-2020 Free Software Foundation, Inc.
|
||||
Written by Bruno Haible <bruno@clisp.org>, 2008.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include <wchar.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
wint_t
|
||||
btowc (int c)
|
||||
{
|
||||
if (c != EOF)
|
||||
{
|
||||
char buf[1];
|
||||
wchar_t wc;
|
||||
|
||||
buf[0] = c;
|
||||
if (mbtowc (&wc, buf, 1) >= 0)
|
||||
return wc;
|
||||
}
|
||||
return WEOF;
|
||||
}
|
||||
59
lib/buffer-lcm.c
Normal file
59
lib/buffer-lcm.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/* buffer-lcm.c - compute a good buffer size for dealing with two files
|
||||
|
||||
Copyright (C) 2002-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Paul Eggert. */
|
||||
|
||||
#include <config.h>
|
||||
#include "buffer-lcm.h"
|
||||
|
||||
/* Return a buffer size suitable for doing I/O with files whose block
|
||||
sizes are A and B. However, never return a value greater than
|
||||
LCM_MAX. */
|
||||
|
||||
size_t
|
||||
buffer_lcm (size_t a, size_t b, size_t lcm_max)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
/* Use reasonable values if buffer sizes are zero. */
|
||||
if (!a)
|
||||
size = b ? b : 8 * 1024;
|
||||
else
|
||||
{
|
||||
if (b)
|
||||
{
|
||||
/* Return lcm (A, B) if it is in range; otherwise, fall back
|
||||
on A. */
|
||||
|
||||
size_t lcm, m, n, q, r;
|
||||
|
||||
/* N = gcd (A, B). */
|
||||
for (m = a, n = b; (r = m % n) != 0; m = n, n = r)
|
||||
continue;
|
||||
|
||||
/* LCM = lcm (A, B), if in range. */
|
||||
q = a / n;
|
||||
lcm = q * b;
|
||||
if (lcm <= lcm_max && lcm / b == q)
|
||||
return lcm;
|
||||
}
|
||||
|
||||
size = a;
|
||||
}
|
||||
|
||||
return size <= lcm_max ? size : lcm_max;
|
||||
}
|
||||
2
lib/buffer-lcm.h
Normal file
2
lib/buffer-lcm.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#include <stddef.h>
|
||||
size_t buffer_lcm (size_t, size_t, size_t) _GL_ATTRIBUTE_CONST;
|
||||
44
lib/byteswap.in.h
Normal file
44
lib/byteswap.in.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* byteswap.h - Byte swapping
|
||||
Copyright (C) 2005, 2007, 2009-2020 Free Software Foundation, Inc.
|
||||
Written by Oskar Liljeblad <oskar@osk.mine.nu>, 2005.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _GL_BYTESWAP_H
|
||||
#define _GL_BYTESWAP_H
|
||||
|
||||
/* Given an unsigned 16-bit argument X, return the value corresponding to
|
||||
X with reversed byte order. */
|
||||
#define bswap_16(x) ((((x) & 0x00FF) << 8) | \
|
||||
(((x) & 0xFF00) >> 8))
|
||||
|
||||
/* Given an unsigned 32-bit argument X, return the value corresponding to
|
||||
X with reversed byte order. */
|
||||
#define bswap_32(x) ((((x) & 0x000000FF) << 24) | \
|
||||
(((x) & 0x0000FF00) << 8) | \
|
||||
(((x) & 0x00FF0000) >> 8) | \
|
||||
(((x) & 0xFF000000) >> 24))
|
||||
|
||||
/* Given an unsigned 64-bit argument X, return the value corresponding to
|
||||
X with reversed byte order. */
|
||||
#define bswap_64(x) ((((x) & 0x00000000000000FFULL) << 56) | \
|
||||
(((x) & 0x000000000000FF00ULL) << 40) | \
|
||||
(((x) & 0x0000000000FF0000ULL) << 24) | \
|
||||
(((x) & 0x00000000FF000000ULL) << 8) | \
|
||||
(((x) & 0x000000FF00000000ULL) >> 8) | \
|
||||
(((x) & 0x0000FF0000000000ULL) >> 24) | \
|
||||
(((x) & 0x00FF000000000000ULL) >> 40) | \
|
||||
(((x) & 0xFF00000000000000ULL) >> 56))
|
||||
|
||||
#endif /* _GL_BYTESWAP_H */
|
||||
313
lib/c++defs.h
Normal file
313
lib/c++defs.h
Normal file
@@ -0,0 +1,313 @@
|
||||
/* C++ compatible function declaration macros.
|
||||
Copyright (C) 2010-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _GL_CXXDEFS_H
|
||||
#define _GL_CXXDEFS_H
|
||||
|
||||
/* Begin/end the GNULIB_NAMESPACE namespace. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_BEGIN_NAMESPACE namespace GNULIB_NAMESPACE {
|
||||
# define _GL_END_NAMESPACE }
|
||||
#else
|
||||
# define _GL_BEGIN_NAMESPACE
|
||||
# define _GL_END_NAMESPACE
|
||||
#endif
|
||||
|
||||
/* The three most frequent use cases of these macros are:
|
||||
|
||||
* For providing a substitute for a function that is missing on some
|
||||
platforms, but is declared and works fine on the platforms on which
|
||||
it exists:
|
||||
|
||||
#if @GNULIB_FOO@
|
||||
# if !@HAVE_FOO@
|
||||
_GL_FUNCDECL_SYS (foo, ...);
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (foo, ...);
|
||||
_GL_CXXALIASWARN (foo);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
...
|
||||
#endif
|
||||
|
||||
* For providing a replacement for a function that exists on all platforms,
|
||||
but is broken/insufficient and needs to be replaced on some platforms:
|
||||
|
||||
#if @GNULIB_FOO@
|
||||
# if @REPLACE_FOO@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef foo
|
||||
# define foo rpl_foo
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (foo, ...);
|
||||
_GL_CXXALIAS_RPL (foo, ...);
|
||||
# else
|
||||
_GL_CXXALIAS_SYS (foo, ...);
|
||||
# endif
|
||||
_GL_CXXALIASWARN (foo);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
...
|
||||
#endif
|
||||
|
||||
* For providing a replacement for a function that exists on some platforms
|
||||
but is broken/insufficient and needs to be replaced on some of them and
|
||||
is additionally either missing or undeclared on some other platforms:
|
||||
|
||||
#if @GNULIB_FOO@
|
||||
# if @REPLACE_FOO@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef foo
|
||||
# define foo rpl_foo
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (foo, ...);
|
||||
_GL_CXXALIAS_RPL (foo, ...);
|
||||
# else
|
||||
# if !@HAVE_FOO@ or if !@HAVE_DECL_FOO@
|
||||
_GL_FUNCDECL_SYS (foo, ...);
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (foo, ...);
|
||||
# endif
|
||||
_GL_CXXALIASWARN (foo);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
...
|
||||
#endif
|
||||
*/
|
||||
|
||||
/* _GL_EXTERN_C declaration;
|
||||
performs the declaration with C linkage. */
|
||||
#if defined __cplusplus
|
||||
# define _GL_EXTERN_C extern "C"
|
||||
#else
|
||||
# define _GL_EXTERN_C extern
|
||||
#endif
|
||||
|
||||
/* _GL_FUNCDECL_RPL (func, rettype, parameters_and_attributes);
|
||||
declares a replacement function, named rpl_func, with the given prototype,
|
||||
consisting of return type, parameters, and attributes.
|
||||
Example:
|
||||
_GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...)
|
||||
_GL_ARG_NONNULL ((1)));
|
||||
*/
|
||||
#define _GL_FUNCDECL_RPL(func,rettype,parameters_and_attributes) \
|
||||
_GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters_and_attributes)
|
||||
#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters_and_attributes) \
|
||||
_GL_EXTERN_C rettype rpl_func parameters_and_attributes
|
||||
|
||||
/* _GL_FUNCDECL_SYS (func, rettype, parameters_and_attributes);
|
||||
declares the system function, named func, with the given prototype,
|
||||
consisting of return type, parameters, and attributes.
|
||||
Example:
|
||||
_GL_FUNCDECL_SYS (open, int, (const char *filename, int flags, ...)
|
||||
_GL_ARG_NONNULL ((1)));
|
||||
*/
|
||||
#define _GL_FUNCDECL_SYS(func,rettype,parameters_and_attributes) \
|
||||
_GL_EXTERN_C rettype func parameters_and_attributes
|
||||
|
||||
/* _GL_CXXALIAS_RPL (func, rettype, parameters);
|
||||
declares a C++ alias called GNULIB_NAMESPACE::func
|
||||
that redirects to rpl_func, if GNULIB_NAMESPACE is defined.
|
||||
Example:
|
||||
_GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...));
|
||||
|
||||
Wrapping rpl_func in an object with an inline conversion operator
|
||||
avoids a reference to rpl_func unless GNULIB_NAMESPACE::func is
|
||||
actually used in the program. */
|
||||
#define _GL_CXXALIAS_RPL(func,rettype,parameters) \
|
||||
_GL_CXXALIAS_RPL_1 (func, rpl_##func, rettype, parameters)
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return ::rpl_func; \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIAS_RPL_CAST_1 (func, rpl_func, rettype, parameters);
|
||||
is like _GL_CXXALIAS_RPL_1 (func, rpl_func, rettype, parameters);
|
||||
except that the C function rpl_func may have a slightly different
|
||||
declaration. A cast is used to silence the "invalid conversion" error
|
||||
that would otherwise occur. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return reinterpret_cast<type>(::rpl_func); \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIAS_SYS (func, rettype, parameters);
|
||||
declares a C++ alias called GNULIB_NAMESPACE::func
|
||||
that redirects to the system provided function func, if GNULIB_NAMESPACE
|
||||
is defined.
|
||||
Example:
|
||||
_GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));
|
||||
|
||||
Wrapping func in an object with an inline conversion operator
|
||||
avoids a reference to func unless GNULIB_NAMESPACE::func is
|
||||
actually used in the program. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return ::func; \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIAS_SYS_CAST (func, rettype, parameters);
|
||||
is like _GL_CXXALIAS_SYS (func, rettype, parameters);
|
||||
except that the C function func may have a slightly different declaration.
|
||||
A cast is used to silence the "invalid conversion" error that would
|
||||
otherwise occur. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return reinterpret_cast<type>(::func); \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIAS_SYS_CAST2 (func, rettype, parameters, rettype2, parameters2);
|
||||
is like _GL_CXXALIAS_SYS (func, rettype, parameters);
|
||||
except that the C function is picked among a set of overloaded functions,
|
||||
namely the one with rettype2 and parameters2. Two consecutive casts
|
||||
are used to silence the "cannot find a match" and "invalid conversion"
|
||||
errors that would otherwise occur. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
/* The outer cast must be a reinterpret_cast.
|
||||
The inner cast: When the function is defined as a set of overloaded
|
||||
functions, it works as a static_cast<>, choosing the designated variant.
|
||||
When the function is defined as a single variant, it works as a
|
||||
reinterpret_cast<>. The parenthesized cast syntax works both ways. */
|
||||
# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return reinterpret_cast<type>((rettype2 (*) parameters2)(::func)); \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIASWARN (func);
|
||||
causes a warning to be emitted when ::func is used but not when
|
||||
GNULIB_NAMESPACE::func is used. func must be defined without overloaded
|
||||
variants. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIASWARN(func) \
|
||||
_GL_CXXALIASWARN_1 (func, GNULIB_NAMESPACE)
|
||||
# define _GL_CXXALIASWARN_1(func,namespace) \
|
||||
_GL_CXXALIASWARN_2 (func, namespace)
|
||||
/* To work around GCC bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43881>,
|
||||
we enable the warning only when not optimizing. */
|
||||
# if !__OPTIMIZE__
|
||||
# define _GL_CXXALIASWARN_2(func,namespace) \
|
||||
_GL_WARN_ON_USE (func, \
|
||||
"The symbol ::" #func " refers to the system function. " \
|
||||
"Use " #namespace "::" #func " instead.")
|
||||
# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
|
||||
# define _GL_CXXALIASWARN_2(func,namespace) \
|
||||
extern __typeof__ (func) func
|
||||
# else
|
||||
# define _GL_CXXALIASWARN_2(func,namespace) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
# endif
|
||||
#else
|
||||
# define _GL_CXXALIASWARN(func) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIASWARN1 (func, rettype, parameters_and_attributes);
|
||||
causes a warning to be emitted when the given overloaded variant of ::func
|
||||
is used but not when GNULIB_NAMESPACE::func is used. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
|
||||
_GL_CXXALIASWARN1_1 (func, rettype, parameters_and_attributes, \
|
||||
GNULIB_NAMESPACE)
|
||||
# define _GL_CXXALIASWARN1_1(func,rettype,parameters_and_attributes,namespace) \
|
||||
_GL_CXXALIASWARN1_2 (func, rettype, parameters_and_attributes, namespace)
|
||||
/* To work around GCC bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43881>,
|
||||
we enable the warning only when not optimizing. */
|
||||
# if !__OPTIMIZE__
|
||||
# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
|
||||
_GL_WARN_ON_USE_CXX (func, rettype, parameters_and_attributes, \
|
||||
"The symbol ::" #func " refers to the system function. " \
|
||||
"Use " #namespace "::" #func " instead.")
|
||||
# else
|
||||
# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
# endif
|
||||
#else
|
||||
# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
#endif /* _GL_CXXDEFS_H */
|
||||
3
lib/c-ctype.c
Normal file
3
lib/c-ctype.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#include <config.h>
|
||||
#define C_CTYPE_INLINE _GL_EXTERN_INLINE
|
||||
#include "c-ctype.h"
|
||||
366
lib/c-ctype.h
Normal file
366
lib/c-ctype.h
Normal file
@@ -0,0 +1,366 @@
|
||||
/* Character handling in C locale.
|
||||
|
||||
These functions work like the corresponding functions in <ctype.h>,
|
||||
except that they have the C (POSIX) locale hardwired, whereas the
|
||||
<ctype.h> functions' behaviour depends on the current locale set via
|
||||
setlocale.
|
||||
|
||||
Copyright (C) 2000-2003, 2006, 2008-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef C_CTYPE_H
|
||||
#define C_CTYPE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef _GL_INLINE_HEADER_BEGIN
|
||||
#error "Please include config.h first."
|
||||
#endif
|
||||
_GL_INLINE_HEADER_BEGIN
|
||||
#ifndef C_CTYPE_INLINE
|
||||
# define C_CTYPE_INLINE _GL_INLINE
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* The functions defined in this file assume the "C" locale and a character
|
||||
set without diacritics (ASCII-US or EBCDIC-US or something like that).
|
||||
Even if the "C" locale on a particular system is an extension of the ASCII
|
||||
character set (like on BeOS, where it is UTF-8, or on AmigaOS, where it
|
||||
is ISO-8859-1), the functions in this file recognize only the ASCII
|
||||
characters. */
|
||||
|
||||
|
||||
#if (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
||||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
||||
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
|
||||
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
|
||||
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
|
||||
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
|
||||
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
|
||||
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
|
||||
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
|
||||
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
|
||||
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
|
||||
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
|
||||
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
|
||||
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
|
||||
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
|
||||
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
|
||||
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
|
||||
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
|
||||
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
|
||||
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
|
||||
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
|
||||
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
|
||||
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)
|
||||
/* The character set is ASCII or one of its variants or extensions, not EBCDIC.
|
||||
Testing the value of '\n' and '\r' is not relevant. */
|
||||
# define C_CTYPE_ASCII 1
|
||||
#elif ! (' ' == '\x40' && '0' == '\xf0' \
|
||||
&& 'A' == '\xc1' && 'J' == '\xd1' && 'S' == '\xe2' \
|
||||
&& 'a' == '\x81' && 'j' == '\x91' && 's' == '\xa2')
|
||||
# error "Only ASCII and EBCDIC are supported"
|
||||
#endif
|
||||
|
||||
#if 'A' < 0
|
||||
# error "EBCDIC and char is signed -- not supported"
|
||||
#endif
|
||||
|
||||
/* Cases for control characters. */
|
||||
|
||||
#define _C_CTYPE_CNTRL \
|
||||
case '\a': case '\b': case '\f': case '\n': \
|
||||
case '\r': case '\t': case '\v': \
|
||||
_C_CTYPE_OTHER_CNTRL
|
||||
|
||||
/* ASCII control characters other than those with \-letter escapes. */
|
||||
|
||||
#if C_CTYPE_ASCII
|
||||
# define _C_CTYPE_OTHER_CNTRL \
|
||||
case '\x00': case '\x01': case '\x02': case '\x03': \
|
||||
case '\x04': case '\x05': case '\x06': case '\x0e': \
|
||||
case '\x0f': case '\x10': case '\x11': case '\x12': \
|
||||
case '\x13': case '\x14': case '\x15': case '\x16': \
|
||||
case '\x17': case '\x18': case '\x19': case '\x1a': \
|
||||
case '\x1b': case '\x1c': case '\x1d': case '\x1e': \
|
||||
case '\x1f': case '\x7f'
|
||||
#else
|
||||
/* Use EBCDIC code page 1047's assignments for ASCII control chars;
|
||||
assume all EBCDIC code pages agree about these assignments. */
|
||||
# define _C_CTYPE_OTHER_CNTRL \
|
||||
case '\x00': case '\x01': case '\x02': case '\x03': \
|
||||
case '\x07': case '\x0e': case '\x0f': case '\x10': \
|
||||
case '\x11': case '\x12': case '\x13': case '\x18': \
|
||||
case '\x19': case '\x1c': case '\x1d': case '\x1e': \
|
||||
case '\x1f': case '\x26': case '\x27': case '\x2d': \
|
||||
case '\x2e': case '\x32': case '\x37': case '\x3c': \
|
||||
case '\x3d': case '\x3f'
|
||||
#endif
|
||||
|
||||
/* Cases for lowercase hex letters, and lowercase letters, all offset by N. */
|
||||
|
||||
#define _C_CTYPE_LOWER_A_THRU_F_N(N) \
|
||||
case 'a' + (N): case 'b' + (N): case 'c' + (N): case 'd' + (N): \
|
||||
case 'e' + (N): case 'f' + (N)
|
||||
#define _C_CTYPE_LOWER_N(N) \
|
||||
_C_CTYPE_LOWER_A_THRU_F_N(N): \
|
||||
case 'g' + (N): case 'h' + (N): case 'i' + (N): case 'j' + (N): \
|
||||
case 'k' + (N): case 'l' + (N): case 'm' + (N): case 'n' + (N): \
|
||||
case 'o' + (N): case 'p' + (N): case 'q' + (N): case 'r' + (N): \
|
||||
case 's' + (N): case 't' + (N): case 'u' + (N): case 'v' + (N): \
|
||||
case 'w' + (N): case 'x' + (N): case 'y' + (N): case 'z' + (N)
|
||||
|
||||
/* Cases for hex letters, digits, lower, punct, and upper. */
|
||||
|
||||
#define _C_CTYPE_A_THRU_F \
|
||||
_C_CTYPE_LOWER_A_THRU_F_N (0): \
|
||||
_C_CTYPE_LOWER_A_THRU_F_N ('A' - 'a')
|
||||
#define _C_CTYPE_DIGIT \
|
||||
case '0': case '1': case '2': case '3': \
|
||||
case '4': case '5': case '6': case '7': \
|
||||
case '8': case '9'
|
||||
#define _C_CTYPE_LOWER _C_CTYPE_LOWER_N (0)
|
||||
#define _C_CTYPE_PUNCT \
|
||||
case '!': case '"': case '#': case '$': \
|
||||
case '%': case '&': case '\'': case '(': \
|
||||
case ')': case '*': case '+': case ',': \
|
||||
case '-': case '.': case '/': case ':': \
|
||||
case ';': case '<': case '=': case '>': \
|
||||
case '?': case '@': case '[': case '\\': \
|
||||
case ']': case '^': case '_': case '`': \
|
||||
case '{': case '|': case '}': case '~'
|
||||
#define _C_CTYPE_UPPER _C_CTYPE_LOWER_N ('A' - 'a')
|
||||
|
||||
|
||||
/* Function definitions. */
|
||||
|
||||
/* Unlike the functions in <ctype.h>, which require an argument in the range
|
||||
of the 'unsigned char' type, the functions here operate on values that are
|
||||
in the 'unsigned char' range or in the 'char' range. In other words,
|
||||
when you have a 'char' value, you need to cast it before using it as
|
||||
argument to a <ctype.h> function:
|
||||
|
||||
const char *s = ...;
|
||||
if (isalpha ((unsigned char) *s)) ...
|
||||
|
||||
but you don't need to cast it for the functions defined in this file:
|
||||
|
||||
const char *s = ...;
|
||||
if (c_isalpha (*s)) ...
|
||||
*/
|
||||
|
||||
C_CTYPE_INLINE bool
|
||||
c_isalnum (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
_C_CTYPE_DIGIT:
|
||||
_C_CTYPE_LOWER:
|
||||
_C_CTYPE_UPPER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
C_CTYPE_INLINE bool
|
||||
c_isalpha (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
_C_CTYPE_LOWER:
|
||||
_C_CTYPE_UPPER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* The function isascii is not locale dependent.
|
||||
Its use in EBCDIC is questionable. */
|
||||
C_CTYPE_INLINE bool
|
||||
c_isascii (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case ' ':
|
||||
_C_CTYPE_CNTRL:
|
||||
_C_CTYPE_DIGIT:
|
||||
_C_CTYPE_LOWER:
|
||||
_C_CTYPE_PUNCT:
|
||||
_C_CTYPE_UPPER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
C_CTYPE_INLINE bool
|
||||
c_isblank (int c)
|
||||
{
|
||||
return c == ' ' || c == '\t';
|
||||
}
|
||||
|
||||
C_CTYPE_INLINE bool
|
||||
c_iscntrl (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
_C_CTYPE_CNTRL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
C_CTYPE_INLINE bool
|
||||
c_isdigit (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
_C_CTYPE_DIGIT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
C_CTYPE_INLINE bool
|
||||
c_isgraph (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
_C_CTYPE_DIGIT:
|
||||
_C_CTYPE_LOWER:
|
||||
_C_CTYPE_PUNCT:
|
||||
_C_CTYPE_UPPER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
C_CTYPE_INLINE bool
|
||||
c_islower (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
_C_CTYPE_LOWER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
C_CTYPE_INLINE bool
|
||||
c_isprint (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case ' ':
|
||||
_C_CTYPE_DIGIT:
|
||||
_C_CTYPE_LOWER:
|
||||
_C_CTYPE_PUNCT:
|
||||
_C_CTYPE_UPPER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
C_CTYPE_INLINE bool
|
||||
c_ispunct (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
_C_CTYPE_PUNCT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
C_CTYPE_INLINE bool
|
||||
c_isspace (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case ' ': case '\t': case '\n': case '\v': case '\f': case '\r':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
C_CTYPE_INLINE bool
|
||||
c_isupper (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
_C_CTYPE_UPPER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
C_CTYPE_INLINE bool
|
||||
c_isxdigit (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
_C_CTYPE_DIGIT:
|
||||
_C_CTYPE_A_THRU_F:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
C_CTYPE_INLINE int
|
||||
c_tolower (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
_C_CTYPE_UPPER:
|
||||
return c - 'A' + 'a';
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
C_CTYPE_INLINE int
|
||||
c_toupper (int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
_C_CTYPE_LOWER:
|
||||
return c - 'a' + 'A';
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
_GL_INLINE_HEADER_END
|
||||
|
||||
#endif /* C_CTYPE_H */
|
||||
56
lib/c-strcase.h
Normal file
56
lib/c-strcase.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* Case-insensitive string comparison functions in C locale.
|
||||
Copyright (C) 1995-1996, 2001, 2003, 2005, 2009-2020 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef C_STRCASE_H
|
||||
#define C_STRCASE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
/* The functions defined in this file assume the "C" locale and a character
|
||||
set without diacritics (ASCII-US or EBCDIC-US or something like that).
|
||||
Even if the "C" locale on a particular system is an extension of the ASCII
|
||||
character set (like on BeOS, where it is UTF-8, or on AmigaOS, where it
|
||||
is ISO-8859-1), the functions in this file recognize only the ASCII
|
||||
characters. More precisely, one of the string arguments must be an ASCII
|
||||
string; the other one can also contain non-ASCII characters (but then
|
||||
the comparison result will be nonzero). */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Compare strings S1 and S2, ignoring case, returning less than, equal to or
|
||||
greater than zero if S1 is lexicographically less than, equal to or greater
|
||||
than S2. */
|
||||
extern int c_strcasecmp (const char *s1, const char *s2) _GL_ATTRIBUTE_PURE;
|
||||
|
||||
/* Compare no more than N characters of strings S1 and S2, ignoring case,
|
||||
returning less than, equal to or greater than zero if S1 is
|
||||
lexicographically less than, equal to or greater than S2. */
|
||||
extern int c_strncasecmp (const char *s1, const char *s2, size_t n)
|
||||
_GL_ATTRIBUTE_PURE;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* C_STRCASE_H */
|
||||
56
lib/c-strcasecmp.c
Normal file
56
lib/c-strcasecmp.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/* c-strcasecmp.c -- case insensitive string comparator in C locale
|
||||
Copyright (C) 1998-1999, 2005-2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include "c-strcase.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "c-ctype.h"
|
||||
|
||||
int
|
||||
c_strcasecmp (const char *s1, const char *s2)
|
||||
{
|
||||
register const unsigned char *p1 = (const unsigned char *) s1;
|
||||
register const unsigned char *p2 = (const unsigned char *) s2;
|
||||
unsigned char c1, c2;
|
||||
|
||||
if (p1 == p2)
|
||||
return 0;
|
||||
|
||||
do
|
||||
{
|
||||
c1 = c_tolower (*p1);
|
||||
c2 = c_tolower (*p2);
|
||||
|
||||
if (c1 == '\0')
|
||||
break;
|
||||
|
||||
++p1;
|
||||
++p2;
|
||||
}
|
||||
while (c1 == c2);
|
||||
|
||||
if (UCHAR_MAX <= INT_MAX)
|
||||
return c1 - c2;
|
||||
else
|
||||
/* On machines where 'char' and 'int' are types of the same size, the
|
||||
difference of two 'unsigned char' values - including the sign bit -
|
||||
doesn't fit in an 'int'. */
|
||||
return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
|
||||
}
|
||||
181
lib/c-strcaseeq.h
Normal file
181
lib/c-strcaseeq.h
Normal file
@@ -0,0 +1,181 @@
|
||||
/* Optimized case-insensitive string comparison in C locale.
|
||||
Copyright (C) 2001-2002, 2007, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Bruno Haible <bruno@clisp.org>. */
|
||||
|
||||
#include "c-strcase.h"
|
||||
#include "c-ctype.h"
|
||||
|
||||
/* STRCASEEQ allows to optimize string comparison with a small literal string.
|
||||
STRCASEEQ (s, "UTF-8", 'U','T','F','-','8',0,0,0,0)
|
||||
is semantically equivalent to
|
||||
c_strcasecmp (s, "UTF-8") == 0
|
||||
just faster. */
|
||||
|
||||
/* Help GCC to generate good code for string comparisons with
|
||||
immediate strings. */
|
||||
#if defined (__GNUC__) && defined (__OPTIMIZE__)
|
||||
|
||||
/* Case insensitive comparison of ASCII characters. */
|
||||
# if C_CTYPE_ASCII
|
||||
# define CASEEQ(other,upper) \
|
||||
(c_isupper (upper) ? ((other) & ~0x20) == (upper) : (other) == (upper))
|
||||
# else
|
||||
# define CASEEQ(other,upper) \
|
||||
(c_toupper (other) == (upper))
|
||||
# endif
|
||||
|
||||
static inline int
|
||||
strcaseeq9 (const char *s1, const char *s2)
|
||||
{
|
||||
return c_strcasecmp (s1 + 9, s2 + 9) == 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
strcaseeq8 (const char *s1, const char *s2, char s28)
|
||||
{
|
||||
if (CASEEQ (s1[8], s28))
|
||||
{
|
||||
if (s28 == 0)
|
||||
return 1;
|
||||
else
|
||||
return strcaseeq9 (s1, s2);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
strcaseeq7 (const char *s1, const char *s2, char s27, char s28)
|
||||
{
|
||||
if (CASEEQ (s1[7], s27))
|
||||
{
|
||||
if (s27 == 0)
|
||||
return 1;
|
||||
else
|
||||
return strcaseeq8 (s1, s2, s28);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
strcaseeq6 (const char *s1, const char *s2, char s26, char s27, char s28)
|
||||
{
|
||||
if (CASEEQ (s1[6], s26))
|
||||
{
|
||||
if (s26 == 0)
|
||||
return 1;
|
||||
else
|
||||
return strcaseeq7 (s1, s2, s27, s28);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
strcaseeq5 (const char *s1, const char *s2, char s25, char s26, char s27, char s28)
|
||||
{
|
||||
if (CASEEQ (s1[5], s25))
|
||||
{
|
||||
if (s25 == 0)
|
||||
return 1;
|
||||
else
|
||||
return strcaseeq6 (s1, s2, s26, s27, s28);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
strcaseeq4 (const char *s1, const char *s2, char s24, char s25, char s26, char s27, char s28)
|
||||
{
|
||||
if (CASEEQ (s1[4], s24))
|
||||
{
|
||||
if (s24 == 0)
|
||||
return 1;
|
||||
else
|
||||
return strcaseeq5 (s1, s2, s25, s26, s27, s28);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
strcaseeq3 (const char *s1, const char *s2, char s23, char s24, char s25, char s26, char s27, char s28)
|
||||
{
|
||||
if (CASEEQ (s1[3], s23))
|
||||
{
|
||||
if (s23 == 0)
|
||||
return 1;
|
||||
else
|
||||
return strcaseeq4 (s1, s2, s24, s25, s26, s27, s28);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
strcaseeq2 (const char *s1, const char *s2, char s22, char s23, char s24, char s25, char s26, char s27, char s28)
|
||||
{
|
||||
if (CASEEQ (s1[2], s22))
|
||||
{
|
||||
if (s22 == 0)
|
||||
return 1;
|
||||
else
|
||||
return strcaseeq3 (s1, s2, s23, s24, s25, s26, s27, s28);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
strcaseeq1 (const char *s1, const char *s2, char s21, char s22, char s23, char s24, char s25, char s26, char s27, char s28)
|
||||
{
|
||||
if (CASEEQ (s1[1], s21))
|
||||
{
|
||||
if (s21 == 0)
|
||||
return 1;
|
||||
else
|
||||
return strcaseeq2 (s1, s2, s22, s23, s24, s25, s26, s27, s28);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
strcaseeq0 (const char *s1, const char *s2, char s20, char s21, char s22, char s23, char s24, char s25, char s26, char s27, char s28)
|
||||
{
|
||||
if (CASEEQ (s1[0], s20))
|
||||
{
|
||||
if (s20 == 0)
|
||||
return 1;
|
||||
else
|
||||
return strcaseeq1 (s1, s2, s21, s22, s23, s24, s25, s26, s27, s28);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define STRCASEEQ(s1,s2,s20,s21,s22,s23,s24,s25,s26,s27,s28) \
|
||||
strcaseeq0 (s1, s2, s20, s21, s22, s23, s24, s25, s26, s27, s28)
|
||||
|
||||
#else
|
||||
|
||||
#define STRCASEEQ(s1,s2,s20,s21,s22,s23,s24,s25,s26,s27,s28) \
|
||||
(c_strcasecmp (s1, s2) == 0)
|
||||
|
||||
#endif
|
||||
56
lib/c-strncasecmp.c
Normal file
56
lib/c-strncasecmp.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/* c-strncasecmp.c -- case insensitive string comparator in C locale
|
||||
Copyright (C) 1998-1999, 2005-2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include "c-strcase.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "c-ctype.h"
|
||||
|
||||
int
|
||||
c_strncasecmp (const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
register const unsigned char *p1 = (const unsigned char *) s1;
|
||||
register const unsigned char *p2 = (const unsigned char *) s2;
|
||||
unsigned char c1, c2;
|
||||
|
||||
if (p1 == p2 || n == 0)
|
||||
return 0;
|
||||
|
||||
do
|
||||
{
|
||||
c1 = c_tolower (*p1);
|
||||
c2 = c_tolower (*p2);
|
||||
|
||||
if (--n == 0 || c1 == '\0')
|
||||
break;
|
||||
|
||||
++p1;
|
||||
++p2;
|
||||
}
|
||||
while (c1 == c2);
|
||||
|
||||
if (UCHAR_MAX <= INT_MAX)
|
||||
return c1 - c2;
|
||||
else
|
||||
/* On machines where 'char' and 'int' are types of the same size, the
|
||||
difference of two 'unsigned char' values - including the sign bit -
|
||||
doesn't fit in an 'int'. */
|
||||
return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
|
||||
}
|
||||
135
lib/c-strtod.c
Normal file
135
lib/c-strtod.c
Normal file
@@ -0,0 +1,135 @@
|
||||
/* Convert string to double, using the C locale.
|
||||
|
||||
Copyright (C) 2003-2004, 2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Paul Eggert. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "c-strtod.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if LONG
|
||||
# define C_STRTOD c_strtold
|
||||
# define DOUBLE long double
|
||||
# define STRTOD_L strtold_l
|
||||
# define HAVE_GOOD_STRTOD_L (HAVE_STRTOLD_L && !GNULIB_defined_strtold_function)
|
||||
# define STRTOD strtold
|
||||
#else
|
||||
# define C_STRTOD c_strtod
|
||||
# define DOUBLE double
|
||||
# define STRTOD_L strtod_l
|
||||
# define HAVE_GOOD_STRTOD_L (HAVE_STRTOD_L && !GNULIB_defined_strtod_function)
|
||||
# define STRTOD strtod
|
||||
#endif
|
||||
|
||||
#if defined LC_ALL_MASK \
|
||||
&& ((LONG ? HAVE_GOOD_STRTOLD_L : HAVE_GOOD_STRTOD_L) \
|
||||
|| HAVE_WORKING_USELOCALE)
|
||||
|
||||
/* Cache for the C locale object.
|
||||
Marked volatile so that different threads see the same value
|
||||
(avoids locking). */
|
||||
static volatile locale_t c_locale_cache;
|
||||
|
||||
/* Return the C locale object, or (locale_t) 0 with errno set
|
||||
if it cannot be created. */
|
||||
static locale_t
|
||||
c_locale (void)
|
||||
{
|
||||
if (!c_locale_cache)
|
||||
c_locale_cache = newlocale (LC_ALL_MASK, "C", (locale_t) 0);
|
||||
return c_locale_cache;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
DOUBLE
|
||||
C_STRTOD (char const *nptr, char **endptr)
|
||||
{
|
||||
DOUBLE r;
|
||||
|
||||
#if defined LC_ALL_MASK \
|
||||
&& ((LONG ? HAVE_GOOD_STRTOLD_L : HAVE_GOOD_STRTOD_L) \
|
||||
|| HAVE_WORKING_USELOCALE)
|
||||
|
||||
locale_t locale = c_locale ();
|
||||
if (!locale)
|
||||
{
|
||||
if (endptr)
|
||||
*endptr = (char *) nptr;
|
||||
return 0; /* errno is set here */
|
||||
}
|
||||
|
||||
# if (LONG ? HAVE_GOOD_STRTOLD_L : HAVE_GOOD_STRTOD_L)
|
||||
|
||||
r = STRTOD_L (nptr, endptr, locale);
|
||||
|
||||
# else /* HAVE_WORKING_USELOCALE */
|
||||
|
||||
locale_t old_locale = uselocale (locale);
|
||||
if (old_locale == (locale_t)0)
|
||||
{
|
||||
if (endptr)
|
||||
*endptr = (char *) nptr;
|
||||
return 0; /* errno is set here */
|
||||
}
|
||||
|
||||
r = STRTOD (nptr, endptr);
|
||||
|
||||
int saved_errno = errno;
|
||||
if (uselocale (old_locale) == (locale_t)0)
|
||||
/* We can't switch back to the old locale. The thread is hosed. */
|
||||
abort ();
|
||||
errno = saved_errno;
|
||||
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
char *saved_locale = setlocale (LC_NUMERIC, NULL);
|
||||
|
||||
if (saved_locale)
|
||||
{
|
||||
saved_locale = strdup (saved_locale);
|
||||
if (saved_locale == NULL)
|
||||
{
|
||||
if (endptr)
|
||||
*endptr = (char *) nptr;
|
||||
return 0; /* errno is set here */
|
||||
}
|
||||
setlocale (LC_NUMERIC, "C");
|
||||
}
|
||||
|
||||
r = STRTOD (nptr, endptr);
|
||||
|
||||
if (saved_locale)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
|
||||
setlocale (LC_NUMERIC, saved_locale);
|
||||
free (saved_locale);
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
45
lib/c-strtod.h
Normal file
45
lib/c-strtod.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* Convert string to double, using the C locale. -*- coding: utf-8 -*-
|
||||
|
||||
Copyright (C) 2003-2004, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Parse the initial portion of the string pointed to by NPTR as a floating-
|
||||
point number (in decimal or hexadecimal notation), like in the C locale:
|
||||
accepting only the ASCII digits '0'..'9', and only '.' as decimal point
|
||||
character.
|
||||
If ENDPTR is not NULL, set *ENDPTR to point to the first byte beyond the
|
||||
parsed number or to NPTR if the string does not start with a parsable
|
||||
number.
|
||||
Return value:
|
||||
- If successful, return the value as a double or 'long double',
|
||||
respectively, and don't modify errno.
|
||||
- In case of overflow, return ±HUGE_VAL or ±HUGE_VALL, respectively, and
|
||||
set errno to ERANGE.
|
||||
- In case of underflow, return a value very near to 0 and set errno to
|
||||
ERANGE.
|
||||
- If the string does not start with a number at all, return 0 (and recall
|
||||
that if ENDPTR != NULL, *ENDPTR is set to NPTR), and maybe set errno to
|
||||
EINVAL.
|
||||
- In case of other error, return 0 and set errno, for example to ENOMEM. */
|
||||
extern double c_strtod (char const *nptr, char **endptr);
|
||||
extern long double c_strtold (char const *nptr, char **endptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
2
lib/c-strtold.c
Normal file
2
lib/c-strtold.c
Normal file
@@ -0,0 +1,2 @@
|
||||
#define LONG 1
|
||||
#include "c-strtod.c"
|
||||
73
lib/calloc.c
Normal file
73
lib/calloc.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/* calloc() function that is glibc compatible.
|
||||
This wrapper function is required at least on Tru64 UNIX 5.1 and mingw.
|
||||
Copyright (C) 2004-2007, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Jim Meyering and Bruno Haible */
|
||||
|
||||
#include <config.h>
|
||||
/* Only the AC_FUNC_CALLOC macro defines 'calloc' already in config.h. */
|
||||
#ifdef calloc
|
||||
# define NEED_CALLOC_GNU 1
|
||||
# undef calloc
|
||||
/* Whereas the gnulib module 'calloc-gnu' defines HAVE_CALLOC_GNU. */
|
||||
#elif GNULIB_CALLOC_GNU && !HAVE_CALLOC_GNU
|
||||
# define NEED_CALLOC_GNU 1
|
||||
#endif
|
||||
|
||||
/* Specification. */
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
/* Call the system's calloc below. */
|
||||
#undef calloc
|
||||
|
||||
/* Allocate and zero-fill an NxS-byte block of memory from the heap.
|
||||
If N or S is zero, allocate and zero-fill a 1-byte block. */
|
||||
|
||||
void *
|
||||
rpl_calloc (size_t n, size_t s)
|
||||
{
|
||||
void *result;
|
||||
|
||||
#if NEED_CALLOC_GNU
|
||||
if (n == 0 || s == 0)
|
||||
{
|
||||
n = 1;
|
||||
s = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Defend against buggy calloc implementations that mishandle
|
||||
size_t overflow. */
|
||||
size_t bytes = n * s;
|
||||
if (bytes / s != n)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
result = calloc (n, s);
|
||||
|
||||
#if !HAVE_CALLOC_POSIX
|
||||
if (result == NULL)
|
||||
errno = ENOMEM;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
91
lib/canon-host.c
Normal file
91
lib/canon-host.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/* Host name canonicalization
|
||||
|
||||
Copyright (C) 2005-2020 Free Software Foundation, Inc.
|
||||
|
||||
Written by Derek Price <derek@ximbiot.com>.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "canon-host.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
|
||||
/* Store the last error for the single-threaded version of this function. */
|
||||
static int last_cherror;
|
||||
|
||||
/* Single-threaded of wrapper for canon_host_r. After a NULL return, error
|
||||
messages may be retrieved via ch_strerror(). */
|
||||
char *
|
||||
canon_host (const char *host)
|
||||
{
|
||||
return canon_host_r (host, &last_cherror);
|
||||
}
|
||||
|
||||
/* Return a malloc'd string containing the canonical hostname associated with
|
||||
HOST, or NULL if a canonical name cannot be determined. On NULL return,
|
||||
if CHERROR is not NULL, set *CHERROR to an error code as returned by
|
||||
getaddrinfo(). Use ch_strerror_r() or gai_strerror() to convert a *CHERROR
|
||||
value to a string suitable for error messages.
|
||||
|
||||
WARNINGS
|
||||
HOST must be a string representation of a resolvable name for this host.
|
||||
Strings containing an IP address in dotted decimal notation will be
|
||||
returned as-is, without further resolution.
|
||||
|
||||
The use of the word "canonical" in this context is unfortunate but
|
||||
entrenched. The value returned by this function will be the end result
|
||||
of the resolution of any CNAME chains in the DNS. There may only be one
|
||||
such value for any given hostname, though the actual IP address
|
||||
referenced by this value and the device using that IP address may each
|
||||
actually have any number of such "canonical" hostnames. See the POSIX
|
||||
getaddrinfo spec
|
||||
<https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html>,
|
||||
RFC 1034 <https://www.ietf.org/rfc/rfc1034.txt>, & RFC 2181
|
||||
<https://www.ietf.org/rfc/rfc2181.txt> for more on what this confusing
|
||||
term really refers to. */
|
||||
char *
|
||||
canon_host_r (char const *host, int *cherror)
|
||||
{
|
||||
char *retval = NULL;
|
||||
static struct addrinfo hints;
|
||||
struct addrinfo *res = NULL;
|
||||
int status;
|
||||
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
status = getaddrinfo (host, NULL, &hints, &res);
|
||||
if (!status)
|
||||
{
|
||||
/* https://lists.gnu.org/r/bug-coreutils/2006-09/msg00300.html
|
||||
says Darwin 7.9.0 getaddrinfo returns 0 but sets
|
||||
res->ai_canonname to NULL. */
|
||||
retval = strdup (res->ai_canonname ? res->ai_canonname : host);
|
||||
if (!retval && cherror)
|
||||
*cherror = EAI_MEMORY;
|
||||
freeaddrinfo (res);
|
||||
}
|
||||
else if (cherror)
|
||||
*cherror = status;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Return a string describing the last error encountered by canon_host. */
|
||||
const char *
|
||||
ch_strerror (void)
|
||||
{
|
||||
return gai_strerror (last_cherror);
|
||||
}
|
||||
29
lib/canon-host.h
Normal file
29
lib/canon-host.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* Host name canonicalization
|
||||
|
||||
Copyright (C) 2005, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
Written by Derek Price <derek@ximbiot.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef CANON_HOST_H
|
||||
# define CANON_HOST_H 1
|
||||
|
||||
char *canon_host (char const *host) _GL_ATTRIBUTE_MALLOC;
|
||||
char *canon_host_r (char const *host, int *cherror) _GL_ATTRIBUTE_MALLOC;
|
||||
|
||||
const char *ch_strerror (void);
|
||||
# define ch_strerror_r(cherror) gai_strerror (cherror);
|
||||
|
||||
#endif /* !CANON_HOST_H */
|
||||
355
lib/canonicalize.c
Normal file
355
lib/canonicalize.c
Normal file
@@ -0,0 +1,355 @@
|
||||
/* Return the canonical absolute name of a given file.
|
||||
Copyright (C) 1996-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "canonicalize.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "areadlink.h"
|
||||
#include "file-set.h"
|
||||
#include "hash-triple.h"
|
||||
#include "pathmax.h"
|
||||
#include "xalloc.h"
|
||||
#include "xgetcwd.h"
|
||||
#include "dosname.h"
|
||||
|
||||
#define MULTIPLE_BITS_SET(i) (((i) & ((i) - 1)) != 0)
|
||||
|
||||
/* In this file, we cannot handle file names longer than PATH_MAX.
|
||||
On systems with no file name length limit, use a fallback. */
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX 8192
|
||||
#endif
|
||||
|
||||
#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
|
||||
# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
|
||||
#endif
|
||||
|
||||
#if ISSLASH ('\\')
|
||||
# define SLASHES "/\\"
|
||||
#else
|
||||
# define SLASHES "/"
|
||||
#endif
|
||||
|
||||
#if !((HAVE_CANONICALIZE_FILE_NAME && FUNC_REALPATH_WORKS) \
|
||||
|| GNULIB_CANONICALIZE_LGPL)
|
||||
/* Return the canonical absolute name of file NAME. A canonical name
|
||||
does not contain any ".", ".." components nor any repeated file name
|
||||
separators ('/') or symlinks. All components must exist.
|
||||
The result is malloc'd. */
|
||||
|
||||
char *
|
||||
canonicalize_file_name (const char *name)
|
||||
{
|
||||
return canonicalize_filename_mode (name, CAN_EXISTING);
|
||||
}
|
||||
#endif /* !HAVE_CANONICALIZE_FILE_NAME */
|
||||
|
||||
/* Return true if we've already seen the triple, <FILENAME, dev, ino>.
|
||||
If *HT is not initialized, initialize it. */
|
||||
static bool
|
||||
seen_triple (Hash_table **ht, char const *filename, struct stat const *st)
|
||||
{
|
||||
if (*ht == NULL)
|
||||
{
|
||||
size_t initial_capacity = 7;
|
||||
*ht = hash_initialize (initial_capacity,
|
||||
NULL,
|
||||
triple_hash,
|
||||
triple_compare_ino_str,
|
||||
triple_free);
|
||||
if (*ht == NULL)
|
||||
xalloc_die ();
|
||||
}
|
||||
|
||||
if (seen_file (*ht, filename, st))
|
||||
return true;
|
||||
|
||||
record_file (*ht, filename, st);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return the canonical absolute name of file NAME, while treating
|
||||
missing elements according to CAN_MODE. A canonical name
|
||||
does not contain any ".", ".." components nor any repeated file name
|
||||
separators ('/') or, depending on other CAN_MODE flags, symlinks.
|
||||
Whether components must exist or not depends on canonicalize mode.
|
||||
The result is malloc'd. */
|
||||
|
||||
char *
|
||||
canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
|
||||
{
|
||||
char *rname, *dest, *extra_buf = NULL;
|
||||
char const *start;
|
||||
char const *end;
|
||||
char const *rname_limit;
|
||||
size_t extra_len = 0;
|
||||
Hash_table *ht = NULL;
|
||||
int saved_errno;
|
||||
int can_flags = can_mode & ~CAN_MODE_MASK;
|
||||
bool logical = can_flags & CAN_NOLINKS;
|
||||
size_t prefix_len;
|
||||
|
||||
can_mode &= CAN_MODE_MASK;
|
||||
|
||||
if (MULTIPLE_BITS_SET (can_mode))
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (name == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (name[0] == '\0')
|
||||
{
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This is always zero for Posix hosts, but can be 2 for MS-Windows
|
||||
and MS-DOS X:/foo/bar file names. */
|
||||
prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
|
||||
|
||||
if (!IS_ABSOLUTE_FILE_NAME (name))
|
||||
{
|
||||
rname = xgetcwd ();
|
||||
if (!rname)
|
||||
return NULL;
|
||||
dest = strchr (rname, '\0');
|
||||
if (dest - rname < PATH_MAX)
|
||||
{
|
||||
char *p = xrealloc (rname, PATH_MAX);
|
||||
dest = p + (dest - rname);
|
||||
rname = p;
|
||||
rname_limit = rname + PATH_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
rname_limit = dest;
|
||||
}
|
||||
start = name;
|
||||
prefix_len = FILE_SYSTEM_PREFIX_LEN (rname);
|
||||
}
|
||||
else
|
||||
{
|
||||
rname = xmalloc (PATH_MAX);
|
||||
rname_limit = rname + PATH_MAX;
|
||||
dest = rname;
|
||||
if (prefix_len)
|
||||
{
|
||||
memcpy (rname, name, prefix_len);
|
||||
dest += prefix_len;
|
||||
}
|
||||
*dest++ = '/';
|
||||
if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
|
||||
{
|
||||
if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len)
|
||||
*dest++ = '/';
|
||||
*dest = '\0';
|
||||
}
|
||||
start = name + prefix_len;
|
||||
}
|
||||
|
||||
for ( ; *start; start = end)
|
||||
{
|
||||
/* Skip sequence of multiple file name separators. */
|
||||
while (ISSLASH (*start))
|
||||
++start;
|
||||
|
||||
/* Find end of component. */
|
||||
for (end = start; *end && !ISSLASH (*end); ++end)
|
||||
/* Nothing. */;
|
||||
|
||||
if (end - start == 0)
|
||||
break;
|
||||
else if (end - start == 1 && start[0] == '.')
|
||||
/* nothing */;
|
||||
else if (end - start == 2 && start[0] == '.' && start[1] == '.')
|
||||
{
|
||||
/* Back up to previous component, ignore if at root already. */
|
||||
if (dest > rname + prefix_len + 1)
|
||||
for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
|
||||
continue;
|
||||
if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
|
||||
&& !prefix_len && ISSLASH (*dest) && !ISSLASH (dest[1]))
|
||||
dest++;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (!ISSLASH (dest[-1]))
|
||||
*dest++ = '/';
|
||||
|
||||
if (dest + (end - start) >= rname_limit)
|
||||
{
|
||||
ptrdiff_t dest_offset = dest - rname;
|
||||
size_t new_size = rname_limit - rname;
|
||||
|
||||
if (end - start + 1 > PATH_MAX)
|
||||
new_size += end - start + 1;
|
||||
else
|
||||
new_size += PATH_MAX;
|
||||
rname = xrealloc (rname, new_size);
|
||||
rname_limit = rname + new_size;
|
||||
|
||||
dest = rname + dest_offset;
|
||||
}
|
||||
|
||||
dest = memcpy (dest, start, end - start);
|
||||
dest += end - start;
|
||||
*dest = '\0';
|
||||
|
||||
if (logical && (can_mode == CAN_MISSING))
|
||||
{
|
||||
/* Avoid the stat in this case as it's inconsequential.
|
||||
i.e. we're neither resolving symlinks or testing
|
||||
component existence. */
|
||||
st.st_mode = 0;
|
||||
}
|
||||
else if ((logical ? stat (rname, &st) : lstat (rname, &st)) != 0)
|
||||
{
|
||||
/* FIXME: If errno == EOVERFLOW here, the entry exists. */
|
||||
saved_errno = errno;
|
||||
if (can_mode == CAN_EXISTING)
|
||||
goto error;
|
||||
if (can_mode == CAN_ALL_BUT_LAST)
|
||||
{
|
||||
if (end[strspn (end, SLASHES)] || saved_errno != ENOENT)
|
||||
goto error;
|
||||
continue;
|
||||
}
|
||||
st.st_mode = 0;
|
||||
}
|
||||
|
||||
if (S_ISLNK (st.st_mode))
|
||||
{
|
||||
char *buf;
|
||||
size_t n, len;
|
||||
|
||||
/* Detect loops. We cannot use the cycle-check module here,
|
||||
since it's actually possible to encounter the same symlink
|
||||
more than once in a given traversal. However, encountering
|
||||
the same symlink,NAME pair twice does indicate a loop. */
|
||||
if (seen_triple (&ht, name, &st))
|
||||
{
|
||||
if (can_mode == CAN_MISSING)
|
||||
continue;
|
||||
saved_errno = ELOOP;
|
||||
goto error;
|
||||
}
|
||||
|
||||
buf = areadlink_with_size (rname, st.st_size);
|
||||
if (!buf)
|
||||
{
|
||||
if (can_mode == CAN_MISSING && errno != ENOMEM)
|
||||
continue;
|
||||
saved_errno = errno;
|
||||
goto error;
|
||||
}
|
||||
|
||||
n = strlen (buf);
|
||||
len = strlen (end);
|
||||
|
||||
if (!extra_len)
|
||||
{
|
||||
extra_len =
|
||||
((n + len + 1) > PATH_MAX) ? (n + len + 1) : PATH_MAX;
|
||||
extra_buf = xmalloc (extra_len);
|
||||
}
|
||||
else if ((n + len + 1) > extra_len)
|
||||
{
|
||||
extra_len = n + len + 1;
|
||||
extra_buf = xrealloc (extra_buf, extra_len);
|
||||
}
|
||||
|
||||
/* Careful here, end may be a pointer into extra_buf... */
|
||||
memmove (&extra_buf[n], end, len + 1);
|
||||
name = end = memcpy (extra_buf, buf, n);
|
||||
|
||||
if (IS_ABSOLUTE_FILE_NAME (buf))
|
||||
{
|
||||
size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
|
||||
|
||||
if (pfxlen)
|
||||
memcpy (rname, buf, pfxlen);
|
||||
dest = rname + pfxlen;
|
||||
*dest++ = '/'; /* It's an absolute symlink */
|
||||
if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
|
||||
{
|
||||
if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
|
||||
*dest++ = '/';
|
||||
*dest = '\0';
|
||||
}
|
||||
/* Install the new prefix to be in effect hereafter. */
|
||||
prefix_len = pfxlen;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Back up to previous component, ignore if at root
|
||||
already: */
|
||||
if (dest > rname + prefix_len + 1)
|
||||
for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
|
||||
continue;
|
||||
if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
|
||||
&& ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
|
||||
dest++;
|
||||
}
|
||||
|
||||
free (buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!S_ISDIR (st.st_mode) && *end && (can_mode != CAN_MISSING))
|
||||
{
|
||||
saved_errno = ENOTDIR;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1]))
|
||||
--dest;
|
||||
if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && !prefix_len
|
||||
&& ISSLASH (*dest) && !ISSLASH (dest[1]))
|
||||
dest++;
|
||||
*dest = '\0';
|
||||
if (rname_limit != dest + 1)
|
||||
rname = xrealloc (rname, dest - rname + 1);
|
||||
|
||||
free (extra_buf);
|
||||
if (ht)
|
||||
hash_free (ht);
|
||||
return rname;
|
||||
|
||||
error:
|
||||
free (extra_buf);
|
||||
free (rname);
|
||||
if (ht)
|
||||
hash_free (ht);
|
||||
errno = saved_errno;
|
||||
return NULL;
|
||||
}
|
||||
56
lib/canonicalize.h
Normal file
56
lib/canonicalize.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* Return the canonical absolute name of a given file.
|
||||
Copyright (C) 1996-2007, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef CANONICALIZE_H_
|
||||
# define CANONICALIZE_H_
|
||||
|
||||
#include <stdlib.h> /* for canonicalize_file_name */
|
||||
|
||||
#define CAN_MODE_MASK (CAN_EXISTING | CAN_ALL_BUT_LAST | CAN_MISSING)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum canonicalize_mode_t
|
||||
{
|
||||
/* All components must exist. */
|
||||
CAN_EXISTING = 0,
|
||||
|
||||
/* All components excluding last one must exist. */
|
||||
CAN_ALL_BUT_LAST = 1,
|
||||
|
||||
/* No requirements on components existence. */
|
||||
CAN_MISSING = 2,
|
||||
|
||||
/* Don't expand symlinks. */
|
||||
CAN_NOLINKS = 4
|
||||
};
|
||||
typedef enum canonicalize_mode_t canonicalize_mode_t;
|
||||
|
||||
/* Return the canonical absolute name of file NAME, while treating
|
||||
missing elements according to CAN_MODE. A canonical name
|
||||
does not contain any `.', `..' components nor any repeated file name
|
||||
separators ('/') or, depending on other CAN_MODE flags, symlinks.
|
||||
Whether components must exist or not depends on canonicalize mode.
|
||||
The result is malloc'd. */
|
||||
char *canonicalize_filename_mode (const char *, canonicalize_mode_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !CANONICALIZE_H_ */
|
||||
160
lib/careadlinkat.c
Normal file
160
lib/careadlinkat.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/* Read symbolic links into a buffer without size limitation, relative to fd.
|
||||
|
||||
Copyright (C) 2001, 2003-2004, 2007, 2009-2020 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "careadlinkat.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Define this independently so that stdint.h is not a prerequisite. */
|
||||
#ifndef SIZE_MAX
|
||||
# define SIZE_MAX ((size_t) -1)
|
||||
#endif
|
||||
|
||||
#ifndef SSIZE_MAX
|
||||
# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
|
||||
#endif
|
||||
|
||||
#include "allocator.h"
|
||||
|
||||
/* Assuming the current directory is FD, get the symbolic link value
|
||||
of FILENAME as a null-terminated string and put it into a buffer.
|
||||
If FD is AT_FDCWD, FILENAME is interpreted relative to the current
|
||||
working directory, as in openat.
|
||||
|
||||
If the link is small enough to fit into BUFFER put it there.
|
||||
BUFFER's size is BUFFER_SIZE, and BUFFER can be null
|
||||
if BUFFER_SIZE is zero.
|
||||
|
||||
If the link is not small, put it into a dynamically allocated
|
||||
buffer managed by ALLOC. It is the caller's responsibility to free
|
||||
the returned value if it is nonnull and is not BUFFER. A null
|
||||
ALLOC stands for the standard allocator.
|
||||
|
||||
The PREADLINKAT function specifies how to read links. It operates
|
||||
like POSIX readlinkat()
|
||||
<https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html>
|
||||
but can assume that its first argument is the same as FD.
|
||||
|
||||
If successful, return the buffer address; otherwise return NULL and
|
||||
set errno. */
|
||||
|
||||
char *
|
||||
careadlinkat (int fd, char const *filename,
|
||||
char *buffer, size_t buffer_size,
|
||||
struct allocator const *alloc,
|
||||
ssize_t (*preadlinkat) (int, char const *, char *, size_t))
|
||||
{
|
||||
char *buf;
|
||||
size_t buf_size;
|
||||
size_t buf_size_max =
|
||||
SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
|
||||
char stack_buf[1024];
|
||||
|
||||
if (! alloc)
|
||||
alloc = &stdlib_allocator;
|
||||
|
||||
if (! buffer_size)
|
||||
{
|
||||
/* Allocate the initial buffer on the stack. This way, in the
|
||||
common case of a symlink of small size, we get away with a
|
||||
single small malloc() instead of a big malloc() followed by a
|
||||
shrinking realloc(). */
|
||||
buffer = stack_buf;
|
||||
buffer_size = sizeof stack_buf;
|
||||
}
|
||||
|
||||
buf = buffer;
|
||||
buf_size = buffer_size;
|
||||
|
||||
do
|
||||
{
|
||||
/* Attempt to read the link into the current buffer. */
|
||||
ssize_t link_length = preadlinkat (fd, filename, buf, buf_size);
|
||||
size_t link_size;
|
||||
if (link_length < 0)
|
||||
{
|
||||
/* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink returns -1
|
||||
with errno == ERANGE if the buffer is too small. */
|
||||
int readlinkat_errno = errno;
|
||||
if (readlinkat_errno != ERANGE)
|
||||
{
|
||||
if (buf != buffer)
|
||||
{
|
||||
alloc->free (buf);
|
||||
errno = readlinkat_errno;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
link_size = link_length;
|
||||
|
||||
if (link_size < buf_size)
|
||||
{
|
||||
buf[link_size++] = '\0';
|
||||
|
||||
if (buf == stack_buf)
|
||||
{
|
||||
char *b = (char *) alloc->allocate (link_size);
|
||||
buf_size = link_size;
|
||||
if (! b)
|
||||
break;
|
||||
memcpy (b, buf, link_size);
|
||||
buf = b;
|
||||
}
|
||||
else if (link_size < buf_size && buf != buffer && alloc->reallocate)
|
||||
{
|
||||
/* Shrink BUF before returning it. */
|
||||
char *b = (char *) alloc->reallocate (buf, link_size);
|
||||
if (b)
|
||||
buf = b;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (buf != buffer)
|
||||
alloc->free (buf);
|
||||
|
||||
if (buf_size <= buf_size_max / 2)
|
||||
buf_size *= 2;
|
||||
else if (buf_size < buf_size_max)
|
||||
buf_size = buf_size_max;
|
||||
else if (buf_size_max < SIZE_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
break;
|
||||
buf = (char *) alloc->allocate (buf_size);
|
||||
}
|
||||
while (buf);
|
||||
|
||||
if (alloc->die)
|
||||
alloc->die (buf_size);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
67
lib/careadlinkat.h
Normal file
67
lib/careadlinkat.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* Read symbolic links into a buffer without size limitation, relative to fd.
|
||||
|
||||
Copyright (C) 2011-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */
|
||||
|
||||
#ifndef _GL_CAREADLINKAT_H
|
||||
#define _GL_CAREADLINKAT_H
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct allocator;
|
||||
|
||||
/* Assuming the current directory is FD, get the symbolic link value
|
||||
of FILENAME as a null-terminated string and put it into a buffer.
|
||||
If FD is AT_FDCWD, FILENAME is interpreted relative to the current
|
||||
working directory, as in openat.
|
||||
|
||||
If the link is small enough to fit into BUFFER put it there.
|
||||
BUFFER's size is BUFFER_SIZE, and BUFFER can be null
|
||||
if BUFFER_SIZE is zero.
|
||||
|
||||
If the link is not small, put it into a dynamically allocated
|
||||
buffer managed by ALLOC. It is the caller's responsibility to free
|
||||
the returned value if it is nonnull and is not BUFFER.
|
||||
|
||||
The PREADLINKAT function specifies how to read links. It operates
|
||||
like POSIX readlinkat()
|
||||
<https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html>
|
||||
but can assume that its first argument is the same as FD.
|
||||
|
||||
If successful, return the buffer address; otherwise return NULL and
|
||||
set errno. */
|
||||
|
||||
char *careadlinkat (int fd, char const *filename,
|
||||
char *restrict buffer, size_t buffer_size,
|
||||
struct allocator const *alloc,
|
||||
ssize_t (*preadlinkat) (int, char const *,
|
||||
char *, size_t));
|
||||
|
||||
/* Suitable value for careadlinkat's FD argument. */
|
||||
#if HAVE_READLINKAT
|
||||
/* AT_FDCWD is declared in <fcntl.h>. */
|
||||
#else
|
||||
/* Define AT_FDCWD independently, so that the careadlinkat module does
|
||||
not depend on the fcntl-h module. We might as well use the same value
|
||||
as fcntl-h. */
|
||||
# ifndef AT_FDCWD
|
||||
# define AT_FDCWD (-3041965)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* _GL_CAREADLINKAT_H */
|
||||
514
lib/cdefs.h
Normal file
514
lib/cdefs.h
Normal file
@@ -0,0 +1,514 @@
|
||||
/* Copyright (C) 1992-2020 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _SYS_CDEFS_H
|
||||
#define _SYS_CDEFS_H 1
|
||||
|
||||
/* We are almost always included from features.h. */
|
||||
#ifndef _FEATURES_H
|
||||
# include <features.h>
|
||||
#endif
|
||||
|
||||
/* The GNU libc does not support any K&R compilers or the traditional mode
|
||||
of ISO C compilers anymore. Check for some of the combinations not
|
||||
anymore supported. */
|
||||
#if defined __GNUC__ && !defined __STDC__
|
||||
# error "You need a ISO C conforming compiler to use the glibc headers"
|
||||
#endif
|
||||
|
||||
/* Some user header file might have defined this before. */
|
||||
#undef __P
|
||||
#undef __PMT
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
/* All functions, except those with callbacks or those that
|
||||
synchronize memory, are leaf functions. */
|
||||
# if __GNUC_PREREQ (4, 6) && !defined _LIBC
|
||||
# define __LEAF , __leaf__
|
||||
# define __LEAF_ATTR __attribute__ ((__leaf__))
|
||||
# else
|
||||
# define __LEAF
|
||||
# define __LEAF_ATTR
|
||||
# endif
|
||||
|
||||
/* GCC can always grok prototypes. For C++ programs we add throw()
|
||||
to help it optimize the function calls. But this works only with
|
||||
gcc 2.8.x and egcs. For gcc 3.2 and up we even mark C functions
|
||||
as non-throwing using a function attribute since programs can use
|
||||
the -fexceptions options for C code as well. */
|
||||
# if !defined __cplusplus && __GNUC_PREREQ (3, 3)
|
||||
# define __THROW __attribute__ ((__nothrow__ __LEAF))
|
||||
# define __THROWNL __attribute__ ((__nothrow__))
|
||||
# define __NTH(fct) __attribute__ ((__nothrow__ __LEAF)) fct
|
||||
# define __NTHNL(fct) __attribute__ ((__nothrow__)) fct
|
||||
# else
|
||||
# if defined __cplusplus && __GNUC_PREREQ (2,8)
|
||||
# define __THROW throw ()
|
||||
# define __THROWNL throw ()
|
||||
# define __NTH(fct) __LEAF_ATTR fct throw ()
|
||||
# define __NTHNL(fct) fct throw ()
|
||||
# else
|
||||
# define __THROW
|
||||
# define __THROWNL
|
||||
# define __NTH(fct) fct
|
||||
# define __NTHNL(fct) fct
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#else /* Not GCC. */
|
||||
|
||||
# if (defined __cplusplus \
|
||||
|| (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L))
|
||||
# define __inline inline
|
||||
# else
|
||||
# define __inline /* No inline functions. */
|
||||
# endif
|
||||
|
||||
# define __THROW
|
||||
# define __THROWNL
|
||||
# define __NTH(fct) fct
|
||||
|
||||
#endif /* GCC. */
|
||||
|
||||
/* Compilers that are not clang may object to
|
||||
#if defined __clang__ && __has_extension(...)
|
||||
even though they do not need to evaluate the right-hand side of the &&. */
|
||||
#if defined __clang__ && defined __has_extension
|
||||
# define __glibc_clang_has_extension(ext) __has_extension (ext)
|
||||
#else
|
||||
# define __glibc_clang_has_extension(ext) 0
|
||||
#endif
|
||||
|
||||
/* These two macros are not used in glibc anymore. They are kept here
|
||||
only because some other projects expect the macros to be defined. */
|
||||
#define __P(args) args
|
||||
#define __PMT(args) args
|
||||
|
||||
/* For these things, GCC behaves the ANSI way normally,
|
||||
and the non-ANSI way under -traditional. */
|
||||
|
||||
#define __CONCAT(x,y) x ## y
|
||||
#define __STRING(x) #x
|
||||
|
||||
/* This is not a typedef so `const __ptr_t' does the right thing. */
|
||||
#define __ptr_t void *
|
||||
|
||||
|
||||
/* C++ needs to know that types and declarations are C, not C++. */
|
||||
#ifdef __cplusplus
|
||||
# define __BEGIN_DECLS extern "C" {
|
||||
# define __END_DECLS }
|
||||
#else
|
||||
# define __BEGIN_DECLS
|
||||
# define __END_DECLS
|
||||
#endif
|
||||
|
||||
|
||||
/* Fortify support. */
|
||||
#define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1)
|
||||
#define __bos0(ptr) __builtin_object_size (ptr, 0)
|
||||
|
||||
#if __GNUC_PREREQ (4,3)
|
||||
# define __warndecl(name, msg) \
|
||||
extern void name (void) __attribute__((__warning__ (msg)))
|
||||
# define __warnattr(msg) __attribute__((__warning__ (msg)))
|
||||
# define __errordecl(name, msg) \
|
||||
extern void name (void) __attribute__((__error__ (msg)))
|
||||
#else
|
||||
# define __warndecl(name, msg) extern void name (void)
|
||||
# define __warnattr(msg)
|
||||
# define __errordecl(name, msg) extern void name (void)
|
||||
#endif
|
||||
|
||||
/* Support for flexible arrays.
|
||||
Headers that should use flexible arrays only if they're "real"
|
||||
(e.g. only if they won't affect sizeof()) should test
|
||||
#if __glibc_c99_flexarr_available. */
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L && !defined __HP_cc
|
||||
# define __flexarr []
|
||||
# define __glibc_c99_flexarr_available 1
|
||||
#elif __GNUC_PREREQ (2,97)
|
||||
/* GCC 2.97 supports C99 flexible array members as an extension,
|
||||
even when in C89 mode or compiling C++ (any version). */
|
||||
# define __flexarr []
|
||||
# define __glibc_c99_flexarr_available 1
|
||||
#elif defined __GNUC__
|
||||
/* Pre-2.97 GCC did not support C99 flexible arrays but did have
|
||||
an equivalent extension with slightly different notation. */
|
||||
# define __flexarr [0]
|
||||
# define __glibc_c99_flexarr_available 1
|
||||
#else
|
||||
/* Some other non-C99 compiler. Approximate with [1]. */
|
||||
# define __flexarr [1]
|
||||
# define __glibc_c99_flexarr_available 0
|
||||
#endif
|
||||
|
||||
|
||||
/* __asm__ ("xyz") is used throughout the headers to rename functions
|
||||
at the assembly language level. This is wrapped by the __REDIRECT
|
||||
macro, in order to support compilers that can do this some other
|
||||
way. When compilers don't support asm-names at all, we have to do
|
||||
preprocessor tricks instead (which don't have exactly the right
|
||||
semantics, but it's the best we can do).
|
||||
|
||||
Example:
|
||||
int __REDIRECT(setpgrp, (__pid_t pid, __pid_t pgrp), setpgid); */
|
||||
|
||||
#if defined __GNUC__ && __GNUC__ >= 2
|
||||
|
||||
# define __REDIRECT(name, proto, alias) name proto __asm__ (__ASMNAME (#alias))
|
||||
# ifdef __cplusplus
|
||||
# define __REDIRECT_NTH(name, proto, alias) \
|
||||
name proto __THROW __asm__ (__ASMNAME (#alias))
|
||||
# define __REDIRECT_NTHNL(name, proto, alias) \
|
||||
name proto __THROWNL __asm__ (__ASMNAME (#alias))
|
||||
# else
|
||||
# define __REDIRECT_NTH(name, proto, alias) \
|
||||
name proto __asm__ (__ASMNAME (#alias)) __THROW
|
||||
# define __REDIRECT_NTHNL(name, proto, alias) \
|
||||
name proto __asm__ (__ASMNAME (#alias)) __THROWNL
|
||||
# endif
|
||||
# define __ASMNAME(cname) __ASMNAME2 (__USER_LABEL_PREFIX__, cname)
|
||||
# define __ASMNAME2(prefix, cname) __STRING (prefix) cname
|
||||
|
||||
/*
|
||||
#elif __SOME_OTHER_COMPILER__
|
||||
|
||||
# define __REDIRECT(name, proto, alias) name proto; \
|
||||
_Pragma("let " #name " = " #alias)
|
||||
*/
|
||||
#endif
|
||||
|
||||
/* GCC has various useful declarations that can be made with the
|
||||
`__attribute__' syntax. All of the ways we use this do fine if
|
||||
they are omitted for compilers that don't understand it. */
|
||||
#if !defined __GNUC__ || __GNUC__ < 2
|
||||
# define __attribute__(xyz) /* Ignore */
|
||||
#endif
|
||||
|
||||
/* At some point during the gcc 2.96 development the `malloc' attribute
|
||||
for functions was introduced. We don't want to use it unconditionally
|
||||
(although this would be possible) since it generates warnings. */
|
||||
#if __GNUC_PREREQ (2,96)
|
||||
# define __attribute_malloc__ __attribute__ ((__malloc__))
|
||||
#else
|
||||
# define __attribute_malloc__ /* Ignore */
|
||||
#endif
|
||||
|
||||
/* Tell the compiler which arguments to an allocation function
|
||||
indicate the size of the allocation. */
|
||||
#if __GNUC_PREREQ (4, 3)
|
||||
# define __attribute_alloc_size__(params) \
|
||||
__attribute__ ((__alloc_size__ params))
|
||||
#else
|
||||
# define __attribute_alloc_size__(params) /* Ignore. */
|
||||
#endif
|
||||
|
||||
/* At some point during the gcc 2.96 development the `pure' attribute
|
||||
for functions was introduced. We don't want to use it unconditionally
|
||||
(although this would be possible) since it generates warnings. */
|
||||
#if __GNUC_PREREQ (2,96)
|
||||
# define __attribute_pure__ __attribute__ ((__pure__))
|
||||
#else
|
||||
# define __attribute_pure__ /* Ignore */
|
||||
#endif
|
||||
|
||||
/* This declaration tells the compiler that the value is constant. */
|
||||
#if __GNUC_PREREQ (2,5)
|
||||
# define __attribute_const__ __attribute__ ((__const__))
|
||||
#else
|
||||
# define __attribute_const__ /* Ignore */
|
||||
#endif
|
||||
|
||||
/* At some point during the gcc 3.1 development the `used' attribute
|
||||
for functions was introduced. We don't want to use it unconditionally
|
||||
(although this would be possible) since it generates warnings. */
|
||||
#if __GNUC_PREREQ (3,1)
|
||||
# define __attribute_used__ __attribute__ ((__used__))
|
||||
# define __attribute_noinline__ __attribute__ ((__noinline__))
|
||||
#else
|
||||
# define __attribute_used__ __attribute__ ((__unused__))
|
||||
# define __attribute_noinline__ /* Ignore */
|
||||
#endif
|
||||
|
||||
/* Since version 3.2, gcc allows marking deprecated functions. */
|
||||
#if __GNUC_PREREQ (3,2)
|
||||
# define __attribute_deprecated__ __attribute__ ((__deprecated__))
|
||||
#else
|
||||
# define __attribute_deprecated__ /* Ignore */
|
||||
#endif
|
||||
|
||||
/* Since version 4.5, gcc also allows one to specify the message printed
|
||||
when a deprecated function is used. clang claims to be gcc 4.2, but
|
||||
may also support this feature. */
|
||||
#if __GNUC_PREREQ (4,5) || \
|
||||
__glibc_clang_has_extension (__attribute_deprecated_with_message__)
|
||||
# define __attribute_deprecated_msg__(msg) \
|
||||
__attribute__ ((__deprecated__ (msg)))
|
||||
#else
|
||||
# define __attribute_deprecated_msg__(msg) __attribute_deprecated__
|
||||
#endif
|
||||
|
||||
/* At some point during the gcc 2.8 development the `format_arg' attribute
|
||||
for functions was introduced. We don't want to use it unconditionally
|
||||
(although this would be possible) since it generates warnings.
|
||||
If several `format_arg' attributes are given for the same function, in
|
||||
gcc-3.0 and older, all but the last one are ignored. In newer gccs,
|
||||
all designated arguments are considered. */
|
||||
#if __GNUC_PREREQ (2,8)
|
||||
# define __attribute_format_arg__(x) __attribute__ ((__format_arg__ (x)))
|
||||
#else
|
||||
# define __attribute_format_arg__(x) /* Ignore */
|
||||
#endif
|
||||
|
||||
/* At some point during the gcc 2.97 development the `strfmon' format
|
||||
attribute for functions was introduced. We don't want to use it
|
||||
unconditionally (although this would be possible) since it
|
||||
generates warnings. */
|
||||
#if __GNUC_PREREQ (2,97)
|
||||
# define __attribute_format_strfmon__(a,b) \
|
||||
__attribute__ ((__format__ (__strfmon__, a, b)))
|
||||
#else
|
||||
# define __attribute_format_strfmon__(a,b) /* Ignore */
|
||||
#endif
|
||||
|
||||
/* The nonnull function attribute marks pointer parameters that
|
||||
must not be NULL. Do not define __nonnull if it is already defined,
|
||||
for portability when this file is used in Gnulib. */
|
||||
#ifndef __nonnull
|
||||
# if __GNUC_PREREQ (3,3)
|
||||
# define __nonnull(params) __attribute__ ((__nonnull__ params))
|
||||
# else
|
||||
# define __nonnull(params)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* If fortification mode, we warn about unused results of certain
|
||||
function calls which can lead to problems. */
|
||||
#if __GNUC_PREREQ (3,4)
|
||||
# define __attribute_warn_unused_result__ \
|
||||
__attribute__ ((__warn_unused_result__))
|
||||
# if defined __USE_FORTIFY_LEVEL && __USE_FORTIFY_LEVEL > 0
|
||||
# define __wur __attribute_warn_unused_result__
|
||||
# endif
|
||||
#else
|
||||
# define __attribute_warn_unused_result__ /* empty */
|
||||
#endif
|
||||
#ifndef __wur
|
||||
# define __wur /* Ignore */
|
||||
#endif
|
||||
|
||||
/* Forces a function to be always inlined. */
|
||||
#if __GNUC_PREREQ (3,2)
|
||||
/* The Linux kernel defines __always_inline in stddef.h (283d7573), and
|
||||
it conflicts with this definition. Therefore undefine it first to
|
||||
allow either header to be included first. */
|
||||
# undef __always_inline
|
||||
# define __always_inline __inline __attribute__ ((__always_inline__))
|
||||
#else
|
||||
# undef __always_inline
|
||||
# define __always_inline __inline
|
||||
#endif
|
||||
|
||||
/* Associate error messages with the source location of the call site rather
|
||||
than with the source location inside the function. */
|
||||
#if __GNUC_PREREQ (4,3)
|
||||
# define __attribute_artificial__ __attribute__ ((__artificial__))
|
||||
#else
|
||||
# define __attribute_artificial__ /* Ignore */
|
||||
#endif
|
||||
|
||||
/* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99
|
||||
inline semantics, unless -fgnu89-inline is used. Using __GNUC_STDC_INLINE__
|
||||
or __GNUC_GNU_INLINE is not a good enough check for gcc because gcc versions
|
||||
older than 4.3 may define these macros and still not guarantee GNU inlining
|
||||
semantics.
|
||||
|
||||
clang++ identifies itself as gcc-4.2, but has support for GNU inlining
|
||||
semantics, that can be checked for by using the __GNUC_STDC_INLINE_ and
|
||||
__GNUC_GNU_INLINE__ macro definitions. */
|
||||
#if (!defined __cplusplus || __GNUC_PREREQ (4,3) \
|
||||
|| (defined __clang__ && (defined __GNUC_STDC_INLINE__ \
|
||||
|| defined __GNUC_GNU_INLINE__)))
|
||||
# if defined __GNUC_STDC_INLINE__ || defined __cplusplus
|
||||
# define __extern_inline extern __inline __attribute__ ((__gnu_inline__))
|
||||
# define __extern_always_inline \
|
||||
extern __always_inline __attribute__ ((__gnu_inline__))
|
||||
# else
|
||||
# define __extern_inline extern __inline
|
||||
# define __extern_always_inline extern __always_inline
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __extern_always_inline
|
||||
# define __fortify_function __extern_always_inline __attribute_artificial__
|
||||
#endif
|
||||
|
||||
/* GCC 4.3 and above allow passing all anonymous arguments of an
|
||||
__extern_always_inline function to some other vararg function. */
|
||||
#if __GNUC_PREREQ (4,3)
|
||||
# define __va_arg_pack() __builtin_va_arg_pack ()
|
||||
# define __va_arg_pack_len() __builtin_va_arg_pack_len ()
|
||||
#endif
|
||||
|
||||
/* It is possible to compile containing GCC extensions even if GCC is
|
||||
run in pedantic mode if the uses are carefully marked using the
|
||||
`__extension__' keyword. But this is not generally available before
|
||||
version 2.8. */
|
||||
#if !__GNUC_PREREQ (2,8)
|
||||
# define __extension__ /* Ignore */
|
||||
#endif
|
||||
|
||||
/* __restrict is known in EGCS 1.2 and above. */
|
||||
#if !__GNUC_PREREQ (2,92)
|
||||
# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
|
||||
# define __restrict restrict
|
||||
# else
|
||||
# define __restrict /* Ignore */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* ISO C99 also allows to declare arrays as non-overlapping. The syntax is
|
||||
array_name[restrict]
|
||||
GCC 3.1 supports this. */
|
||||
#if __GNUC_PREREQ (3,1) && !defined __GNUG__
|
||||
# define __restrict_arr __restrict
|
||||
#else
|
||||
# ifdef __GNUC__
|
||||
# define __restrict_arr /* Not supported in old GCC. */
|
||||
# else
|
||||
# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
|
||||
# define __restrict_arr restrict
|
||||
# else
|
||||
/* Some other non-C99 compiler. */
|
||||
# define __restrict_arr /* Not supported. */
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
# define __glibc_unlikely(cond) __builtin_expect ((cond), 0)
|
||||
# define __glibc_likely(cond) __builtin_expect ((cond), 1)
|
||||
#else
|
||||
# define __glibc_unlikely(cond) (cond)
|
||||
# define __glibc_likely(cond) (cond)
|
||||
#endif
|
||||
|
||||
#ifdef __has_attribute
|
||||
# define __glibc_has_attribute(attr) __has_attribute (attr)
|
||||
#else
|
||||
# define __glibc_has_attribute(attr) 0
|
||||
#endif
|
||||
|
||||
#if (!defined _Noreturn \
|
||||
&& (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \
|
||||
&& !__GNUC_PREREQ (4,7))
|
||||
# if __GNUC_PREREQ (2,8)
|
||||
# define _Noreturn __attribute__ ((__noreturn__))
|
||||
# else
|
||||
# define _Noreturn
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if __GNUC_PREREQ (8, 0)
|
||||
/* Describes a char array whose address can safely be passed as the first
|
||||
argument to strncpy and strncat, as the char array is not necessarily
|
||||
a NUL-terminated string. */
|
||||
# define __attribute_nonstring__ __attribute__ ((__nonstring__))
|
||||
#else
|
||||
# define __attribute_nonstring__
|
||||
#endif
|
||||
|
||||
#if (!defined _Static_assert && !defined __cplusplus \
|
||||
&& (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \
|
||||
&& (!__GNUC_PREREQ (4, 6) || defined __STRICT_ANSI__))
|
||||
# define _Static_assert(expr, diagnostic) \
|
||||
extern int (*__Static_assert_function (void)) \
|
||||
[!!sizeof (struct { int __error_if_negative: (expr) ? 2 : -1; })]
|
||||
#endif
|
||||
|
||||
/* The #ifndef lets Gnulib avoid including these on non-glibc
|
||||
platforms, where the includes typically do not exist. */
|
||||
#ifndef __WORDSIZE
|
||||
# include <bits/wordsize.h>
|
||||
# include <bits/long-double.h>
|
||||
#endif
|
||||
|
||||
#if defined __LONG_DOUBLE_MATH_OPTIONAL && defined __NO_LONG_DOUBLE_MATH
|
||||
# define __LDBL_COMPAT 1
|
||||
# ifdef __REDIRECT
|
||||
# define __LDBL_REDIR1(name, proto, alias) __REDIRECT (name, proto, alias)
|
||||
# define __LDBL_REDIR(name, proto) \
|
||||
__LDBL_REDIR1 (name, proto, __nldbl_##name)
|
||||
# define __LDBL_REDIR1_NTH(name, proto, alias) __REDIRECT_NTH (name, proto, alias)
|
||||
# define __LDBL_REDIR_NTH(name, proto) \
|
||||
__LDBL_REDIR1_NTH (name, proto, __nldbl_##name)
|
||||
# define __LDBL_REDIR1_DECL(name, alias) \
|
||||
extern __typeof (name) name __asm (__ASMNAME (#alias));
|
||||
# define __LDBL_REDIR_DECL(name) \
|
||||
extern __typeof (name) name __asm (__ASMNAME ("__nldbl_" #name));
|
||||
# define __REDIRECT_LDBL(name, proto, alias) \
|
||||
__LDBL_REDIR1 (name, proto, __nldbl_##alias)
|
||||
# define __REDIRECT_NTH_LDBL(name, proto, alias) \
|
||||
__LDBL_REDIR1_NTH (name, proto, __nldbl_##alias)
|
||||
# endif
|
||||
#endif
|
||||
#if !defined __LDBL_COMPAT || !defined __REDIRECT
|
||||
# define __LDBL_REDIR1(name, proto, alias) name proto
|
||||
# define __LDBL_REDIR(name, proto) name proto
|
||||
# define __LDBL_REDIR1_NTH(name, proto, alias) name proto __THROW
|
||||
# define __LDBL_REDIR_NTH(name, proto) name proto __THROW
|
||||
# define __LDBL_REDIR_DECL(name)
|
||||
# ifdef __REDIRECT
|
||||
# define __REDIRECT_LDBL(name, proto, alias) __REDIRECT (name, proto, alias)
|
||||
# define __REDIRECT_NTH_LDBL(name, proto, alias) \
|
||||
__REDIRECT_NTH (name, proto, alias)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* __glibc_macro_warning (MESSAGE) issues warning MESSAGE. This is
|
||||
intended for use in preprocessor macros.
|
||||
|
||||
Note: MESSAGE must be a _single_ string; concatenation of string
|
||||
literals is not supported. */
|
||||
#if __GNUC_PREREQ (4,8) || __glibc_clang_prereq (3,5)
|
||||
# define __glibc_macro_warning1(message) _Pragma (#message)
|
||||
# define __glibc_macro_warning(message) \
|
||||
__glibc_macro_warning1 (GCC warning message)
|
||||
#else
|
||||
# define __glibc_macro_warning(msg)
|
||||
#endif
|
||||
|
||||
/* Generic selection (ISO C11) is a C-only feature, available in GCC
|
||||
since version 4.9. Previous versions do not provide generic
|
||||
selection, even though they might set __STDC_VERSION__ to 201112L,
|
||||
when in -std=c11 mode. Thus, we must check for !defined __GNUC__
|
||||
when testing __STDC_VERSION__ for generic selection support.
|
||||
On the other hand, Clang also defines __GNUC__, so a clang-specific
|
||||
check is required to enable the use of generic selection. */
|
||||
#if !defined __cplusplus \
|
||||
&& (__GNUC_PREREQ (4, 9) \
|
||||
|| __glibc_clang_has_extension (c_generic_selections) \
|
||||
|| (!defined __GNUC__ && defined __STDC_VERSION__ \
|
||||
&& __STDC_VERSION__ >= 201112L))
|
||||
# define __HAVE_GENERIC_SELECTION 1
|
||||
#else
|
||||
# define __HAVE_GENERIC_SELECTION 0
|
||||
#endif
|
||||
|
||||
#endif /* sys/cdefs.h */
|
||||
264
lib/chdir-long.c
Normal file
264
lib/chdir-long.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/* provide a chdir function that tries not to fail due to ENAMETOOLONG
|
||||
Copyright (C) 2004-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Jim Meyering */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "chdir-long.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "assure.h"
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# error "compile this file only if your system defines PATH_MAX"
|
||||
#endif
|
||||
|
||||
/* The results of openat() in this file are not leaked to any
|
||||
single-threaded code that could use stdio.
|
||||
FIXME - if the kernel ever adds support for multi-thread safety for
|
||||
avoiding standard fds, then we should use openat_safer. */
|
||||
|
||||
struct cd_buf
|
||||
{
|
||||
int fd;
|
||||
};
|
||||
|
||||
static void
|
||||
cdb_init (struct cd_buf *cdb)
|
||||
{
|
||||
cdb->fd = AT_FDCWD;
|
||||
}
|
||||
|
||||
static int
|
||||
cdb_fchdir (struct cd_buf const *cdb)
|
||||
{
|
||||
return fchdir (cdb->fd);
|
||||
}
|
||||
|
||||
static void
|
||||
cdb_free (struct cd_buf const *cdb)
|
||||
{
|
||||
if (0 <= cdb->fd)
|
||||
{
|
||||
bool close_fail = close (cdb->fd);
|
||||
assure (! close_fail);
|
||||
}
|
||||
}
|
||||
|
||||
/* Given a file descriptor of an open directory (or AT_FDCWD), CDB->fd,
|
||||
try to open the CDB->fd-relative directory, DIR. If the open succeeds,
|
||||
update CDB->fd with the resulting descriptor, close the incoming file
|
||||
descriptor, and return zero. Upon failure, return -1 and set errno. */
|
||||
static int
|
||||
cdb_advance_fd (struct cd_buf *cdb, char const *dir)
|
||||
{
|
||||
int new_fd = openat (cdb->fd, dir,
|
||||
O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK);
|
||||
if (new_fd < 0)
|
||||
return -1;
|
||||
|
||||
cdb_free (cdb);
|
||||
cdb->fd = new_fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return a pointer to the first non-slash in S. */
|
||||
static char * _GL_ATTRIBUTE_PURE
|
||||
find_non_slash (char const *s)
|
||||
{
|
||||
size_t n_slash = strspn (s, "/");
|
||||
return (char *) s + n_slash;
|
||||
}
|
||||
|
||||
/* This is a function much like chdir, but without the PATH_MAX limitation
|
||||
on the length of the directory name. A significant difference is that
|
||||
it must be able to modify (albeit only temporarily) the directory
|
||||
name. It handles an arbitrarily long directory name by operating
|
||||
on manageable portions of the name. On systems without the openat
|
||||
syscall, this means changing the working directory to more and more
|
||||
"distant" points along the long directory name and then restoring
|
||||
the working directory. If any of those attempts to save or restore
|
||||
the working directory fails, this function exits nonzero.
|
||||
|
||||
Note that this function may still fail with errno == ENAMETOOLONG, but
|
||||
only if the specified directory name contains a component that is long
|
||||
enough to provoke such a failure all by itself (e.g. if the component
|
||||
has length PATH_MAX or greater on systems that define PATH_MAX). */
|
||||
|
||||
int
|
||||
chdir_long (char *dir)
|
||||
{
|
||||
int e = chdir (dir);
|
||||
if (e == 0 || errno != ENAMETOOLONG)
|
||||
return e;
|
||||
|
||||
{
|
||||
size_t len = strlen (dir);
|
||||
char *dir_end = dir + len;
|
||||
struct cd_buf cdb;
|
||||
size_t n_leading_slash;
|
||||
|
||||
cdb_init (&cdb);
|
||||
|
||||
/* If DIR is the empty string, then the chdir above
|
||||
must have failed and set errno to ENOENT. */
|
||||
assure (0 < len);
|
||||
assure (PATH_MAX <= len);
|
||||
|
||||
/* Count leading slashes. */
|
||||
n_leading_slash = strspn (dir, "/");
|
||||
|
||||
/* Handle any leading slashes as well as any name that matches
|
||||
the regular expression, m!^//hostname[/]*! . Handling this
|
||||
prefix separately usually results in a single additional
|
||||
cdb_advance_fd call, but it's worthwhile, since it makes the
|
||||
code in the following loop cleaner. */
|
||||
if (n_leading_slash == 2)
|
||||
{
|
||||
int err;
|
||||
/* Find next slash.
|
||||
We already know that dir[2] is neither a slash nor '\0'. */
|
||||
char *slash = memchr (dir + 3, '/', dir_end - (dir + 3));
|
||||
if (slash == NULL)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
*slash = '\0';
|
||||
err = cdb_advance_fd (&cdb, dir);
|
||||
*slash = '/';
|
||||
if (err != 0)
|
||||
goto Fail;
|
||||
dir = find_non_slash (slash + 1);
|
||||
}
|
||||
else if (n_leading_slash)
|
||||
{
|
||||
if (cdb_advance_fd (&cdb, "/") != 0)
|
||||
goto Fail;
|
||||
dir += n_leading_slash;
|
||||
}
|
||||
|
||||
assure (*dir != '/');
|
||||
assure (dir <= dir_end);
|
||||
|
||||
while (PATH_MAX <= dir_end - dir)
|
||||
{
|
||||
int err;
|
||||
/* Find a slash that is PATH_MAX or fewer bytes away from dir.
|
||||
I.e. see if there is a slash that will give us a name of
|
||||
length PATH_MAX-1 or less. */
|
||||
char *slash = memrchr (dir, '/', PATH_MAX);
|
||||
if (slash == NULL)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*slash = '\0';
|
||||
assure (slash - dir < PATH_MAX);
|
||||
err = cdb_advance_fd (&cdb, dir);
|
||||
*slash = '/';
|
||||
if (err != 0)
|
||||
goto Fail;
|
||||
|
||||
dir = find_non_slash (slash + 1);
|
||||
}
|
||||
|
||||
if (dir < dir_end)
|
||||
{
|
||||
if (cdb_advance_fd (&cdb, dir) != 0)
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
if (cdb_fchdir (&cdb) != 0)
|
||||
goto Fail;
|
||||
|
||||
cdb_free (&cdb);
|
||||
return 0;
|
||||
|
||||
Fail:
|
||||
{
|
||||
int saved_errno = errno;
|
||||
cdb_free (&cdb);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if TEST_CHDIR
|
||||
|
||||
# include "closeout.h"
|
||||
# include "error.h"
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
char *line = NULL;
|
||||
size_t n = 0;
|
||||
int len;
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
len = getline (&line, &n, stdin);
|
||||
if (len < 0)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
if (feof (stdin))
|
||||
exit (0);
|
||||
|
||||
error (EXIT_FAILURE, saved_errno,
|
||||
"reading standard input");
|
||||
}
|
||||
else if (len == 0)
|
||||
exit (0);
|
||||
|
||||
if (line[len-1] == '\n')
|
||||
line[len-1] = '\0';
|
||||
|
||||
if (chdir_long (line) != 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
"chdir_long failed: %s", line);
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
/* Using 'pwd' here makes sense only if it is a robust implementation,
|
||||
like the one in coreutils after the 2004-04-19 changes. */
|
||||
char const *cmd = "pwd";
|
||||
execlp (cmd, (char *) NULL);
|
||||
error (EXIT_FAILURE, errno, "%s", cmd);
|
||||
}
|
||||
|
||||
fclose (stdin);
|
||||
fclose (stderr);
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
compile-command: "gcc -DTEST_CHDIR=1 -g -O -W -Wall chdir-long.c libcoreutils.a"
|
||||
End:
|
||||
*/
|
||||
30
lib/chdir-long.h
Normal file
30
lib/chdir-long.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* provide a chdir function that tries not to fail due to ENAMETOOLONG
|
||||
Copyright (C) 2004-2005, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Jim Meyering. */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "pathmax.h"
|
||||
|
||||
/* On systems without PATH_MAX, presume that chdir accepts
|
||||
arbitrarily long directory names. */
|
||||
#ifndef PATH_MAX
|
||||
# define chdir_long(Dir) chdir (Dir)
|
||||
#else
|
||||
int chdir_long (char *dir);
|
||||
#endif
|
||||
3
lib/chmodat.c
Normal file
3
lib/chmodat.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#include <config.h>
|
||||
#define CHMODAT_INLINE _GL_EXTERN_INLINE
|
||||
#include "openat.h"
|
||||
151
lib/chown.c
Normal file
151
lib/chown.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/* provide consistent interface to chown for systems that don't interpret
|
||||
an ID of -1 as meaning "don't change the corresponding ID".
|
||||
|
||||
Copyright (C) 1997, 2004-2007, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Jim Meyering */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include <unistd.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if !HAVE_CHOWN
|
||||
|
||||
/* Simple stub that always fails with ENOSYS, for mingw. */
|
||||
int
|
||||
chown (const char *file _GL_UNUSED, uid_t uid _GL_UNUSED,
|
||||
gid_t gid _GL_UNUSED)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else /* HAVE_CHOWN */
|
||||
|
||||
/* Below we refer to the system's chown(). */
|
||||
# undef chown
|
||||
|
||||
/* Provide a more-closely POSIX-conforming version of chown on
|
||||
systems with one or both of the following problems:
|
||||
- chown doesn't treat an ID of -1 as meaning
|
||||
"don't change the corresponding ID".
|
||||
- chown doesn't dereference symlinks. */
|
||||
|
||||
int
|
||||
rpl_chown (const char *file, uid_t uid, gid_t gid)
|
||||
{
|
||||
struct stat st;
|
||||
bool stat_valid = false;
|
||||
int result;
|
||||
|
||||
# if CHOWN_CHANGE_TIME_BUG
|
||||
if (gid != (gid_t) -1 || uid != (uid_t) -1)
|
||||
{
|
||||
if (stat (file, &st))
|
||||
return -1;
|
||||
stat_valid = true;
|
||||
}
|
||||
# endif
|
||||
|
||||
# if CHOWN_FAILS_TO_HONOR_ID_OF_NEGATIVE_ONE
|
||||
if (gid == (gid_t) -1 || uid == (uid_t) -1)
|
||||
{
|
||||
/* Stat file to get id(s) that should remain unchanged. */
|
||||
if (!stat_valid && stat (file, &st))
|
||||
return -1;
|
||||
if (gid == (gid_t) -1)
|
||||
gid = st.st_gid;
|
||||
if (uid == (uid_t) -1)
|
||||
uid = st.st_uid;
|
||||
}
|
||||
# endif
|
||||
|
||||
# if CHOWN_MODIFIES_SYMLINK
|
||||
{
|
||||
/* Handle the case in which the system-supplied chown function
|
||||
does *not* follow symlinks. Instead, it changes permissions
|
||||
on the symlink itself. To work around that, we open the
|
||||
file (but this can fail due to lack of read or write permission) and
|
||||
use fchown on the resulting descriptor. */
|
||||
int open_flags = O_NONBLOCK | O_NOCTTY;
|
||||
int fd = open (file, O_RDONLY | open_flags);
|
||||
if (0 <= fd
|
||||
|| (errno == EACCES
|
||||
&& 0 <= (fd = open (file, O_WRONLY | open_flags))))
|
||||
{
|
||||
int saved_errno;
|
||||
bool fchown_socket_failure;
|
||||
|
||||
result = fchown (fd, uid, gid);
|
||||
saved_errno = errno;
|
||||
|
||||
/* POSIX says fchown can fail with errno == EINVAL on sockets
|
||||
and pipes, so fall back on chown in that case. */
|
||||
fchown_socket_failure =
|
||||
(result != 0 && saved_errno == EINVAL
|
||||
&& fstat (fd, &st) == 0
|
||||
&& (S_ISFIFO (st.st_mode) || S_ISSOCK (st.st_mode)));
|
||||
|
||||
close (fd);
|
||||
|
||||
if (! fchown_socket_failure)
|
||||
{
|
||||
errno = saved_errno;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (errno != EACCES)
|
||||
return -1;
|
||||
}
|
||||
# endif
|
||||
|
||||
# if CHOWN_TRAILING_SLASH_BUG
|
||||
if (!stat_valid)
|
||||
{
|
||||
size_t len = strlen (file);
|
||||
if (len && file[len - 1] == '/' && stat (file, &st))
|
||||
return -1;
|
||||
}
|
||||
# endif
|
||||
|
||||
result = chown (file, uid, gid);
|
||||
|
||||
# if CHOWN_CHANGE_TIME_BUG
|
||||
if (result == 0 && stat_valid
|
||||
&& (uid == st.st_uid || uid == (uid_t) -1)
|
||||
&& (gid == st.st_gid || gid == (gid_t) -1))
|
||||
{
|
||||
/* No change in ownership, but at least one argument was not -1,
|
||||
so we are required to update ctime. Since chown succeeded,
|
||||
we assume that chmod will do likewise. Fortunately, on all
|
||||
known systems where a 'no-op' chown skips the ctime update, a
|
||||
'no-op' chmod still does the trick. */
|
||||
result = chmod (file, st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO
|
||||
| S_ISUID | S_ISGID | S_ISVTX));
|
||||
}
|
||||
# endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* HAVE_CHOWN */
|
||||
3
lib/chownat.c
Normal file
3
lib/chownat.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#include <config.h>
|
||||
#define CHOWNAT_INLINE _GL_EXTERN_INLINE
|
||||
#include "openat.h"
|
||||
76
lib/cl-strtod.c
Normal file
76
lib/cl-strtod.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/* Convert string to double in the current locale, falling back on the C locale.
|
||||
|
||||
Copyright 2019-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Paul Eggert. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "cl-strtod.h"
|
||||
|
||||
#include <c-strtod.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if LONG
|
||||
# define CL_STRTOD cl_strtold
|
||||
# define DOUBLE long double
|
||||
# define C_STRTOD c_strtold
|
||||
# define STRTOD strtold
|
||||
#else
|
||||
# define CL_STRTOD cl_strtod
|
||||
# define DOUBLE double
|
||||
# define C_STRTOD c_strtod
|
||||
# define STRTOD strtod
|
||||
#endif
|
||||
|
||||
/* This function acts like strtod or strtold, except that it falls
|
||||
back on the C locale if the initial prefix is not parsable in
|
||||
the current locale. If the prefix is parsable in both locales,
|
||||
it uses the longer parse, breaking ties in favor of the current locale.
|
||||
|
||||
Parse the initial prefix of NPTR as a floating-point number in the
|
||||
current locale or in the C locale (preferring the locale that
|
||||
yields the longer parse, or the current locale if there is a tie).
|
||||
If ENDPTR is not NULL, set *ENDPTR to the first unused byte, or to
|
||||
NPTR if the prefix cannot be parsed.
|
||||
|
||||
If successful, return a number without changing errno.
|
||||
If the prefix cannot be parsed, return 0 and possibly set errno to EINVAL.
|
||||
If the number overflows, return an extreme value and set errno to ERANGE.
|
||||
If the number underflows, return a value close to 0 and set errno to ERANGE.
|
||||
If there is some other error, return 0 and set errno. */
|
||||
|
||||
DOUBLE
|
||||
CL_STRTOD (char const *nptr, char **restrict endptr)
|
||||
{
|
||||
char *end;
|
||||
DOUBLE d = STRTOD (nptr, &end);
|
||||
if (*end)
|
||||
{
|
||||
int strtod_errno = errno;
|
||||
char *c_end;
|
||||
DOUBLE c = C_STRTOD (nptr, &c_end);
|
||||
if (end < c_end)
|
||||
d = c, end = c_end;
|
||||
else
|
||||
errno = strtod_errno;
|
||||
}
|
||||
if (endptr)
|
||||
*endptr = end;
|
||||
return d;
|
||||
}
|
||||
2
lib/cl-strtod.h
Normal file
2
lib/cl-strtod.h
Normal file
@@ -0,0 +1,2 @@
|
||||
double cl_strtod (char const *, char **restrict);
|
||||
long double cl_strtold (char const *, char **restrict);
|
||||
2
lib/cl-strtold.c
Normal file
2
lib/cl-strtold.c
Normal file
@@ -0,0 +1,2 @@
|
||||
#define LONG 1
|
||||
#include "cl-strtod.c"
|
||||
83
lib/cloexec.c
Normal file
83
lib/cloexec.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/* cloexec.c - set or clear the close-on-exec descriptor flag
|
||||
|
||||
Copyright (C) 1991, 2004-2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
The code is taken from glibc/manual/llio.texi */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "cloexec.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Set the 'FD_CLOEXEC' flag of DESC if VALUE is true,
|
||||
or clear the flag if VALUE is false.
|
||||
Return 0 on success, or -1 on error with 'errno' set.
|
||||
|
||||
Note that on MingW, this function does NOT protect DESC from being
|
||||
inherited into spawned children. Instead, either use dup_cloexec
|
||||
followed by closing the original DESC, or use interfaces such as
|
||||
open or pipe2 that accept flags like O_CLOEXEC to create DESC
|
||||
non-inheritable in the first place. */
|
||||
|
||||
int
|
||||
set_cloexec_flag (int desc, bool value)
|
||||
{
|
||||
#ifdef F_SETFD
|
||||
|
||||
int flags = fcntl (desc, F_GETFD, 0);
|
||||
|
||||
if (0 <= flags)
|
||||
{
|
||||
int newflags = (value ? flags | FD_CLOEXEC : flags & ~FD_CLOEXEC);
|
||||
|
||||
if (flags == newflags
|
||||
|| fcntl (desc, F_SETFD, newflags) != -1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
#else /* !F_SETFD */
|
||||
|
||||
/* Use dup2 to reject invalid file descriptors; the cloexec flag
|
||||
will be unaffected. */
|
||||
if (desc < 0)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
if (dup2 (desc, desc) < 0)
|
||||
/* errno is EBADF here. */
|
||||
return -1;
|
||||
|
||||
/* There is nothing we can do on this kind of platform. Punt. */
|
||||
return 0;
|
||||
#endif /* !F_SETFD */
|
||||
}
|
||||
|
||||
|
||||
/* Duplicates a file handle FD, while marking the copy to be closed
|
||||
prior to exec or spawn. Returns -1 and sets errno if FD could not
|
||||
be duplicated. */
|
||||
|
||||
int
|
||||
dup_cloexec (int fd)
|
||||
{
|
||||
return fcntl (fd, F_DUPFD_CLOEXEC, 0);
|
||||
}
|
||||
38
lib/cloexec.h
Normal file
38
lib/cloexec.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* cloexec.c - set or clear the close-on-exec descriptor flag
|
||||
|
||||
Copyright (C) 2004, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Set the 'FD_CLOEXEC' flag of DESC if VALUE is true,
|
||||
or clear the flag if VALUE is false.
|
||||
Return 0 on success, or -1 on error with 'errno' set.
|
||||
|
||||
Note that on MingW, this function does NOT protect DESC from being
|
||||
inherited into spawned children. Instead, either use dup_cloexec
|
||||
followed by closing the original DESC, or use interfaces such as
|
||||
open or pipe2 that accept flags like O_CLOEXEC to create DESC
|
||||
non-inheritable in the first place. */
|
||||
|
||||
int set_cloexec_flag (int desc, bool value);
|
||||
|
||||
/* Duplicates a file handle FD, while marking the copy to be closed
|
||||
prior to exec or spawn. Returns -1 and sets errno if FD could not
|
||||
be duplicated. */
|
||||
|
||||
int dup_cloexec (int fd);
|
||||
78
lib/close-stream.c
Normal file
78
lib/close-stream.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/* Close a stream, with nicer error checking than fclose's.
|
||||
|
||||
Copyright (C) 1998-2002, 2004, 2006-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "close-stream.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "fpending.h"
|
||||
|
||||
#if USE_UNLOCKED_IO
|
||||
# include "unlocked-io.h"
|
||||
#endif
|
||||
|
||||
/* Close STREAM. Return 0 if successful, EOF (setting errno)
|
||||
otherwise. A failure might set errno to 0 if the error number
|
||||
cannot be determined.
|
||||
|
||||
A failure with errno set to EPIPE may or may not indicate an error
|
||||
situation worth signaling to the user. See the documentation of the
|
||||
close_stdout_set_ignore_EPIPE function for details.
|
||||
|
||||
If a program writes *anything* to STREAM, that program should close
|
||||
STREAM and make sure that it succeeds before exiting. Otherwise,
|
||||
suppose that you go to the extreme of checking the return status
|
||||
of every function that does an explicit write to STREAM. The last
|
||||
printf can succeed in writing to the internal stream buffer, and yet
|
||||
the fclose(STREAM) could still fail (due e.g., to a disk full error)
|
||||
when it tries to write out that buffered data. Thus, you would be
|
||||
left with an incomplete output file and the offending program would
|
||||
exit successfully. Even calling fflush is not always sufficient,
|
||||
since some file systems (NFS and CODA) buffer written/flushed data
|
||||
until an actual close call.
|
||||
|
||||
Besides, it's wasteful to check the return value from every call
|
||||
that writes to STREAM -- just let the internal stream state record
|
||||
the failure. That's what the ferror test is checking below. */
|
||||
|
||||
int
|
||||
close_stream (FILE *stream)
|
||||
{
|
||||
const bool some_pending = (__fpending (stream) != 0);
|
||||
const bool prev_fail = (ferror (stream) != 0);
|
||||
const bool fclose_fail = (fclose (stream) != 0);
|
||||
|
||||
/* Return an error indication if there was a previous failure or if
|
||||
fclose failed, with one exception: ignore an fclose failure if
|
||||
there was no previous error, no data remains to be flushed, and
|
||||
fclose failed with EBADF. That can happen when a program like cp
|
||||
is invoked like this 'cp a b >&-' (i.e., with standard output
|
||||
closed) and doesn't generate any output (hence no previous error
|
||||
and nothing to be flushed). */
|
||||
|
||||
if (prev_fail || (fclose_fail && (some_pending || errno != EBADF)))
|
||||
{
|
||||
if (! fclose_fail)
|
||||
errno = 0;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
2
lib/close-stream.h
Normal file
2
lib/close-stream.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#include <stdio.h>
|
||||
int close_stream (FILE *stream);
|
||||
71
lib/close.c
Normal file
71
lib/close.c
Normal file
@@ -0,0 +1,71 @@
|
||||
/* close replacement.
|
||||
Copyright (C) 2008-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include <unistd.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "fd-hook.h"
|
||||
#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
|
||||
# include "msvc-inval.h"
|
||||
#endif
|
||||
|
||||
#undef close
|
||||
|
||||
#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
|
||||
static int
|
||||
close_nothrow (int fd)
|
||||
{
|
||||
int result;
|
||||
|
||||
TRY_MSVC_INVAL
|
||||
{
|
||||
result = close (fd);
|
||||
}
|
||||
CATCH_MSVC_INVAL
|
||||
{
|
||||
result = -1;
|
||||
errno = EBADF;
|
||||
}
|
||||
DONE_MSVC_INVAL;
|
||||
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
# define close_nothrow close
|
||||
#endif
|
||||
|
||||
/* Override close() to call into other gnulib modules. */
|
||||
|
||||
int
|
||||
rpl_close (int fd)
|
||||
{
|
||||
#if WINDOWS_SOCKETS
|
||||
int retval = execute_all_close_hooks (close_nothrow, fd);
|
||||
#else
|
||||
int retval = close_nothrow (fd);
|
||||
#endif
|
||||
|
||||
#if REPLACE_FCHDIR
|
||||
if (retval >= 0)
|
||||
_gl_unregister_fd (fd);
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
71
lib/closedir.c
Normal file
71
lib/closedir.c
Normal file
@@ -0,0 +1,71 @@
|
||||
/* Stop reading the entries of a directory.
|
||||
Copyright (C) 2006-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include <dirent.h>
|
||||
|
||||
#if REPLACE_FCHDIR
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_CLOSEDIR
|
||||
|
||||
/* Override closedir(), to keep track of the open file descriptors.
|
||||
Needed because there is a function dirfd(). */
|
||||
|
||||
#else
|
||||
|
||||
# include <stdlib.h>
|
||||
|
||||
# include "dirent-private.h"
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
closedir (DIR *dirp)
|
||||
{
|
||||
# if REPLACE_FCHDIR || REPLACE_DIRFD
|
||||
int fd = dirfd (dirp);
|
||||
# endif
|
||||
int retval;
|
||||
|
||||
#if HAVE_CLOSEDIR
|
||||
# undef closedir
|
||||
|
||||
retval = closedir (dirp);
|
||||
|
||||
# ifdef __KLIBC__
|
||||
if (!retval)
|
||||
_gl_unregister_dirp_fd (fd);
|
||||
# endif
|
||||
#else
|
||||
|
||||
if (dirp->current != INVALID_HANDLE_VALUE)
|
||||
FindClose (dirp->current);
|
||||
free (dirp);
|
||||
|
||||
retval = 0;
|
||||
|
||||
#endif
|
||||
|
||||
#if REPLACE_FCHDIR
|
||||
if (retval >= 0)
|
||||
_gl_unregister_fd (fd);
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
112
lib/closein.c
Normal file
112
lib/closein.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/* Close standard input, rewinding seekable stdin if necessary.
|
||||
|
||||
Copyright (C) 2007, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "closein.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "gettext.h"
|
||||
#define _(msgid) gettext (msgid)
|
||||
|
||||
#include "close-stream.h"
|
||||
#include "closeout.h"
|
||||
#include "error.h"
|
||||
#include "exitfail.h"
|
||||
#include "freadahead.h"
|
||||
#include "quotearg.h"
|
||||
|
||||
static const char *file_name;
|
||||
|
||||
/* Set the file name to be reported in the event an error is detected
|
||||
on stdin by close_stdin. See also close_stdout_set_file_name, if
|
||||
an error is detected when closing stdout. */
|
||||
void
|
||||
close_stdin_set_file_name (const char *file)
|
||||
{
|
||||
file_name = file;
|
||||
}
|
||||
|
||||
/* Close standard input, rewinding any unused input if stdin is
|
||||
seekable. On error, issue a diagnostic and _exit with status
|
||||
'exit_failure'. Then call close_stdout.
|
||||
|
||||
Most programs can get by with close_stdout. close_stdin is only
|
||||
needed when a program wants to guarantee that partially read input
|
||||
from seekable stdin is not consumed, for any subsequent clients.
|
||||
For example, POSIX requires that these two commands behave alike:
|
||||
|
||||
(sed -ne 1q; cat) < file
|
||||
tail -n +2 file
|
||||
|
||||
Since close_stdin is commonly registered via 'atexit', POSIX
|
||||
and the C standard both say that it should not call 'exit',
|
||||
because the behavior is undefined if 'exit' is called more than
|
||||
once. So it calls '_exit' instead of 'exit'. If close_stdin
|
||||
is registered via atexit before other functions are registered,
|
||||
the other functions can act before this _exit is invoked.
|
||||
|
||||
Applications that use close_stdout should flush any streams other
|
||||
than stdin, stdout, and stderr before exiting, since the call to
|
||||
_exit will bypass other buffer flushing. Applications should be
|
||||
flushing and closing other streams anyway, to check for I/O errors.
|
||||
Also, applications should not use tmpfile, since _exit can bypass
|
||||
the removal of these files.
|
||||
|
||||
It's important to detect such failures and exit nonzero because many
|
||||
tools (most notably 'make' and other build-management systems) depend
|
||||
on being able to detect failure in other tools via their exit status. */
|
||||
|
||||
void
|
||||
close_stdin (void)
|
||||
{
|
||||
bool fail = false;
|
||||
|
||||
/* There is no need to flush stdin if we can determine quickly that stdin's
|
||||
input buffer is empty; in this case we know that if stdin is seekable,
|
||||
(fseeko (stdin, 0, SEEK_CUR), ftello (stdin))
|
||||
== lseek (0, 0, SEEK_CUR). */
|
||||
if (freadahead (stdin) > 0)
|
||||
{
|
||||
/* Only attempt flush if stdin is seekable, as fflush is entitled to
|
||||
fail on non-seekable streams. */
|
||||
if (fseeko (stdin, 0, SEEK_CUR) == 0 && fflush (stdin) != 0)
|
||||
fail = true;
|
||||
}
|
||||
if (close_stream (stdin) != 0)
|
||||
fail = true;
|
||||
if (fail)
|
||||
{
|
||||
/* Report failure, but defer exit until after closing stdout,
|
||||
since the failure report should still be flushed. */
|
||||
char const *close_error = _("error closing file");
|
||||
if (file_name)
|
||||
error (0, errno, "%s: %s", quotearg_colon (file_name),
|
||||
close_error);
|
||||
else
|
||||
error (0, errno, "%s", close_error);
|
||||
}
|
||||
|
||||
close_stdout ();
|
||||
|
||||
if (fail)
|
||||
_exit (exit_failure);
|
||||
}
|
||||
32
lib/closein.h
Normal file
32
lib/closein.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/* Close standard input, rewinding seekable stdin if necessary.
|
||||
|
||||
Copyright (C) 2007, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _GL_CLOSEIN_H
|
||||
# define _GL_CLOSEIN_H 1
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
void close_stdin_set_file_name (const char *file);
|
||||
void close_stdin (void);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
136
lib/closeout.c
Normal file
136
lib/closeout.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/* Close standard output and standard error, exiting with a diagnostic on error.
|
||||
|
||||
Copyright (C) 1998-2002, 2004, 2006, 2008-2020 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "closeout.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "gettext.h"
|
||||
#define _(msgid) gettext (msgid)
|
||||
|
||||
#include "close-stream.h"
|
||||
#include "error.h"
|
||||
#include "exitfail.h"
|
||||
#include "quotearg.h"
|
||||
|
||||
#ifndef __has_feature
|
||||
# define __has_feature(a) false
|
||||
#endif
|
||||
|
||||
#if defined __SANITIZE_ADDRESS__ || __has_feature (address_sanitizer)
|
||||
enum { SANITIZE_ADDRESS = true };
|
||||
#else
|
||||
enum { SANITIZE_ADDRESS = false };
|
||||
#endif
|
||||
|
||||
static const char *file_name;
|
||||
|
||||
/* Set the file name to be reported in the event an error is detected
|
||||
by close_stdout. */
|
||||
void
|
||||
close_stdout_set_file_name (const char *file)
|
||||
{
|
||||
file_name = file;
|
||||
}
|
||||
|
||||
static bool ignore_EPIPE /* = false */;
|
||||
|
||||
/* Specify the reaction to an EPIPE error during the closing of stdout:
|
||||
- If ignore = true, it shall be ignored.
|
||||
- If ignore = false, it shall evoke a diagnostic, along with a nonzero
|
||||
exit status.
|
||||
The default is ignore = false.
|
||||
|
||||
This setting matters only if the SIGPIPE signal is ignored (i.e. its
|
||||
handler set to SIG_IGN) or blocked. Only particular programs need to
|
||||
temporarily ignore SIGPIPE. If SIGPIPE is ignored or blocked because
|
||||
it was ignored or blocked in the parent process when it created the
|
||||
child process, it usually is a bug in the parent process: It is bad
|
||||
practice to have SIGPIPE ignored or blocked while creating a child
|
||||
process.
|
||||
|
||||
EPIPE occurs when writing to a pipe or socket that has no readers now,
|
||||
when SIGPIPE is ignored or blocked.
|
||||
|
||||
The ignore = false setting is suitable for a scenario where it is normally
|
||||
guaranteed that the pipe writer terminates before the pipe reader. In
|
||||
this case, an EPIPE is an indication of a premature termination of the
|
||||
pipe reader and should lead to a diagnostic and a nonzero exit status.
|
||||
|
||||
The ignore = true setting is suitable for a scenario where you don't know
|
||||
ahead of time whether the pipe writer or the pipe reader will terminate
|
||||
first. In this case, an EPIPE is an indication that the pipe writer can
|
||||
stop doing useless write() calls; this is what close_stdout does anyway.
|
||||
EPIPE is part of the normal pipe/socket shutdown protocol in this case,
|
||||
and should not lead to a diagnostic message. */
|
||||
|
||||
void
|
||||
close_stdout_set_ignore_EPIPE (bool ignore)
|
||||
{
|
||||
ignore_EPIPE = ignore;
|
||||
}
|
||||
|
||||
/* Close standard output. On error, issue a diagnostic and _exit
|
||||
with status 'exit_failure'.
|
||||
|
||||
Also close standard error. On error, _exit with status 'exit_failure'.
|
||||
|
||||
Since close_stdout is commonly registered via 'atexit', POSIX
|
||||
and the C standard both say that it should not call 'exit',
|
||||
because the behavior is undefined if 'exit' is called more than
|
||||
once. So it calls '_exit' instead of 'exit'. If close_stdout
|
||||
is registered via atexit before other functions are registered,
|
||||
the other functions can act before this _exit is invoked.
|
||||
|
||||
Applications that use close_stdout should flush any streams
|
||||
other than stdout and stderr before exiting, since the call to
|
||||
_exit will bypass other buffer flushing. Applications should
|
||||
be flushing and closing other streams anyway, to check for I/O
|
||||
errors. Also, applications should not use tmpfile, since _exit
|
||||
can bypass the removal of these files.
|
||||
|
||||
It's important to detect such failures and exit nonzero because many
|
||||
tools (most notably 'make' and other build-management systems) depend
|
||||
on being able to detect failure in other tools via their exit status. */
|
||||
|
||||
void
|
||||
close_stdout (void)
|
||||
{
|
||||
if (close_stream (stdout) != 0
|
||||
&& !(ignore_EPIPE && errno == EPIPE))
|
||||
{
|
||||
char const *write_error = _("write error");
|
||||
if (file_name)
|
||||
error (0, errno, "%s: %s", quotearg_colon (file_name),
|
||||
write_error);
|
||||
else
|
||||
error (0, errno, "%s", write_error);
|
||||
|
||||
_exit (exit_failure);
|
||||
}
|
||||
|
||||
/* Close stderr only if not sanitizing, as sanitizers may report to
|
||||
stderr after this function returns. */
|
||||
if (!SANITIZE_ADDRESS && close_stream (stderr) != 0)
|
||||
_exit (exit_failure);
|
||||
}
|
||||
36
lib/closeout.h
Normal file
36
lib/closeout.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/* Close standard output and standard error.
|
||||
|
||||
Copyright (C) 1998, 2000, 2003-2004, 2006, 2008-2020 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef CLOSEOUT_H
|
||||
# define CLOSEOUT_H 1
|
||||
|
||||
# include <stdbool.h>
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
void close_stdout_set_file_name (const char *file);
|
||||
void close_stdout_set_ignore_EPIPE (bool ignore);
|
||||
void close_stdout (void);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
3812
lib/config.h
Normal file
3812
lib/config.h
Normal file
File diff suppressed because it is too large
Load Diff
3811
lib/config.hin
Normal file
3811
lib/config.hin
Normal file
File diff suppressed because it is too large
Load Diff
31
lib/configmake.h
Normal file
31
lib/configmake.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||||
#if HAVE_WINSOCK2_H
|
||||
# include <winsock2.h> /* avoid mingw pollution on DATADIR */
|
||||
#endif
|
||||
#define PREFIX "/data/coreutils"
|
||||
#define EXEC_PREFIX "/data/coreutils"
|
||||
#define BINDIR "/data/coreutils/bin"
|
||||
#define SBINDIR "/data/coreutils/sbin"
|
||||
#define LIBEXECDIR "/data/coreutils/libexec"
|
||||
#define DATAROOTDIR "/data/coreutils/share"
|
||||
#define DATADIR "/data/coreutils/share"
|
||||
#define SYSCONFDIR "/data/coreutils/etc"
|
||||
#define SHAREDSTATEDIR "/data/coreutils/com"
|
||||
#define LOCALSTATEDIR "/data/coreutils/var"
|
||||
#define RUNSTATEDIR "/data/coreutils/var/run"
|
||||
#define INCLUDEDIR "/data/coreutils/include"
|
||||
#define OLDINCLUDEDIR "/usr/include"
|
||||
#define DOCDIR "/data/coreutils/share/doc/coreutils"
|
||||
#define INFODIR "/data/coreutils/share/info"
|
||||
#define HTMLDIR "/data/coreutils/share/doc/coreutils"
|
||||
#define DVIDIR "/data/coreutils/share/doc/coreutils"
|
||||
#define PDFDIR "/data/coreutils/share/doc/coreutils"
|
||||
#define PSDIR "/data/coreutils/share/doc/coreutils"
|
||||
#define LIBDIR "/data/coreutils/lib"
|
||||
#define LISPDIR "/data/coreutils/share/emacs/site-lisp"
|
||||
#define LOCALEDIR "/data/coreutils/share/locale"
|
||||
#define MANDIR "/data/coreutils/share/man"
|
||||
#define PKGDATADIR "/data/coreutils/share/coreutils"
|
||||
#define PKGINCLUDEDIR "/data/coreutils/include/coreutils"
|
||||
#define PKGLIBDIR "/data/coreutils/lib/coreutils"
|
||||
#define PKGLIBEXECDIR "/data/coreutils/libexec/coreutils"
|
||||
61
lib/copy-acl.c
Normal file
61
lib/copy-acl.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/* Copy access control list from one file to file. -*- coding: utf-8 -*-
|
||||
|
||||
Copyright (C) 2002-2003, 2005-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "acl.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "quote.h"
|
||||
#include "error.h"
|
||||
#include "gettext.h"
|
||||
#define _(msgid) gettext (msgid)
|
||||
|
||||
|
||||
/* Copy access control lists from one file to another. If SOURCE_DESC is
|
||||
a valid file descriptor, use file descriptor operations, else use
|
||||
filename based operations on SRC_NAME. Likewise for DEST_DESC and
|
||||
DST_NAME.
|
||||
If access control lists are not available, fchmod the target file to
|
||||
MODE. Also sets the non-permission bits of the destination file
|
||||
(S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
|
||||
Return 0 if successful, otherwise output a diagnostic and return a
|
||||
negative error code. */
|
||||
|
||||
int
|
||||
copy_acl (const char *src_name, int source_desc, const char *dst_name,
|
||||
int dest_desc, mode_t mode)
|
||||
{
|
||||
int ret = qcopy_acl (src_name, source_desc, dst_name, dest_desc, mode);
|
||||
switch (ret)
|
||||
{
|
||||
case -2:
|
||||
error (0, errno, "%s", quote (src_name));
|
||||
break;
|
||||
|
||||
case -1:
|
||||
error (0, errno, _("preserving permissions for %s"), quote (dst_name));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
3
lib/count-leading-zeros.c
Normal file
3
lib/count-leading-zeros.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#include <config.h>
|
||||
#define COUNT_LEADING_ZEROS_INLINE _GL_EXTERN_INLINE
|
||||
#include "count-leading-zeros.h"
|
||||
121
lib/count-leading-zeros.h
Normal file
121
lib/count-leading-zeros.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/* count-leading-zeros.h -- counts the number of leading 0 bits in a word.
|
||||
Copyright (C) 2012-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Eric Blake. */
|
||||
|
||||
#ifndef COUNT_LEADING_ZEROS_H
|
||||
#define COUNT_LEADING_ZEROS_H 1
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef _GL_INLINE_HEADER_BEGIN
|
||||
#error "Please include config.h first."
|
||||
#endif
|
||||
_GL_INLINE_HEADER_BEGIN
|
||||
#ifndef COUNT_LEADING_ZEROS_INLINE
|
||||
# define COUNT_LEADING_ZEROS_INLINE _GL_INLINE
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Assuming the GCC builtin is BUILTIN and the MSC builtin is MSC_BUILTIN,
|
||||
expand to code that computes the number of leading zeros of the local
|
||||
variable 'x' of type TYPE (an unsigned integer type) and return it
|
||||
from the current function. */
|
||||
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
||||
# define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \
|
||||
return x ? BUILTIN (x) : CHAR_BIT * sizeof x;
|
||||
#elif _MSC_VER
|
||||
# pragma intrinsic _BitScanReverse
|
||||
# pragma intrinsic _BitScanReverse64
|
||||
# define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \
|
||||
do \
|
||||
{ \
|
||||
unsigned long result; \
|
||||
return MSC_BUILTIN (&result, x) ? result : CHAR_BIT * sizeof x; \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
# define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \
|
||||
do \
|
||||
{ \
|
||||
int count; \
|
||||
unsigned int leading_32; \
|
||||
if (! x) \
|
||||
return CHAR_BIT * sizeof x; \
|
||||
for (count = 0; \
|
||||
(leading_32 = ((x >> (sizeof (TYPE) * CHAR_BIT - 32)) \
|
||||
& 0xffffffffU), \
|
||||
count < CHAR_BIT * sizeof x - 32 && !leading_32); \
|
||||
count += 32) \
|
||||
x = x << 31 << 1; \
|
||||
return count + count_leading_zeros_32 (leading_32); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* Compute and return the number of leading zeros in X,
|
||||
where 0 < X < 2**32. */
|
||||
COUNT_LEADING_ZEROS_INLINE int
|
||||
count_leading_zeros_32 (unsigned int x)
|
||||
{
|
||||
/* <https://github.com/gibsjose/BitHacks>
|
||||
<https://www.fit.vutbr.cz/~ibarina/pub/bithacks.pdf> */
|
||||
static const char de_Bruijn_lookup[32] = {
|
||||
31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1,
|
||||
23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0
|
||||
};
|
||||
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
return de_Bruijn_lookup[((x * 0x07c4acddU) & 0xffffffffU) >> 27];
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Compute and return the number of leading zeros in X. */
|
||||
COUNT_LEADING_ZEROS_INLINE int
|
||||
count_leading_zeros (unsigned int x)
|
||||
{
|
||||
COUNT_LEADING_ZEROS (__builtin_clz, _BitScanReverse, unsigned int);
|
||||
}
|
||||
|
||||
/* Compute and return the number of leading zeros in X. */
|
||||
COUNT_LEADING_ZEROS_INLINE int
|
||||
count_leading_zeros_l (unsigned long int x)
|
||||
{
|
||||
COUNT_LEADING_ZEROS (__builtin_clzl, _BitScanReverse, unsigned long int);
|
||||
}
|
||||
|
||||
/* Compute and return the number of leading zeros in X. */
|
||||
COUNT_LEADING_ZEROS_INLINE int
|
||||
count_leading_zeros_ll (unsigned long long int x)
|
||||
{
|
||||
COUNT_LEADING_ZEROS (__builtin_clzll, _BitScanReverse64,
|
||||
unsigned long long int);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
_GL_INLINE_HEADER_END
|
||||
|
||||
#endif /* COUNT_LEADING_ZEROS_H */
|
||||
31
lib/creat-safer.c
Normal file
31
lib/creat-safer.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/* Invoke creat, but avoid some glitches.
|
||||
|
||||
Copyright (C) 2005-2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Jim Meyering. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "fcntl-safer.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "unistd-safer.h"
|
||||
|
||||
int
|
||||
creat_safer (char const *file, mode_t mode)
|
||||
{
|
||||
return fd_safer (creat (file, mode));
|
||||
}
|
||||
502
lib/ctype.h
Normal file
502
lib/ctype.h
Normal file
@@ -0,0 +1,502 @@
|
||||
/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||||
/* A substitute for ISO C99 <ctype.h>, for platforms on which it is incomplete.
|
||||
|
||||
Copyright (C) 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Bruno Haible. */
|
||||
|
||||
/*
|
||||
* ISO C 99 <ctype.h> for platforms on which it is incomplete.
|
||||
* <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/ctype.h.html>
|
||||
*/
|
||||
|
||||
#ifndef _GL_CTYPE_H
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
|
||||
/* Include the original <ctype.h>. */
|
||||
/* The include_next requires a split double-inclusion guard. */
|
||||
#include_next <ctype.h>
|
||||
|
||||
#ifndef _GL_CTYPE_H
|
||||
#define _GL_CTYPE_H
|
||||
|
||||
/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
|
||||
/* C++ compatible function declaration macros.
|
||||
Copyright (C) 2010-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _GL_CXXDEFS_H
|
||||
#define _GL_CXXDEFS_H
|
||||
|
||||
/* Begin/end the GNULIB_NAMESPACE namespace. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_BEGIN_NAMESPACE namespace GNULIB_NAMESPACE {
|
||||
# define _GL_END_NAMESPACE }
|
||||
#else
|
||||
# define _GL_BEGIN_NAMESPACE
|
||||
# define _GL_END_NAMESPACE
|
||||
#endif
|
||||
|
||||
/* The three most frequent use cases of these macros are:
|
||||
|
||||
* For providing a substitute for a function that is missing on some
|
||||
platforms, but is declared and works fine on the platforms on which
|
||||
it exists:
|
||||
|
||||
#if @GNULIB_FOO@
|
||||
# if !@HAVE_FOO@
|
||||
_GL_FUNCDECL_SYS (foo, ...);
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (foo, ...);
|
||||
_GL_CXXALIASWARN (foo);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
...
|
||||
#endif
|
||||
|
||||
* For providing a replacement for a function that exists on all platforms,
|
||||
but is broken/insufficient and needs to be replaced on some platforms:
|
||||
|
||||
#if @GNULIB_FOO@
|
||||
# if @REPLACE_FOO@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef foo
|
||||
# define foo rpl_foo
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (foo, ...);
|
||||
_GL_CXXALIAS_RPL (foo, ...);
|
||||
# else
|
||||
_GL_CXXALIAS_SYS (foo, ...);
|
||||
# endif
|
||||
_GL_CXXALIASWARN (foo);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
...
|
||||
#endif
|
||||
|
||||
* For providing a replacement for a function that exists on some platforms
|
||||
but is broken/insufficient and needs to be replaced on some of them and
|
||||
is additionally either missing or undeclared on some other platforms:
|
||||
|
||||
#if @GNULIB_FOO@
|
||||
# if @REPLACE_FOO@
|
||||
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
|
||||
# undef foo
|
||||
# define foo rpl_foo
|
||||
# endif
|
||||
_GL_FUNCDECL_RPL (foo, ...);
|
||||
_GL_CXXALIAS_RPL (foo, ...);
|
||||
# else
|
||||
# if !@HAVE_FOO@ or if !@HAVE_DECL_FOO@
|
||||
_GL_FUNCDECL_SYS (foo, ...);
|
||||
# endif
|
||||
_GL_CXXALIAS_SYS (foo, ...);
|
||||
# endif
|
||||
_GL_CXXALIASWARN (foo);
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
...
|
||||
#endif
|
||||
*/
|
||||
|
||||
/* _GL_EXTERN_C declaration;
|
||||
performs the declaration with C linkage. */
|
||||
#if defined __cplusplus
|
||||
# define _GL_EXTERN_C extern "C"
|
||||
#else
|
||||
# define _GL_EXTERN_C extern
|
||||
#endif
|
||||
|
||||
/* _GL_FUNCDECL_RPL (func, rettype, parameters_and_attributes);
|
||||
declares a replacement function, named rpl_func, with the given prototype,
|
||||
consisting of return type, parameters, and attributes.
|
||||
Example:
|
||||
_GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...)
|
||||
_GL_ARG_NONNULL ((1)));
|
||||
*/
|
||||
#define _GL_FUNCDECL_RPL(func,rettype,parameters_and_attributes) \
|
||||
_GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters_and_attributes)
|
||||
#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters_and_attributes) \
|
||||
_GL_EXTERN_C rettype rpl_func parameters_and_attributes
|
||||
|
||||
/* _GL_FUNCDECL_SYS (func, rettype, parameters_and_attributes);
|
||||
declares the system function, named func, with the given prototype,
|
||||
consisting of return type, parameters, and attributes.
|
||||
Example:
|
||||
_GL_FUNCDECL_SYS (open, int, (const char *filename, int flags, ...)
|
||||
_GL_ARG_NONNULL ((1)));
|
||||
*/
|
||||
#define _GL_FUNCDECL_SYS(func,rettype,parameters_and_attributes) \
|
||||
_GL_EXTERN_C rettype func parameters_and_attributes
|
||||
|
||||
/* _GL_CXXALIAS_RPL (func, rettype, parameters);
|
||||
declares a C++ alias called GNULIB_NAMESPACE::func
|
||||
that redirects to rpl_func, if GNULIB_NAMESPACE is defined.
|
||||
Example:
|
||||
_GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...));
|
||||
|
||||
Wrapping rpl_func in an object with an inline conversion operator
|
||||
avoids a reference to rpl_func unless GNULIB_NAMESPACE::func is
|
||||
actually used in the program. */
|
||||
#define _GL_CXXALIAS_RPL(func,rettype,parameters) \
|
||||
_GL_CXXALIAS_RPL_1 (func, rpl_##func, rettype, parameters)
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return ::rpl_func; \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIAS_RPL_CAST_1 (func, rpl_func, rettype, parameters);
|
||||
is like _GL_CXXALIAS_RPL_1 (func, rpl_func, rettype, parameters);
|
||||
except that the C function rpl_func may have a slightly different
|
||||
declaration. A cast is used to silence the "invalid conversion" error
|
||||
that would otherwise occur. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return reinterpret_cast<type>(::rpl_func); \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIAS_SYS (func, rettype, parameters);
|
||||
declares a C++ alias called GNULIB_NAMESPACE::func
|
||||
that redirects to the system provided function func, if GNULIB_NAMESPACE
|
||||
is defined.
|
||||
Example:
|
||||
_GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));
|
||||
|
||||
Wrapping func in an object with an inline conversion operator
|
||||
avoids a reference to func unless GNULIB_NAMESPACE::func is
|
||||
actually used in the program. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return ::func; \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIAS_SYS_CAST (func, rettype, parameters);
|
||||
is like _GL_CXXALIAS_SYS (func, rettype, parameters);
|
||||
except that the C function func may have a slightly different declaration.
|
||||
A cast is used to silence the "invalid conversion" error that would
|
||||
otherwise occur. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return reinterpret_cast<type>(::func); \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIAS_SYS_CAST2 (func, rettype, parameters, rettype2, parameters2);
|
||||
is like _GL_CXXALIAS_SYS (func, rettype, parameters);
|
||||
except that the C function is picked among a set of overloaded functions,
|
||||
namely the one with rettype2 and parameters2. Two consecutive casts
|
||||
are used to silence the "cannot find a match" and "invalid conversion"
|
||||
errors that would otherwise occur. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
/* The outer cast must be a reinterpret_cast.
|
||||
The inner cast: When the function is defined as a set of overloaded
|
||||
functions, it works as a static_cast<>, choosing the designated variant.
|
||||
When the function is defined as a single variant, it works as a
|
||||
reinterpret_cast<>. The parenthesized cast syntax works both ways. */
|
||||
# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
|
||||
namespace GNULIB_NAMESPACE \
|
||||
{ \
|
||||
static const struct _gl_ ## func ## _wrapper \
|
||||
{ \
|
||||
typedef rettype (*type) parameters; \
|
||||
\
|
||||
inline operator type () const \
|
||||
{ \
|
||||
return reinterpret_cast<type>((rettype2 (*) parameters2)(::func)); \
|
||||
} \
|
||||
} func = {}; \
|
||||
} \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#else
|
||||
# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIASWARN (func);
|
||||
causes a warning to be emitted when ::func is used but not when
|
||||
GNULIB_NAMESPACE::func is used. func must be defined without overloaded
|
||||
variants. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIASWARN(func) \
|
||||
_GL_CXXALIASWARN_1 (func, GNULIB_NAMESPACE)
|
||||
# define _GL_CXXALIASWARN_1(func,namespace) \
|
||||
_GL_CXXALIASWARN_2 (func, namespace)
|
||||
/* To work around GCC bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43881>,
|
||||
we enable the warning only when not optimizing. */
|
||||
# if !__OPTIMIZE__
|
||||
# define _GL_CXXALIASWARN_2(func,namespace) \
|
||||
_GL_WARN_ON_USE (func, \
|
||||
"The symbol ::" #func " refers to the system function. " \
|
||||
"Use " #namespace "::" #func " instead.")
|
||||
# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
|
||||
# define _GL_CXXALIASWARN_2(func,namespace) \
|
||||
extern __typeof__ (func) func
|
||||
# else
|
||||
# define _GL_CXXALIASWARN_2(func,namespace) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
# endif
|
||||
#else
|
||||
# define _GL_CXXALIASWARN(func) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
/* _GL_CXXALIASWARN1 (func, rettype, parameters_and_attributes);
|
||||
causes a warning to be emitted when the given overloaded variant of ::func
|
||||
is used but not when GNULIB_NAMESPACE::func is used. */
|
||||
#if defined __cplusplus && defined GNULIB_NAMESPACE
|
||||
# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
|
||||
_GL_CXXALIASWARN1_1 (func, rettype, parameters_and_attributes, \
|
||||
GNULIB_NAMESPACE)
|
||||
# define _GL_CXXALIASWARN1_1(func,rettype,parameters_and_attributes,namespace) \
|
||||
_GL_CXXALIASWARN1_2 (func, rettype, parameters_and_attributes, namespace)
|
||||
/* To work around GCC bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43881>,
|
||||
we enable the warning only when not optimizing. */
|
||||
# if !__OPTIMIZE__
|
||||
# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
|
||||
_GL_WARN_ON_USE_CXX (func, rettype, parameters_and_attributes, \
|
||||
"The symbol ::" #func " refers to the system function. " \
|
||||
"Use " #namespace "::" #func " instead.")
|
||||
# else
|
||||
# define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
# endif
|
||||
#else
|
||||
# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
|
||||
_GL_EXTERN_C int _gl_cxxalias_dummy
|
||||
#endif
|
||||
|
||||
#endif /* _GL_CXXDEFS_H */
|
||||
|
||||
/* The definition of _GL_WARN_ON_USE is copied here. */
|
||||
/* A C macro for emitting warnings if a function is used.
|
||||
Copyright (C) 2010-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* _GL_WARN_ON_USE (function, "literal string") issues a declaration
|
||||
for FUNCTION which will then trigger a compiler warning containing
|
||||
the text of "literal string" anywhere that function is called, if
|
||||
supported by the compiler. If the compiler does not support this
|
||||
feature, the macro expands to an unused extern declaration.
|
||||
|
||||
_GL_WARN_ON_USE_ATTRIBUTE ("literal string") expands to the
|
||||
attribute used in _GL_WARN_ON_USE. If the compiler does not support
|
||||
this feature, it expands to empty.
|
||||
|
||||
These macros are useful for marking a function as a potential
|
||||
portability trap, with the intent that "literal string" include
|
||||
instructions on the replacement function that should be used
|
||||
instead.
|
||||
_GL_WARN_ON_USE is for functions with 'extern' linkage.
|
||||
_GL_WARN_ON_USE_ATTRIBUTE is for functions with 'static' or 'inline'
|
||||
linkage.
|
||||
|
||||
However, one of the reasons that a function is a portability trap is
|
||||
if it has the wrong signature. Declaring FUNCTION with a different
|
||||
signature in C is a compilation error, so this macro must use the
|
||||
same type as any existing declaration so that programs that avoid
|
||||
the problematic FUNCTION do not fail to compile merely because they
|
||||
included a header that poisoned the function. But this implies that
|
||||
_GL_WARN_ON_USE is only safe to use if FUNCTION is known to already
|
||||
have a declaration. Use of this macro implies that there must not
|
||||
be any other macro hiding the declaration of FUNCTION; but
|
||||
undefining FUNCTION first is part of the poisoning process anyway
|
||||
(although for symbols that are provided only via a macro, the result
|
||||
is a compilation error rather than a warning containing
|
||||
"literal string"). Also note that in C++, it is only safe to use if
|
||||
FUNCTION has no overloads.
|
||||
|
||||
For an example, it is possible to poison 'getline' by:
|
||||
- adding a call to gl_WARN_ON_USE_PREPARE([[#include <stdio.h>]],
|
||||
[getline]) in configure.ac, which potentially defines
|
||||
HAVE_RAW_DECL_GETLINE
|
||||
- adding this code to a header that wraps the system <stdio.h>:
|
||||
#undef getline
|
||||
#if HAVE_RAW_DECL_GETLINE
|
||||
_GL_WARN_ON_USE (getline, "getline is required by POSIX 2008, but"
|
||||
"not universally present; use the gnulib module getline");
|
||||
#endif
|
||||
|
||||
It is not possible to directly poison global variables. But it is
|
||||
possible to write a wrapper accessor function, and poison that
|
||||
(less common usage, like &environ, will cause a compilation error
|
||||
rather than issue the nice warning, but the end result of informing
|
||||
the developer about their portability problem is still achieved):
|
||||
#if HAVE_RAW_DECL_ENVIRON
|
||||
static char ***
|
||||
rpl_environ (void) { return &environ; }
|
||||
_GL_WARN_ON_USE (rpl_environ, "environ is not always properly declared");
|
||||
# undef environ
|
||||
# define environ (*rpl_environ ())
|
||||
#endif
|
||||
or better (avoiding contradictory use of 'static' and 'extern'):
|
||||
#if HAVE_RAW_DECL_ENVIRON
|
||||
static char ***
|
||||
_GL_WARN_ON_USE_ATTRIBUTE ("environ is not always properly declared")
|
||||
rpl_environ (void) { return &environ; }
|
||||
# undef environ
|
||||
# define environ (*rpl_environ ())
|
||||
#endif
|
||||
*/
|
||||
#ifndef _GL_WARN_ON_USE
|
||||
|
||||
# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)
|
||||
/* A compiler attribute is available in gcc versions 4.3.0 and later. */
|
||||
# define _GL_WARN_ON_USE(function, message) \
|
||||
extern __typeof__ (function) function __attribute__ ((__warning__ (message)))
|
||||
# define _GL_WARN_ON_USE_ATTRIBUTE(message) \
|
||||
__attribute__ ((__warning__ (message)))
|
||||
# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
|
||||
/* Verify the existence of the function. */
|
||||
# define _GL_WARN_ON_USE(function, message) \
|
||||
extern __typeof__ (function) function
|
||||
# define _GL_WARN_ON_USE_ATTRIBUTE(message)
|
||||
# else /* Unsupported. */
|
||||
# define _GL_WARN_ON_USE(function, message) \
|
||||
_GL_WARN_EXTERN_C int _gl_warn_on_use
|
||||
# define _GL_WARN_ON_USE_ATTRIBUTE(message)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* _GL_WARN_ON_USE_CXX (function, rettype, parameters_and_attributes, "string")
|
||||
is like _GL_WARN_ON_USE (function, "string"), except that the function is
|
||||
declared with the given prototype, consisting of return type, parameters,
|
||||
and attributes.
|
||||
This variant is useful for overloaded functions in C++. _GL_WARN_ON_USE does
|
||||
not work in this case. */
|
||||
#ifndef _GL_WARN_ON_USE_CXX
|
||||
# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)
|
||||
# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \
|
||||
extern rettype function parameters_and_attributes \
|
||||
__attribute__ ((__warning__ (msg)))
|
||||
# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
|
||||
/* Verify the existence of the function. */
|
||||
# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \
|
||||
extern rettype function parameters_and_attributes
|
||||
# else /* Unsupported. */
|
||||
# define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \
|
||||
_GL_WARN_EXTERN_C int _gl_warn_on_use
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* _GL_WARN_EXTERN_C declaration;
|
||||
performs the declaration with C linkage. */
|
||||
#ifndef _GL_WARN_EXTERN_C
|
||||
# if defined __cplusplus
|
||||
# define _GL_WARN_EXTERN_C extern "C"
|
||||
# else
|
||||
# define _GL_WARN_EXTERN_C extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Return non-zero if c is a blank, i.e. a space or tab character. */
|
||||
#if 1
|
||||
# if !1
|
||||
_GL_EXTERN_C int isblank (int c);
|
||||
# endif
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef isblank
|
||||
# if HAVE_RAW_DECL_ISBLANK
|
||||
_GL_WARN_ON_USE (isblank, "isblank is unportable - "
|
||||
"use gnulib module isblank for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* _GL_CTYPE_H */
|
||||
#endif /* _GL_CTYPE_H */
|
||||
57
lib/ctype.in.h
Normal file
57
lib/ctype.in.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* A substitute for ISO C99 <ctype.h>, for platforms on which it is incomplete.
|
||||
|
||||
Copyright (C) 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Bruno Haible. */
|
||||
|
||||
/*
|
||||
* ISO C 99 <ctype.h> for platforms on which it is incomplete.
|
||||
* <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/ctype.h.html>
|
||||
*/
|
||||
|
||||
#ifndef _@GUARD_PREFIX@_CTYPE_H
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
@PRAGMA_SYSTEM_HEADER@
|
||||
#endif
|
||||
@PRAGMA_COLUMNS@
|
||||
|
||||
/* Include the original <ctype.h>. */
|
||||
/* The include_next requires a split double-inclusion guard. */
|
||||
#@INCLUDE_NEXT@ @NEXT_CTYPE_H@
|
||||
|
||||
#ifndef _@GUARD_PREFIX@_CTYPE_H
|
||||
#define _@GUARD_PREFIX@_CTYPE_H
|
||||
|
||||
/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
|
||||
|
||||
/* The definition of _GL_WARN_ON_USE is copied here. */
|
||||
|
||||
/* Return non-zero if c is a blank, i.e. a space or tab character. */
|
||||
#if @GNULIB_ISBLANK@
|
||||
# if !@HAVE_ISBLANK@
|
||||
_GL_EXTERN_C int isblank (int c);
|
||||
# endif
|
||||
#elif defined GNULIB_POSIXCHECK
|
||||
# undef isblank
|
||||
# if HAVE_RAW_DECL_ISBLANK
|
||||
_GL_WARN_ON_USE (isblank, "isblank is unportable - "
|
||||
"use gnulib module isblank for portability");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* _@GUARD_PREFIX@_CTYPE_H */
|
||||
#endif /* _@GUARD_PREFIX@_CTYPE_H */
|
||||
85
lib/cycle-check.c
Normal file
85
lib/cycle-check.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/* help detect directory cycles efficiently
|
||||
|
||||
Copyright (C) 2003-2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Jim Meyering */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "cycle-check.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "assure.h"
|
||||
|
||||
#define CC_MAGIC 9827862
|
||||
|
||||
/* Return true if I is a power of 2, or is zero. */
|
||||
|
||||
static bool
|
||||
is_zero_or_power_of_two (uintmax_t i)
|
||||
{
|
||||
return (i & (i - 1)) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
cycle_check_init (struct cycle_check_state *state)
|
||||
{
|
||||
state->chdir_counter = 0;
|
||||
state->magic = CC_MAGIC;
|
||||
}
|
||||
|
||||
/* In traversing a directory hierarchy, call this function once for each
|
||||
descending chdir call, with SB corresponding to the chdir operand.
|
||||
If SB corresponds to a directory that has already been seen,
|
||||
return true to indicate that there is a directory cycle.
|
||||
Note that this is done "lazily", which means that some of
|
||||
the directories in the cycle may be processed twice before
|
||||
the cycle is detected. */
|
||||
|
||||
bool
|
||||
cycle_check (struct cycle_check_state *state, struct stat const *sb)
|
||||
{
|
||||
assure (state->magic == CC_MAGIC);
|
||||
|
||||
/* If the current directory ever happens to be the same
|
||||
as the one we last recorded for the cycle detection,
|
||||
then it's obviously part of a cycle. */
|
||||
if (state->chdir_counter && SAME_INODE (*sb, state->dev_ino))
|
||||
return true;
|
||||
|
||||
/* If the number of "descending" chdir calls is a power of two,
|
||||
record the dev/ino of the current directory. */
|
||||
if (is_zero_or_power_of_two (++(state->chdir_counter)))
|
||||
{
|
||||
/* On all architectures that we know about, if the counter
|
||||
overflows then there is a directory cycle here somewhere,
|
||||
even if we haven't detected it yet. Typically this happens
|
||||
only after the counter is incremented 2**64 times, so it's a
|
||||
fairly theoretical point. */
|
||||
if (state->chdir_counter == 0)
|
||||
return true;
|
||||
|
||||
state->dev_ino.st_dev = sb->st_dev;
|
||||
state->dev_ino.st_ino = sb->st_ino;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
52
lib/cycle-check.h
Normal file
52
lib/cycle-check.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* help detect directory cycles efficiently
|
||||
|
||||
Copyright (C) 2003-2004, 2006, 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Jim Meyering */
|
||||
|
||||
#ifndef CYCLE_CHECK_H
|
||||
# define CYCLE_CHECK_H 1
|
||||
|
||||
# include <stdint.h>
|
||||
# include <stdbool.h>
|
||||
# include "dev-ino.h"
|
||||
# include "same-inode.h"
|
||||
|
||||
struct cycle_check_state
|
||||
{
|
||||
struct dev_ino dev_ino;
|
||||
uintmax_t chdir_counter;
|
||||
int magic;
|
||||
};
|
||||
|
||||
void cycle_check_init (struct cycle_check_state *state);
|
||||
bool cycle_check (struct cycle_check_state *state, struct stat const *sb);
|
||||
|
||||
# define CYCLE_CHECK_REFLECT_CHDIR_UP(State, SB_dir, SB_subdir) \
|
||||
do \
|
||||
{ \
|
||||
/* You must call cycle_check at least once before using this macro. */ \
|
||||
if ((State)->chdir_counter == 0) \
|
||||
abort (); \
|
||||
if (SAME_INODE ((State)->dev_ino, SB_subdir)) \
|
||||
{ \
|
||||
(State)->dev_ino.st_dev = (SB_dir).st_dev; \
|
||||
(State)->dev_ino.st_ino = (SB_dir).st_ino; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#endif
|
||||
13
lib/dev-ino.h
Normal file
13
lib/dev-ino.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef DEV_INO_H
|
||||
# define DEV_INO_H 1
|
||||
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
|
||||
struct dev_ino
|
||||
{
|
||||
ino_t st_ino;
|
||||
dev_t st_dev;
|
||||
};
|
||||
|
||||
#endif
|
||||
260
lib/di-set.c
Normal file
260
lib/di-set.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/* Set operations for device-inode pairs stored in a space-efficient manner.
|
||||
|
||||
Copyright 2009-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* written by Paul Eggert and Jim Meyering */
|
||||
|
||||
#include <config.h>
|
||||
#include "di-set.h"
|
||||
|
||||
#include "hash.h"
|
||||
#include "ino-map.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* The hash package hashes "void *", but this package wants to hash
|
||||
integers. Use integers that are as large as possible, but no
|
||||
larger than void *, so that they can be cast to void * and back
|
||||
without losing information. */
|
||||
typedef size_t hashint;
|
||||
#define HASHINT_MAX ((hashint) -1)
|
||||
|
||||
/* Integers represent inode numbers. Integers in the range
|
||||
1..(LARGE_INO_MIN-1) represent inode numbers directly. (The hash
|
||||
package does not work with null pointers, so inode 0 cannot be used
|
||||
as a key.) To find the representations of other inode numbers, map
|
||||
them through INO_MAP. */
|
||||
#define LARGE_INO_MIN (HASHINT_MAX / 2)
|
||||
|
||||
/* Set operations for device-inode pairs stored in a space-efficient
|
||||
manner. Use a two-level hash table. The top level hashes by
|
||||
device number, as there are typically a small number of devices.
|
||||
The lower level hashes by mapped inode numbers. In the typical
|
||||
case where the inode number is positive and small, the inode number
|
||||
maps to itself, masquerading as a void * value; otherwise, its
|
||||
value is the result of hashing the inode value through INO_MAP. */
|
||||
|
||||
/* A pair that maps a device number to a set of inode numbers. */
|
||||
struct di_ent
|
||||
{
|
||||
dev_t dev;
|
||||
struct hash_table *ino_set;
|
||||
};
|
||||
|
||||
/* A two-level hash table that manages and indexes these pairs. */
|
||||
struct di_set
|
||||
{
|
||||
/* Map device numbers to sets of inode number representatives. */
|
||||
struct hash_table *dev_map;
|
||||
|
||||
/* If nonnull, map large inode numbers to their small
|
||||
representatives. If null, there are no large inode numbers in
|
||||
this set. */
|
||||
struct ino_map *ino_map;
|
||||
|
||||
/* Cache of the most recently allocated and otherwise-unused storage
|
||||
for probing this table. */
|
||||
struct di_ent *probe;
|
||||
};
|
||||
|
||||
/* Hash a device-inode-set entry. */
|
||||
static size_t
|
||||
di_ent_hash (void const *x, size_t table_size)
|
||||
{
|
||||
struct di_ent const *p = x;
|
||||
dev_t dev = p->dev;
|
||||
|
||||
/* When DEV is wider than size_t, exclusive-OR the words of DEV into H.
|
||||
This avoids loss of info, without applying % to the wider type,
|
||||
which could be quite slow on some systems. */
|
||||
size_t h = dev;
|
||||
unsigned int i;
|
||||
unsigned int n_words = sizeof dev / sizeof h + (sizeof dev % sizeof h != 0);
|
||||
for (i = 1; i < n_words; i++)
|
||||
h ^= dev >> CHAR_BIT * sizeof h * i;
|
||||
|
||||
return h % table_size;
|
||||
}
|
||||
|
||||
/* Return true if two device-inode-set entries are the same. */
|
||||
static bool
|
||||
di_ent_compare (void const *x, void const *y)
|
||||
{
|
||||
struct di_ent const *a = x;
|
||||
struct di_ent const *b = y;
|
||||
return a->dev == b->dev;
|
||||
}
|
||||
|
||||
/* Free a device-inode-set entry. */
|
||||
static void
|
||||
di_ent_free (void *v)
|
||||
{
|
||||
struct di_ent *a = v;
|
||||
hash_free (a->ino_set);
|
||||
free (a);
|
||||
}
|
||||
|
||||
/* Create a set of device-inode pairs. Return NULL on allocation failure. */
|
||||
struct di_set *
|
||||
di_set_alloc (void)
|
||||
{
|
||||
struct di_set *dis = malloc (sizeof *dis);
|
||||
if (dis)
|
||||
{
|
||||
enum { INITIAL_DEV_MAP_SIZE = 11 };
|
||||
dis->dev_map = hash_initialize (INITIAL_DEV_MAP_SIZE, NULL,
|
||||
di_ent_hash, di_ent_compare,
|
||||
di_ent_free);
|
||||
if (! dis->dev_map)
|
||||
{
|
||||
free (dis);
|
||||
return NULL;
|
||||
}
|
||||
dis->ino_map = NULL;
|
||||
dis->probe = NULL;
|
||||
}
|
||||
|
||||
return dis;
|
||||
}
|
||||
|
||||
/* Free a set of device-inode pairs. */
|
||||
void
|
||||
di_set_free (struct di_set *dis)
|
||||
{
|
||||
hash_free (dis->dev_map);
|
||||
if (dis->ino_map)
|
||||
ino_map_free (dis->ino_map);
|
||||
free (dis->probe);
|
||||
free (dis);
|
||||
}
|
||||
|
||||
/* Hash an encoded inode number I. */
|
||||
static size_t
|
||||
di_ino_hash (void const *i, size_t table_size)
|
||||
{
|
||||
return (hashint) i % table_size;
|
||||
}
|
||||
|
||||
/* Using the DIS table, map a device to a hash table that represents
|
||||
a set of inode numbers. Return NULL on error. */
|
||||
static struct hash_table *
|
||||
map_device (struct di_set *dis, dev_t dev)
|
||||
{
|
||||
/* Find space for the probe, reusing the cache if available. */
|
||||
struct di_ent *ent;
|
||||
struct di_ent *probe = dis->probe;
|
||||
if (probe)
|
||||
{
|
||||
/* If repeating a recent query, return the cached result. */
|
||||
if (probe->dev == dev)
|
||||
return probe->ino_set;
|
||||
}
|
||||
else
|
||||
{
|
||||
dis->probe = probe = malloc (sizeof *probe);
|
||||
if (! probe)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Probe for the device. */
|
||||
probe->dev = dev;
|
||||
ent = hash_insert (dis->dev_map, probe);
|
||||
if (! ent)
|
||||
return NULL;
|
||||
|
||||
if (ent != probe)
|
||||
{
|
||||
/* Use the existing entry. */
|
||||
probe->ino_set = ent->ino_set;
|
||||
}
|
||||
else
|
||||
{
|
||||
enum { INITIAL_INO_SET_SIZE = 1021 };
|
||||
|
||||
/* Prepare to allocate a new probe next time; this one is in use. */
|
||||
dis->probe = NULL;
|
||||
|
||||
/* DEV is new; allocate an inode set for it. */
|
||||
probe->ino_set = hash_initialize (INITIAL_INO_SET_SIZE, NULL,
|
||||
di_ino_hash, NULL, NULL);
|
||||
}
|
||||
|
||||
return probe->ino_set;
|
||||
}
|
||||
|
||||
/* Using the DIS table, map an inode number to a mapped value.
|
||||
Return INO_MAP_INSERT_FAILURE on error. */
|
||||
static hashint
|
||||
map_inode_number (struct di_set *dis, ino_t ino)
|
||||
{
|
||||
if (0 < ino && ino < LARGE_INO_MIN)
|
||||
return ino;
|
||||
|
||||
if (! dis->ino_map)
|
||||
{
|
||||
dis->ino_map = ino_map_alloc (LARGE_INO_MIN);
|
||||
if (! dis->ino_map)
|
||||
return INO_MAP_INSERT_FAILURE;
|
||||
}
|
||||
|
||||
return ino_map_insert (dis->ino_map, ino);
|
||||
}
|
||||
|
||||
/* Attempt to insert the DEV,INO pair into the set DIS.
|
||||
If it matches a pair already in DIS, keep that pair and return 0.
|
||||
Otherwise, if insertion is successful, return 1.
|
||||
Upon any failure return -1. */
|
||||
int
|
||||
di_set_insert (struct di_set *dis, dev_t dev, ino_t ino)
|
||||
{
|
||||
hashint i;
|
||||
|
||||
/* Map the device number to a set of inodes. */
|
||||
struct hash_table *ino_set = map_device (dis, dev);
|
||||
if (! ino_set)
|
||||
return -1;
|
||||
|
||||
/* Map the inode number to a small representative I. */
|
||||
i = map_inode_number (dis, ino);
|
||||
if (i == INO_MAP_INSERT_FAILURE)
|
||||
return -1;
|
||||
|
||||
/* Put I into the inode set. */
|
||||
return hash_insert_if_absent (ino_set, (void const *) i, NULL);
|
||||
}
|
||||
|
||||
/* Look up the DEV,INO pair in the set DIS.
|
||||
If found, return 1; if not found, return 0.
|
||||
Upon any failure return -1. */
|
||||
int
|
||||
di_set_lookup (struct di_set *dis, dev_t dev, ino_t ino)
|
||||
{
|
||||
hashint i;
|
||||
|
||||
/* Map the device number to a set of inodes. */
|
||||
struct hash_table *ino_set = map_device (dis, dev);
|
||||
if (! ino_set)
|
||||
return -1;
|
||||
|
||||
/* Map the inode number to a small representative I. */
|
||||
i = map_inode_number (dis, ino);
|
||||
if (i == INO_MAP_INSERT_FAILURE)
|
||||
return -1;
|
||||
|
||||
/* Perform the look-up. */
|
||||
return !!hash_lookup (ino_set, (void const *) i);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user