diff options
author | yar <yar@FreeBSD.org> | 2008-01-26 17:09:40 +0000 |
---|---|---|
committer | yar <yar@FreeBSD.org> | 2008-01-26 17:09:40 +0000 |
commit | ac1e4103b99e1e9f8d65dd75a868092bf0bf5fe0 (patch) | |
tree | 2a5d945168363a5dc91eeeca07c233b9f6a775a2 /include | |
parent | bbd4f2a2116be9844c33e49113b99b9fcfe493be (diff) | |
download | FreeBSD-src-ac1e4103b99e1e9f8d65dd75a868092bf0bf5fe0.zip FreeBSD-src-ac1e4103b99e1e9f8d65dd75a868092bf0bf5fe0.tar.gz |
Our fts(3) API, as inherited from 4.4BSD, suffers from integer
fields in FTS and FTSENT structs being too narrow. In addition,
the narrow types creep from there into fts.c. As a result, fts(3)
consumers, e.g., find(1) or rm(1), can't handle file trees an ordinary
user can create, which can have security implications.
To fix the historic implementation of fts(3), OpenBSD and NetBSD
have already changed <fts.h> in somewhat incompatible ways, so we
are free to do so, too. This change is a superset of changes from
the other BSDs with a few more improvements. It doesn't touch
fts(3) functionality; it just extends integer types used by it to
match modern reality and the C standard.
Here are its points:
o For C object sizes, use size_t unless it's 100% certain that
the object will be really small. (Note that fts(3) can construct
pathnames _much_ longer than PATH_MAX for its consumers.)
o Avoid the short types because on modern platforms using them
results in larger and slower code. Change shorts to ints as
follows:
- For variables than count simple, limited things like states,
use plain vanilla `int' as it's the type of choice in C.
- For a limited number of bit flags use `unsigned' because signed
bit-wise operations are implementation-defined, i.e., unportable,
in C.
o For things that should be at least 64 bits wide, use long long
and not int64_t, as the latter is an optional type. See
FTSENT.fts_number aka FTS.fts_bignum. Extending fts_number `to
satisfy future needs' is pointless because there is fts_pointer,
which can be used to link to arbitrary data from an FTSENT.
However, there already are fts(3) consumers that require fts_number,
or fts_bignum, have at least 64 bits in it, so we must allow for them.
o For the tree depth, use `long'. This is a trade-off between making
this field too wide and allowing for 64-bit inode numbers and/or
chain-mounted filesystems. On the one hand, `long' is almost
enough for 32-bit filesystems on a 32-bit platform (our ino_t is
uint32_t now). On the other hand, platforms with a 64-bit (or
wider) `long' will be ready for 64-bit inode numbers, as well as
for several 32-bit filesystems mounted one under another. Note
that fts_level has to be signed because -1 is a magic value for it,
FTS_ROOTPARENTLEVEL.
o For the `nlinks' local var in fts_build(), use `long'. The logic
in fts_build() requires that `nlinks' be signed, but our nlink_t
currently is uint16_t. Therefore let's make the signed var wide
enough to be able to represent 2^16-1 in pure C99, and even 2^32-1
on a 64-bit platform. Perhaps the logic should be changed just
to use nlink_t, but it can be done later w/o breaking fts(3) ABI
any more because `nlinks' is just a local var.
This commit also inludes supporting stuff for the fts change:
o Preserve the old versions of fts(3) functions through libc symbol
versioning because the old versions appeared in all our former releases.
o Bump __FreeBSD_version just in case. There is a small chance that
some ill-written 3-rd party apps may fail to build or work correctly
if compiled after this change.
o Update the fts(3) manpage accordingly. In particular, remove
references to fts_bignum, which was a FreeBSD-specific hack to work
around the too narrow types of FTSENT members. Now fts_number is
at least 64 bits wide (long long) and fts_bignum is an undocumented
alias for fts_number kept around for compatibility reasons. According
to Google Code Search, the only big consumers of fts_bignum are in
our own source tree, so they can be fixed easily to use fts_number.
o Mention the change in src/UPDATING.
PR: bin/104458
Approved by: re (quite a while ago)
Discussed with: deischen (the symbol versioning part)
Reviewed by: -arch (mostly silence); das (generally OK, but we didn't
agree on some types used; assuming that no objections on
-arch let me to stick to my opinion)
Diffstat (limited to 'include')
-rw-r--r-- | include/fts.h | 29 |
1 files changed, 11 insertions, 18 deletions
diff --git a/include/fts.h b/include/fts.h index 7eb03a6..cd3da87 100644 --- a/include/fts.h +++ b/include/fts.h @@ -44,8 +44,8 @@ typedef struct { dev_t fts_dev; /* starting device # */ char *fts_path; /* path for this descent */ int fts_rfd; /* fd for root */ - int fts_pathlen; /* sizeof(path) */ - int fts_nitems; /* elements in the sort array */ + size_t fts_pathlen; /* sizeof(path) */ + size_t fts_nitems; /* elements in the sort array */ int (*fts_compar) /* compare function */ (const struct _ftsent * const *, const struct _ftsent * const *); @@ -69,22 +69,15 @@ typedef struct _ftsent { struct _ftsent *fts_cycle; /* cycle node */ struct _ftsent *fts_parent; /* parent directory */ struct _ftsent *fts_link; /* next file in directory */ - union { - struct { - long __fts_number; /* local numeric value */ - void *__fts_pointer; /* local address value */ - } __struct_ftsent; - int64_t __fts_bignum; - } __union_ftsent; -#define fts_number __union_ftsent.__struct_ftsent.__fts_number -#define fts_pointer __union_ftsent.__struct_ftsent.__fts_pointer -#define fts_bignum __union_ftsent.__fts_bignum + long long fts_number; /* local numeric value */ +#define fts_bignum fts_number /* XXX non-std, should go away */ + void *fts_pointer; /* local address value */ char *fts_accpath; /* access path */ char *fts_path; /* root path */ int fts_errno; /* errno for this node */ int fts_symfd; /* fd for symlink */ - u_short fts_pathlen; /* strlen(fts_path) */ - u_short fts_namelen; /* strlen(fts_name) */ + size_t fts_pathlen; /* strlen(fts_path) */ + size_t fts_namelen; /* strlen(fts_name) */ ino_t fts_ino; /* inode */ dev_t fts_dev; /* device */ @@ -92,7 +85,7 @@ typedef struct _ftsent { #define FTS_ROOTPARENTLEVEL -1 #define FTS_ROOTLEVEL 0 - short fts_level; /* depth (-1 to N) */ + long fts_level; /* depth (-1 to N) */ #define FTS_D 1 /* preorder directory */ #define FTS_DC 2 /* directory that causes cycles */ @@ -108,18 +101,18 @@ typedef struct _ftsent { #define FTS_SL 12 /* symbolic link */ #define FTS_SLNONE 13 /* symbolic link without target */ #define FTS_W 14 /* whiteout object */ - u_short fts_info; /* user flags for FTSENT structure */ + int fts_info; /* user status for FTSENT structure */ #define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */ #define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */ #define FTS_ISW 0x04 /* this is a whiteout object */ - u_short fts_flags; /* private flags for FTSENT structure */ + unsigned fts_flags; /* private flags for FTSENT structure */ #define FTS_AGAIN 1 /* read node again */ #define FTS_FOLLOW 2 /* follow symbolic link */ #define FTS_NOINSTR 3 /* no instructions */ #define FTS_SKIP 4 /* discard node */ - u_short fts_instr; /* fts_set() instructions */ + int fts_instr; /* fts_set() instructions */ struct stat *fts_statp; /* stat(2) information */ char *fts_name; /* file name */ |