- Add a custom version of exec_copyin_args() to deal with the 32-bit
pointers in argv and envv in userland and use that together with kern_execve() and exec_free_args() to implement freebsd32_execve() without using the stackgap. - Fix freebsd32_adjtime() to call adjtime() rather than utimes(). Still uses stackgap for now. - Use kern_setitimer(), kern_getitimer(), kern_select(), kern_utimes(), kern_statfs(), kern_fstatfs(), kern_fhstatfs(), kern_stat(), kern_fstat(), and kern_lstat(). Tested by: cokane (amd64) Silence on: amd64, ia64
This commit is contained in:
parent
78e436448f
commit
38765a3178
@ -222,65 +222,111 @@ freebsd32_sigaltstack(struct thread *td,
|
|||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Custom version of exec_copyin_args() so that we can translate
|
||||||
|
* the pointers.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
freebsd32_exec_copyin_args(struct image_args *args, char *fname,
|
||||||
|
enum uio_seg segflg, u_int32_t *argv, u_int32_t *envv)
|
||||||
|
{
|
||||||
|
char *argp, *envp;
|
||||||
|
u_int32_t *p32, arg;
|
||||||
|
size_t length;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
bzero(args, sizeof(*args));
|
||||||
|
if (argv == NULL)
|
||||||
|
return (EFAULT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate temporary demand zeroed space for argument and
|
||||||
|
* environment strings
|
||||||
|
*/
|
||||||
|
args->buf = (char *) kmem_alloc_wait(exec_map, PATH_MAX + ARG_MAX);
|
||||||
|
if (args->buf == NULL)
|
||||||
|
return (ENOMEM);
|
||||||
|
args->begin_argv = args->buf;
|
||||||
|
args->endp = args->begin_argv;
|
||||||
|
args->stringspace = ARG_MAX;
|
||||||
|
|
||||||
|
args->fname = args->buf + ARG_MAX;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy the file name.
|
||||||
|
*/
|
||||||
|
error = (segflg == UIO_SYSSPACE) ?
|
||||||
|
copystr(fname, args->fname, PATH_MAX, &length) :
|
||||||
|
copyinstr(fname, args->fname, PATH_MAX, &length);
|
||||||
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extract arguments first
|
||||||
|
*/
|
||||||
|
p32 = argv;
|
||||||
|
for (;;) {
|
||||||
|
error = copyin(p32++, &arg, sizeof(arg));
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
if (arg == 0)
|
||||||
|
break;
|
||||||
|
argp = PTRIN(arg);
|
||||||
|
error = copyinstr(argp, args->endp, args->stringspace, &length);
|
||||||
|
if (error) {
|
||||||
|
if (error == ENAMETOOLONG)
|
||||||
|
return (E2BIG);
|
||||||
|
else
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
args->stringspace -= length;
|
||||||
|
args->endp += length;
|
||||||
|
args->argc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
args->begin_envv = args->endp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extract environment strings
|
||||||
|
*/
|
||||||
|
if (envv) {
|
||||||
|
p32 = envv;
|
||||||
|
for (;;) {
|
||||||
|
error = copyin(p32++, &arg, sizeof(arg));
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
if (arg == 0)
|
||||||
|
break;
|
||||||
|
envp = PTRIN(arg);
|
||||||
|
error = copyinstr(envp, args->endp, args->stringspace,
|
||||||
|
&length);
|
||||||
|
if (error) {
|
||||||
|
if (error == ENAMETOOLONG)
|
||||||
|
return (E2BIG);
|
||||||
|
else
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
args->stringspace -= length;
|
||||||
|
args->endp += length;
|
||||||
|
args->envc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
freebsd32_execve(struct thread *td, struct freebsd32_execve_args *uap)
|
freebsd32_execve(struct thread *td, struct freebsd32_execve_args *uap)
|
||||||
{
|
{
|
||||||
|
struct image_args eargs;
|
||||||
int error;
|
int error;
|
||||||
caddr_t sg;
|
|
||||||
struct execve_args ap;
|
|
||||||
u_int32_t *p32, arg;
|
|
||||||
char **p, *p64;
|
|
||||||
int count;
|
|
||||||
|
|
||||||
sg = stackgap_init();
|
error = freebsd32_exec_copyin_args(&eargs, uap->fname, UIO_USERSPACE,
|
||||||
ap.fname = uap->fname;
|
uap->argv, uap->envv);
|
||||||
|
if (error == 0)
|
||||||
if (uap->argv) {
|
error = kern_execve(td, &eargs, NULL);
|
||||||
count = 0;
|
exec_free_args(&eargs);
|
||||||
p32 = uap->argv;
|
return (error);
|
||||||
do {
|
|
||||||
error = copyin(p32++, &arg, sizeof(arg));
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
count++;
|
|
||||||
} while (arg != 0);
|
|
||||||
p = stackgap_alloc(&sg, count * sizeof(char *));
|
|
||||||
ap.argv = p;
|
|
||||||
p32 = uap->argv;
|
|
||||||
do {
|
|
||||||
error = copyin(p32++, &arg, sizeof(arg));
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
p64 = PTRIN(arg);
|
|
||||||
error = copyout(&p64, p++, sizeof(p64));
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
} while (arg != 0);
|
|
||||||
}
|
|
||||||
if (uap->envv) {
|
|
||||||
count = 0;
|
|
||||||
p32 = uap->envv;
|
|
||||||
do {
|
|
||||||
error = copyin(p32++, &arg, sizeof(arg));
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
count++;
|
|
||||||
} while (arg != 0);
|
|
||||||
p = stackgap_alloc(&sg, count * sizeof(char *));
|
|
||||||
ap.envv = p;
|
|
||||||
p32 = uap->envv;
|
|
||||||
do {
|
|
||||||
error = copyin(p32++, &arg, sizeof(arg));
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
p64 = PTRIN(arg);
|
|
||||||
error = copyout(&p64, p++, sizeof(p64));
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
} while (arg != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return execve(td, &ap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __ia64__
|
#ifdef __ia64__
|
||||||
@ -437,99 +483,63 @@ CTASSERT(sizeof(struct itimerval32) == 16);
|
|||||||
int
|
int
|
||||||
freebsd32_setitimer(struct thread *td, struct freebsd32_setitimer_args *uap)
|
freebsd32_setitimer(struct thread *td, struct freebsd32_setitimer_args *uap)
|
||||||
{
|
{
|
||||||
|
struct itimerval itv, oitv, *itvp;
|
||||||
|
struct itimerval32 i32;
|
||||||
int error;
|
int error;
|
||||||
caddr_t sg;
|
|
||||||
struct itimerval32 *p32, *op32, s32;
|
|
||||||
struct itimerval *p = NULL, *op = NULL, s;
|
|
||||||
|
|
||||||
p32 = uap->itv;
|
if (uap->itv != NULL) {
|
||||||
if (p32) {
|
error = copyin(uap->itv, &i32, sizeof(i32));
|
||||||
sg = stackgap_init();
|
|
||||||
p = stackgap_alloc(&sg, sizeof(struct itimerval));
|
|
||||||
uap->itv = (struct itimerval32 *)p;
|
|
||||||
error = copyin(p32, &s32, sizeof(s32));
|
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
TV_CP(s32, s, it_interval);
|
TV_CP(i32, itv, it_interval);
|
||||||
TV_CP(s32, s, it_value);
|
TV_CP(i32, itv, it_value);
|
||||||
error = copyout(&s, p, sizeof(s));
|
itvp = &itv;
|
||||||
if (error)
|
} else
|
||||||
return (error);
|
itvp = NULL;
|
||||||
}
|
error = kern_setitimer(td, uap->which, itvp, &oitv);
|
||||||
op32 = uap->oitv;
|
if (error || uap->oitv == NULL)
|
||||||
if (op32) {
|
|
||||||
sg = stackgap_init();
|
|
||||||
op = stackgap_alloc(&sg, sizeof(struct itimerval));
|
|
||||||
uap->oitv = (struct itimerval32 *)op;
|
|
||||||
}
|
|
||||||
error = setitimer(td, (struct setitimer_args *) uap);
|
|
||||||
if (error)
|
|
||||||
return (error);
|
return (error);
|
||||||
if (op32) {
|
TV_CP(oitv, i32, it_interval);
|
||||||
error = copyin(op, &s, sizeof(s));
|
TV_CP(oitv, i32, it_value);
|
||||||
if (error)
|
return (copyout(&i32, uap->oitv, sizeof(i32)));
|
||||||
return (error);
|
|
||||||
TV_CP(s, s32, it_interval);
|
|
||||||
TV_CP(s, s32, it_value);
|
|
||||||
error = copyout(&s32, op32, sizeof(s32));
|
|
||||||
}
|
|
||||||
return (error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
freebsd32_getitimer(struct thread *td, struct freebsd32_getitimer_args *uap)
|
freebsd32_getitimer(struct thread *td, struct freebsd32_getitimer_args *uap)
|
||||||
{
|
{
|
||||||
|
struct itimerval itv;
|
||||||
|
struct itimerval32 i32;
|
||||||
int error;
|
int error;
|
||||||
caddr_t sg;
|
|
||||||
struct itimerval32 *p32, s32;
|
|
||||||
struct itimerval *p = NULL, s;
|
|
||||||
|
|
||||||
p32 = uap->itv;
|
error = kern_getitimer(td, uap->which, &itv);
|
||||||
if (p32) {
|
if (error || uap->itv == NULL)
|
||||||
sg = stackgap_init();
|
|
||||||
p = stackgap_alloc(&sg, sizeof(struct itimerval));
|
|
||||||
uap->itv = (struct itimerval32 *)p;
|
|
||||||
}
|
|
||||||
error = getitimer(td, (struct getitimer_args *) uap);
|
|
||||||
if (error)
|
|
||||||
return (error);
|
return (error);
|
||||||
if (p32) {
|
TV_CP(itv, i32, it_interval);
|
||||||
error = copyin(p, &s, sizeof(s));
|
TV_CP(itv, i32, it_value);
|
||||||
if (error)
|
return (copyout(&i32, uap->itv, sizeof(i32)));
|
||||||
return (error);
|
|
||||||
TV_CP(s, s32, it_interval);
|
|
||||||
TV_CP(s, s32, it_value);
|
|
||||||
error = copyout(&s32, p32, sizeof(s32));
|
|
||||||
}
|
|
||||||
return (error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
freebsd32_select(struct thread *td, struct freebsd32_select_args *uap)
|
freebsd32_select(struct thread *td, struct freebsd32_select_args *uap)
|
||||||
{
|
{
|
||||||
|
struct timeval32 tv32;
|
||||||
|
struct timeval tv, *tvp;
|
||||||
int error;
|
int error;
|
||||||
caddr_t sg;
|
|
||||||
struct timeval32 *p32, s32;
|
|
||||||
struct timeval *p = NULL, s;
|
|
||||||
|
|
||||||
p32 = uap->tv;
|
if (uap->tv != NULL) {
|
||||||
if (p32) {
|
error = copyin(uap->tv, &tv32, sizeof(tv32));
|
||||||
sg = stackgap_init();
|
|
||||||
p = stackgap_alloc(&sg, sizeof(struct timeval));
|
|
||||||
uap->tv = (struct timeval32 *)p;
|
|
||||||
error = copyin(p32, &s32, sizeof(s32));
|
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
CP(s32, s, tv_sec);
|
CP(tv32, tv, tv_sec);
|
||||||
CP(s32, s, tv_usec);
|
CP(tv32, tv, tv_usec);
|
||||||
error = copyout(&s, p, sizeof(s));
|
tvp = &tv;
|
||||||
if (error)
|
} else
|
||||||
return (error);
|
tvp = NULL;
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* XXX big-endian needs to convert the fd_sets too.
|
* XXX big-endian needs to convert the fd_sets too.
|
||||||
|
* XXX Do pointers need PTRIN()?
|
||||||
*/
|
*/
|
||||||
return (select(td, (struct select_args *) uap));
|
return (kern_select(td, uap->nd, uap->in, uap->ou, uap->ex, tvp));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct kevent32 {
|
struct kevent32 {
|
||||||
@ -799,28 +809,22 @@ freebsd32_settimeofday(struct thread *td,
|
|||||||
int
|
int
|
||||||
freebsd32_utimes(struct thread *td, struct freebsd32_utimes_args *uap)
|
freebsd32_utimes(struct thread *td, struct freebsd32_utimes_args *uap)
|
||||||
{
|
{
|
||||||
|
struct timeval32 s32[2];
|
||||||
|
struct timeval s[2], *sp;
|
||||||
int error;
|
int error;
|
||||||
caddr_t sg;
|
|
||||||
struct timeval32 *p32, s32[2];
|
|
||||||
struct timeval *p = NULL, s[2];
|
|
||||||
|
|
||||||
p32 = uap->tptr;
|
if (uap->tptr != NULL) {
|
||||||
if (p32) {
|
error = copyin(uap->tptr, s32, sizeof(s32));
|
||||||
sg = stackgap_init();
|
|
||||||
p = stackgap_alloc(&sg, 2*sizeof(struct timeval));
|
|
||||||
uap->tptr = (struct timeval32 *)p;
|
|
||||||
error = copyin(p32, s32, sizeof(s32));
|
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
CP(s32[0], s[0], tv_sec);
|
CP(s32[0], s[0], tv_sec);
|
||||||
CP(s32[0], s[0], tv_usec);
|
CP(s32[0], s[0], tv_usec);
|
||||||
CP(s32[1], s[1], tv_sec);
|
CP(s32[1], s[1], tv_sec);
|
||||||
CP(s32[1], s[1], tv_usec);
|
CP(s32[1], s[1], tv_usec);
|
||||||
error = copyout(s, p, sizeof(s));
|
sp = s;
|
||||||
if (error)
|
} else
|
||||||
return (error);
|
sp = NULL;
|
||||||
}
|
return (kern_utimes(td, uap->path, UIO_USERSPACE, sp, UIO_SYSSPACE));
|
||||||
return (utimes(td, (struct utimes_args *) uap));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -851,7 +855,7 @@ freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap)
|
|||||||
op = stackgap_alloc(&sg, sizeof(struct timeval));
|
op = stackgap_alloc(&sg, sizeof(struct timeval));
|
||||||
uap->olddelta = (struct timeval32 *)op;
|
uap->olddelta = (struct timeval32 *)op;
|
||||||
}
|
}
|
||||||
error = utimes(td, (struct utimes_args *) uap);
|
error = adjtime(td, (struct adjtime_args *) uap);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
if (op32) {
|
if (op32) {
|
||||||
@ -869,28 +873,15 @@ freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap)
|
|||||||
int
|
int
|
||||||
freebsd4_freebsd32_statfs(struct thread *td, struct freebsd4_freebsd32_statfs_args *uap)
|
freebsd4_freebsd32_statfs(struct thread *td, struct freebsd4_freebsd32_statfs_args *uap)
|
||||||
{
|
{
|
||||||
|
struct statfs32 s32;
|
||||||
|
struct statfs s;
|
||||||
int error;
|
int error;
|
||||||
caddr_t sg;
|
|
||||||
struct statfs32 *p32, s32;
|
|
||||||
struct statfs *p = NULL, s;
|
|
||||||
|
|
||||||
p32 = uap->buf;
|
error = kern_statfs(td, uap->path, UIO_USERSPACE, &s);
|
||||||
if (p32) {
|
|
||||||
sg = stackgap_init();
|
|
||||||
p = stackgap_alloc(&sg, sizeof(struct statfs));
|
|
||||||
uap->buf = (struct statfs32 *)p;
|
|
||||||
}
|
|
||||||
error = statfs(td, (struct statfs_args *) uap);
|
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
if (p32) {
|
copy_statfs(&s, &s32);
|
||||||
error = copyin(p, &s, sizeof(s));
|
return (copyout(&s32, uap->buf, sizeof(s32)));
|
||||||
if (error)
|
|
||||||
return (error);
|
|
||||||
copy_statfs(&s, &s32);
|
|
||||||
error = copyout(&s32, p32, sizeof(s32));
|
|
||||||
}
|
|
||||||
return (error);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -898,28 +889,15 @@ freebsd4_freebsd32_statfs(struct thread *td, struct freebsd4_freebsd32_statfs_ar
|
|||||||
int
|
int
|
||||||
freebsd4_freebsd32_fstatfs(struct thread *td, struct freebsd4_freebsd32_fstatfs_args *uap)
|
freebsd4_freebsd32_fstatfs(struct thread *td, struct freebsd4_freebsd32_fstatfs_args *uap)
|
||||||
{
|
{
|
||||||
|
struct statfs32 s32;
|
||||||
|
struct statfs s;
|
||||||
int error;
|
int error;
|
||||||
caddr_t sg;
|
|
||||||
struct statfs32 *p32, s32;
|
|
||||||
struct statfs *p = NULL, s;
|
|
||||||
|
|
||||||
p32 = uap->buf;
|
error = kern_fstatfs(td, uap->fd, &s);
|
||||||
if (p32) {
|
|
||||||
sg = stackgap_init();
|
|
||||||
p = stackgap_alloc(&sg, sizeof(struct statfs));
|
|
||||||
uap->buf = (struct statfs32 *)p;
|
|
||||||
}
|
|
||||||
error = fstatfs(td, (struct fstatfs_args *) uap);
|
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
if (p32) {
|
copy_statfs(&s, &s32);
|
||||||
error = copyin(p, &s, sizeof(s));
|
return (copyout(&s32, uap->buf, sizeof(s32)));
|
||||||
if (error)
|
|
||||||
return (error);
|
|
||||||
copy_statfs(&s, &s32);
|
|
||||||
error = copyout(&s32, p32, sizeof(s32));
|
|
||||||
}
|
|
||||||
return (error);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -927,28 +905,18 @@ freebsd4_freebsd32_fstatfs(struct thread *td, struct freebsd4_freebsd32_fstatfs_
|
|||||||
int
|
int
|
||||||
freebsd4_freebsd32_fhstatfs(struct thread *td, struct freebsd4_freebsd32_fhstatfs_args *uap)
|
freebsd4_freebsd32_fhstatfs(struct thread *td, struct freebsd4_freebsd32_fhstatfs_args *uap)
|
||||||
{
|
{
|
||||||
|
struct statfs32 s32;
|
||||||
|
struct statfs s;
|
||||||
|
fhandle_t fh;
|
||||||
int error;
|
int error;
|
||||||
caddr_t sg;
|
|
||||||
struct statfs32 *p32, s32;
|
|
||||||
struct statfs *p = NULL, s;
|
|
||||||
|
|
||||||
p32 = uap->buf;
|
if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0)
|
||||||
if (p32) {
|
return (error);
|
||||||
sg = stackgap_init();
|
error = kern_fhstatfs(td, fh, &s);
|
||||||
p = stackgap_alloc(&sg, sizeof(struct statfs));
|
|
||||||
uap->buf = (struct statfs32 *)p;
|
|
||||||
}
|
|
||||||
error = fhstatfs(td, (struct fhstatfs_args *) uap);
|
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
if (p32) {
|
copy_statfs(&s, &s32);
|
||||||
error = copyin(p, &s, sizeof(s));
|
return (copyout(&s32, uap->buf, sizeof(s32)));
|
||||||
if (error)
|
|
||||||
return (error);
|
|
||||||
copy_statfs(&s, &s32);
|
|
||||||
error = copyout(&s32, p32, sizeof(s32));
|
|
||||||
}
|
|
||||||
return (error);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1124,20 +1092,8 @@ freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap)
|
|||||||
struct stat sb;
|
struct stat sb;
|
||||||
struct stat32 sb32;
|
struct stat32 sb32;
|
||||||
int error;
|
int error;
|
||||||
struct nameidata nd;
|
|
||||||
|
|
||||||
#ifdef LOOKUP_SHARED
|
error = kern_stat(td, uap->path, UIO_USERSPACE, &sb);
|
||||||
NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ,
|
|
||||||
UIO_USERSPACE, uap->path, td);
|
|
||||||
#else
|
|
||||||
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
|
|
||||||
uap->path, td);
|
|
||||||
#endif
|
|
||||||
if ((error = namei(&nd)) != 0)
|
|
||||||
return (error);
|
|
||||||
error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
|
|
||||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
|
||||||
vput(nd.ni_vp);
|
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
copy_stat(&sb, &sb32);
|
copy_stat(&sb, &sb32);
|
||||||
@ -1148,17 +1104,11 @@ freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap)
|
|||||||
int
|
int
|
||||||
freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap)
|
freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap)
|
||||||
{
|
{
|
||||||
struct file *fp;
|
|
||||||
struct stat ub;
|
struct stat ub;
|
||||||
struct stat32 ub32;
|
struct stat32 ub32;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if ((error = fget(td, uap->fd, &fp)) != 0)
|
error = kern_fstat(td, uap->fd, &ub);
|
||||||
return (error);
|
|
||||||
mtx_lock(&Giant);
|
|
||||||
error = fo_stat(fp, &ub, td->td_ucred, td);
|
|
||||||
mtx_unlock(&Giant);
|
|
||||||
fdrop(fp, td);
|
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
copy_stat(&ub, &ub32);
|
copy_stat(&ub, &ub32);
|
||||||
@ -1169,20 +1119,11 @@ freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap)
|
|||||||
int
|
int
|
||||||
freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap)
|
freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap)
|
||||||
{
|
{
|
||||||
int error;
|
|
||||||
struct vnode *vp;
|
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
struct stat32 sb32;
|
struct stat32 sb32;
|
||||||
struct nameidata nd;
|
int error;
|
||||||
|
|
||||||
NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
|
error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb);
|
||||||
uap->path, td);
|
|
||||||
if ((error = namei(&nd)) != 0)
|
|
||||||
return (error);
|
|
||||||
vp = nd.ni_vp;
|
|
||||||
error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
|
|
||||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
|
||||||
vput(vp);
|
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
copy_stat(&sb, &sb32);
|
copy_stat(&sb, &sb32);
|
||||||
|
Loading…
Reference in New Issue
Block a user