Enhance vfs.ino64_trunc_error sysctl.

Provide a new mode "2" which returns a special overflow indicator in
the non-representable field instead of the silent truncation (mode
"0") or EOVERFLOW (mode "1").

In particular, the typical use of st_ino to detect hard links with
mode "2" reports false positives, which might be more suitable for
some uses.

Discussed with:	bde
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Konstantin Belousov 2017-06-09 11:17:08 +00:00
parent 15eaaf082a
commit 7abe0df223
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=319734
2 changed files with 61 additions and 10 deletions

View File

@ -1911,11 +1911,31 @@ freebsd11_cvtstat32(struct stat *in, struct freebsd11_stat32 *out)
{
CP(*in, *out, st_ino);
if (in->st_ino != out->st_ino && ino64_trunc_error)
return (EOVERFLOW);
if (in->st_ino != out->st_ino) {
switch (ino64_trunc_error) {
default:
case 0:
break;
case 1:
return (EOVERFLOW);
case 2:
out->st_ino = UINT32_MAX;
break;
}
}
CP(*in, *out, st_nlink);
if (in->st_nlink != out->st_nlink && ino64_trunc_error)
return (EOVERFLOW);
if (in->st_nlink != out->st_nlink) {
switch (ino64_trunc_error) {
default:
case 0:
break;
case 1:
return (EOVERFLOW);
case 2:
out->st_nlink = UINT16_MAX;
break;
}
}
CP(*in, *out, st_dev);
CP(*in, *out, st_mode);
CP(*in, *out, st_uid);

View File

@ -2117,12 +2117,32 @@ freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost)
ost->st_dev = st->st_dev;
ost->st_ino = st->st_ino;
if (ost->st_ino != st->st_ino && ino64_trunc_error)
return (EOVERFLOW);
if (ost->st_ino != st->st_ino) {
switch (ino64_trunc_error) {
default:
case 0:
break;
case 1:
return (EOVERFLOW);
case 2:
ost->st_ino = UINT32_MAX;
break;
}
}
ost->st_mode = st->st_mode;
ost->st_nlink = st->st_nlink;
if (ost->st_nlink != st->st_nlink && ino64_trunc_error)
return (EOVERFLOW);
if (ost->st_nlink != st->st_nlink) {
switch (ino64_trunc_error) {
default:
case 0:
break;
case 1:
return (EOVERFLOW);
case 2:
ost->st_nlink = UINT16_MAX;
break;
}
}
ost->st_uid = st->st_uid;
ost->st_gid = st->st_gid;
ost->st_rdev = st->st_rdev;
@ -3751,8 +3771,19 @@ freebsd11_kern_getdirentries(struct thread *td, int fd, char *ubuf, u_int count,
dstdp.d_type = dp->d_type;
dstdp.d_namlen = dp->d_namlen;
dstdp.d_fileno = dp->d_fileno; /* truncate */
if (dstdp.d_fileno != dp->d_fileno && ino64_trunc_error)
continue;
if (dstdp.d_fileno != dp->d_fileno) {
switch (ino64_trunc_error) {
default:
case 0:
break;
case 1:
error = EOVERFLOW;
goto done;
case 2:
dstdp.d_fileno = UINT32_MAX;
break;
}
}
dstdp.d_reclen = sizeof(dstdp) - sizeof(dstdp.d_name) +
((dp->d_namlen + 1 + 3) &~ 3);
bcopy(dp->d_name, dstdp.d_name, dstdp.d_namlen);