Changeset View
Changeset View
Standalone View
Standalone View
sys/compat/linux/linux_file.c
Show First 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | static struct bsd_to_linux_bitmap mfd_bitmap[] = { | ||||
MFD_HUGETLB_ENTRY(16GB), | MFD_HUGETLB_ENTRY(16GB), | ||||
}; | }; | ||||
#undef MFD_HUGETLB_ENTRY | #undef MFD_HUGETLB_ENTRY | ||||
#ifdef LINUX_LEGACY_SYSCALLS | #ifdef LINUX_LEGACY_SYSCALLS | ||||
int | int | ||||
linux_creat(struct thread *td, struct linux_creat_args *args) | linux_creat(struct thread *td, struct linux_creat_args *args) | ||||
{ | { | ||||
char *path; | |||||
int error; | |||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_openat(td, AT_FDCWD, args->path, UIO_USERSPACE, | return (kern_openat(td, AT_FDCWD, args->path, UIO_USERSPACE, | ||||
O_WRONLY | O_CREAT | O_TRUNC, args->mode)); | O_WRONLY | O_CREAT | O_TRUNC, args->mode)); | ||||
} | } | ||||
LCONVPATHEXIST(args->path, &path); | |||||
error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE, | |||||
O_WRONLY | O_CREAT | O_TRUNC, args->mode); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
#endif | #endif | ||||
static int | static int | ||||
linux_common_openflags(int l_flags) | linux_common_openflags(int l_flags) | ||||
{ | { | ||||
int bsd_flags; | int bsd_flags; | ||||
bsd_flags = 0; | bsd_flags = 0; | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | |||||
done: | done: | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
linux_openat(struct thread *td, struct linux_openat_args *args) | linux_openat(struct thread *td, struct linux_openat_args *args) | ||||
{ | { | ||||
char *path; | int dfd; | ||||
int dfd, error; | |||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; | dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; | ||||
if (!LUSECONVPATH(td)) { | |||||
return (linux_common_open(td, dfd, args->filename, args->flags, | return (linux_common_open(td, dfd, args->filename, args->flags, | ||||
args->mode, UIO_USERSPACE)); | args->mode, UIO_USERSPACE)); | ||||
} | } | ||||
if (args->flags & LINUX_O_CREAT) | |||||
LCONVPATH_AT(args->filename, &path, 1, dfd); | |||||
else | |||||
LCONVPATH_AT(args->filename, &path, 0, dfd); | |||||
error = linux_common_open(td, dfd, path, args->flags, args->mode, | |||||
UIO_SYSSPACE); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
#ifdef LINUX_LEGACY_SYSCALLS | #ifdef LINUX_LEGACY_SYSCALLS | ||||
int | int | ||||
linux_open(struct thread *td, struct linux_open_args *args) | linux_open(struct thread *td, struct linux_open_args *args) | ||||
{ | { | ||||
char *path; | |||||
int error; | |||||
if (!LUSECONVPATH(td)) { | |||||
return (linux_common_open(td, AT_FDCWD, args->path, args->flags, | return (linux_common_open(td, AT_FDCWD, args->path, args->flags, | ||||
args->mode, UIO_USERSPACE)); | args->mode, UIO_USERSPACE)); | ||||
} | } | ||||
if (args->flags & LINUX_O_CREAT) | |||||
LCONVPATHCREAT(args->path, &path); | |||||
else | |||||
LCONVPATHEXIST(args->path, &path); | |||||
error = linux_common_open(td, AT_FDCWD, path, args->flags, args->mode, | |||||
UIO_SYSSPACE); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
#endif | #endif | ||||
int | int | ||||
linux_name_to_handle_at(struct thread *td, | linux_name_to_handle_at(struct thread *td, | ||||
struct linux_name_to_handle_at_args *args) | struct linux_name_to_handle_at_args *args) | ||||
{ | { | ||||
static const l_int valid_flags = (LINUX_AT_SYMLINK_FOLLOW | | static const l_int valid_flags = (LINUX_AT_SYMLINK_FOLLOW | | ||||
LINUX_AT_EMPTY_PATH); | LINUX_AT_EMPTY_PATH); | ||||
Show All 12 Lines | if (fd == LINUX_AT_FDCWD) | ||||
fd = AT_FDCWD; | fd = AT_FDCWD; | ||||
bsd_flags = 0; | bsd_flags = 0; | ||||
if (!(args->flags & LINUX_AT_SYMLINK_FOLLOW)) | if (!(args->flags & LINUX_AT_SYMLINK_FOLLOW)) | ||||
bsd_flags |= AT_SYMLINK_NOFOLLOW; | bsd_flags |= AT_SYMLINK_NOFOLLOW; | ||||
if ((args->flags & LINUX_AT_EMPTY_PATH) != 0) | if ((args->flags & LINUX_AT_EMPTY_PATH) != 0) | ||||
bsd_flags |= AT_EMPTY_PATH; | bsd_flags |= AT_EMPTY_PATH; | ||||
if (!LUSECONVPATH(td)) { | |||||
error = kern_getfhat(td, bsd_flags, fd, args->name, | error = kern_getfhat(td, bsd_flags, fd, args->name, | ||||
UIO_USERSPACE, &fh, UIO_SYSSPACE); | UIO_USERSPACE, &fh, UIO_SYSSPACE); | ||||
} else { | |||||
char *path; | |||||
LCONVPATH_AT(args->name, &path, 0, fd); | |||||
error = kern_getfhat(td, bsd_flags, fd, path, UIO_SYSSPACE, | |||||
&fh, UIO_SYSSPACE); | |||||
LFREEPATH(path); | |||||
} | |||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
/* Emit mount_id -- required before EOVERFLOW case. */ | /* Emit mount_id -- required before EOVERFLOW case. */ | ||||
mount_id = (fh.fh_fsid.val[0] ^ fh.fh_fsid.val[1]); | mount_id = (fh.fh_fsid.val[0] ^ fh.fh_fsid.val[1]); | ||||
error = copyout(&mount_id, args->mnt_id, sizeof(mount_id)); | error = copyout(&mount_id, args->mnt_id, sizeof(mount_id)); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
▲ Show 20 Lines • Show All 334 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* These exist mainly for hooks for doing /compat/linux translation. | * These exist mainly for hooks for doing /compat/linux translation. | ||||
*/ | */ | ||||
#ifdef LINUX_LEGACY_SYSCALLS | #ifdef LINUX_LEGACY_SYSCALLS | ||||
int | int | ||||
linux_access(struct thread *td, struct linux_access_args *args) | linux_access(struct thread *td, struct linux_access_args *args) | ||||
{ | { | ||||
char *path; | |||||
int error; | |||||
/* Linux convention. */ | /* Linux convention. */ | ||||
if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) | if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (!LUSECONVPATH(td)) { | return (kern_accessat(td, AT_FDCWD, args->path, UIO_USERSPACE, 0, | ||||
error = kern_accessat(td, AT_FDCWD, args->path, UIO_USERSPACE, 0, | args->amode)); | ||||
args->amode); | |||||
} else { | |||||
LCONVPATHEXIST(args->path, &path); | |||||
error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0, | |||||
args->amode); | |||||
LFREEPATH(path); | |||||
} | } | ||||
return (error); | |||||
} | |||||
#endif | #endif | ||||
static int | static int | ||||
linux_do_accessat(struct thread *td, int ldfd, const char *filename, | linux_do_accessat(struct thread *td, int ldfd, const char *filename, | ||||
int amode, int flags) | int amode, int flags) | ||||
{ | { | ||||
char *path; | int dfd; | ||||
int error, dfd; | |||||
/* Linux convention. */ | /* Linux convention. */ | ||||
if (amode & ~(F_OK | X_OK | W_OK | R_OK)) | if (amode & ~(F_OK | X_OK | W_OK | R_OK)) | ||||
return (EINVAL); | return (EINVAL); | ||||
dfd = (ldfd == LINUX_AT_FDCWD) ? AT_FDCWD : ldfd; | dfd = (ldfd == LINUX_AT_FDCWD) ? AT_FDCWD : ldfd; | ||||
if (!LUSECONVPATH(td)) { | return (kern_accessat(td, dfd, filename, UIO_USERSPACE, flags, amode)); | ||||
error = kern_accessat(td, dfd, filename, UIO_USERSPACE, flags, amode); | |||||
} else { | |||||
LCONVPATHEXIST_AT(filename, &path, dfd); | |||||
error = kern_accessat(td, dfd, path, UIO_SYSSPACE, flags, amode); | |||||
LFREEPATH(path); | |||||
} | } | ||||
return (error); | |||||
} | |||||
int | int | ||||
linux_faccessat(struct thread *td, struct linux_faccessat_args *args) | linux_faccessat(struct thread *td, struct linux_faccessat_args *args) | ||||
{ | { | ||||
return (linux_do_accessat(td, args->dfd, args->filename, args->amode, | return (linux_do_accessat(td, args->dfd, args->filename, args->amode, | ||||
0)); | 0)); | ||||
} | } | ||||
Show All 17 Lines | return (linux_do_accessat(td, args->dfd, args->filename, args->amode, | ||||
flags)); | flags)); | ||||
} | } | ||||
#ifdef LINUX_LEGACY_SYSCALLS | #ifdef LINUX_LEGACY_SYSCALLS | ||||
int | int | ||||
linux_unlink(struct thread *td, struct linux_unlink_args *args) | linux_unlink(struct thread *td, struct linux_unlink_args *args) | ||||
{ | { | ||||
char *path; | |||||
int error; | int error; | ||||
struct stat st; | struct stat st; | ||||
if (!LUSECONVPATH(td)) { | |||||
error = kern_funlinkat(td, AT_FDCWD, args->path, FD_NONE, | error = kern_funlinkat(td, AT_FDCWD, args->path, FD_NONE, | ||||
UIO_USERSPACE, 0, 0); | UIO_USERSPACE, 0, 0); | ||||
if (error == EPERM) { | if (error == EPERM) { | ||||
/* Introduce POSIX noncompliant behaviour of Linux */ | /* Introduce POSIX noncompliant behaviour of Linux */ | ||||
if (kern_statat(td, 0, AT_FDCWD, args->path, | if (kern_statat(td, 0, AT_FDCWD, args->path, | ||||
UIO_USERSPACE, &st, NULL) == 0) { | UIO_USERSPACE, &st, NULL) == 0) { | ||||
if (S_ISDIR(st.st_mode)) | if (S_ISDIR(st.st_mode)) | ||||
error = EISDIR; | error = EISDIR; | ||||
} | } | ||||
} | } | ||||
} else { | |||||
LCONVPATHEXIST(args->path, &path); | |||||
error = kern_funlinkat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0, 0); | |||||
if (error == EPERM) { | |||||
/* Introduce POSIX noncompliant behaviour of Linux */ | |||||
if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st, | |||||
NULL) == 0) { | |||||
if (S_ISDIR(st.st_mode)) | |||||
error = EISDIR; | |||||
} | |||||
} | |||||
LFREEPATH(path); | |||||
} | |||||
return (error); | return (error); | ||||
} | } | ||||
#endif | #endif | ||||
static int | static int | ||||
linux_unlinkat_impl(struct thread *td, enum uio_seg pathseg, const char *path, | linux_unlinkat_impl(struct thread *td, enum uio_seg pathseg, const char *path, | ||||
int dfd, struct linux_unlinkat_args *args) | int dfd, struct linux_unlinkat_args *args) | ||||
Show All 12 Lines | if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path, | ||||
error = EISDIR; | error = EISDIR; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) | linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) | ||||
{ | { | ||||
char *path; | int dfd; | ||||
int error, dfd; | |||||
if (args->flag & ~LINUX_AT_REMOVEDIR) | if (args->flag & ~LINUX_AT_REMOVEDIR) | ||||
return (EINVAL); | return (EINVAL); | ||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; | dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; | ||||
if (!LUSECONVPATH(td)) { | |||||
return (linux_unlinkat_impl(td, UIO_USERSPACE, args->pathname, | return (linux_unlinkat_impl(td, UIO_USERSPACE, args->pathname, | ||||
dfd, args)); | dfd, args)); | ||||
} | } | ||||
LCONVPATHEXIST_AT(args->pathname, &path, dfd); | |||||
error = linux_unlinkat_impl(td, UIO_SYSSPACE, path, dfd, args); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
int | int | ||||
linux_chdir(struct thread *td, struct linux_chdir_args *args) | linux_chdir(struct thread *td, struct linux_chdir_args *args) | ||||
{ | { | ||||
char *path; | |||||
int error; | |||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_chdir(td, args->path, UIO_USERSPACE)); | return (kern_chdir(td, args->path, UIO_USERSPACE)); | ||||
} | } | ||||
LCONVPATHEXIST(args->path, &path); | |||||
error = kern_chdir(td, path, UIO_SYSSPACE); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
#ifdef LINUX_LEGACY_SYSCALLS | #ifdef LINUX_LEGACY_SYSCALLS | ||||
int | int | ||||
linux_chmod(struct thread *td, struct linux_chmod_args *args) | linux_chmod(struct thread *td, struct linux_chmod_args *args) | ||||
{ | { | ||||
char *path; | |||||
int error; | |||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_fchmodat(td, AT_FDCWD, args->path, UIO_USERSPACE, | return (kern_fchmodat(td, AT_FDCWD, args->path, UIO_USERSPACE, | ||||
args->mode, 0)); | args->mode, 0)); | ||||
} | } | ||||
LCONVPATHEXIST(args->path, &path); | |||||
error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode, 0); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
#endif | #endif | ||||
int | int | ||||
linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args) | linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args) | ||||
{ | { | ||||
char *path; | int dfd; | ||||
int error, dfd; | |||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; | dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; | ||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_fchmodat(td, dfd, args->filename, UIO_USERSPACE, | return (kern_fchmodat(td, dfd, args->filename, UIO_USERSPACE, | ||||
args->mode, 0)); | args->mode, 0)); | ||||
} | } | ||||
LCONVPATHEXIST_AT(args->filename, &path, dfd); | |||||
error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
#ifdef LINUX_LEGACY_SYSCALLS | #ifdef LINUX_LEGACY_SYSCALLS | ||||
int | int | ||||
linux_mkdir(struct thread *td, struct linux_mkdir_args *args) | linux_mkdir(struct thread *td, struct linux_mkdir_args *args) | ||||
{ | { | ||||
char *path; | |||||
int error; | |||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_mkdirat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->mode)); | return (kern_mkdirat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->mode)); | ||||
} | } | ||||
LCONVPATHCREAT(args->path, &path); | |||||
error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
#endif | #endif | ||||
int | int | ||||
linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args) | linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args) | ||||
{ | { | ||||
char *path; | int dfd; | ||||
int error, dfd; | |||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; | dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; | ||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_mkdirat(td, dfd, args->pathname, UIO_USERSPACE, args->mode)); | return (kern_mkdirat(td, dfd, args->pathname, UIO_USERSPACE, args->mode)); | ||||
} | } | ||||
LCONVPATHCREAT_AT(args->pathname, &path, dfd); | |||||
error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
#ifdef LINUX_LEGACY_SYSCALLS | #ifdef LINUX_LEGACY_SYSCALLS | ||||
int | int | ||||
linux_rmdir(struct thread *td, struct linux_rmdir_args *args) | linux_rmdir(struct thread *td, struct linux_rmdir_args *args) | ||||
{ | { | ||||
char *path; | |||||
int error; | |||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_frmdirat(td, AT_FDCWD, args->path, FD_NONE, | return (kern_frmdirat(td, AT_FDCWD, args->path, FD_NONE, | ||||
UIO_USERSPACE, 0)); | UIO_USERSPACE, 0)); | ||||
} | } | ||||
LCONVPATHEXIST(args->path, &path); | |||||
error = kern_frmdirat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
int | int | ||||
linux_rename(struct thread *td, struct linux_rename_args *args) | linux_rename(struct thread *td, struct linux_rename_args *args) | ||||
{ | { | ||||
char *from, *to; | |||||
int error; | |||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_renameat(td, AT_FDCWD, args->from, AT_FDCWD, | return (kern_renameat(td, AT_FDCWD, args->from, AT_FDCWD, | ||||
args->to, UIO_USERSPACE)); | args->to, UIO_USERSPACE)); | ||||
} | } | ||||
LCONVPATHEXIST(args->from, &from); | |||||
/* Expand LCONVPATHCREATE so that `from' can be freed on errors */ | |||||
error = linux_emul_convpath(args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); | |||||
if (to == NULL) { | |||||
LFREEPATH(from); | |||||
return (error); | |||||
} | |||||
error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE); | |||||
LFREEPATH(from); | |||||
LFREEPATH(to); | |||||
return (error); | |||||
} | |||||
#endif | #endif | ||||
int | int | ||||
linux_renameat(struct thread *td, struct linux_renameat_args *args) | linux_renameat(struct thread *td, struct linux_renameat_args *args) | ||||
{ | { | ||||
struct linux_renameat2_args renameat2_args = { | struct linux_renameat2_args renameat2_args = { | ||||
.olddfd = args->olddfd, | .olddfd = args->olddfd, | ||||
.oldname = args->oldname, | .oldname = args->oldname, | ||||
.newdfd = args->newdfd, | .newdfd = args->newdfd, | ||||
.newname = args->newname, | .newname = args->newname, | ||||
.flags = 0 | .flags = 0 | ||||
}; | }; | ||||
return (linux_renameat2(td, &renameat2_args)); | return (linux_renameat2(td, &renameat2_args)); | ||||
} | } | ||||
int | int | ||||
linux_renameat2(struct thread *td, struct linux_renameat2_args *args) | linux_renameat2(struct thread *td, struct linux_renameat2_args *args) | ||||
{ | { | ||||
char *from, *to; | int olddfd, newdfd; | ||||
int error, olddfd, newdfd; | |||||
if (args->flags != 0) { | if (args->flags != 0) { | ||||
if (args->flags & ~(LINUX_RENAME_EXCHANGE | | if (args->flags & ~(LINUX_RENAME_EXCHANGE | | ||||
LINUX_RENAME_NOREPLACE | LINUX_RENAME_WHITEOUT)) | LINUX_RENAME_NOREPLACE | LINUX_RENAME_WHITEOUT)) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (args->flags & LINUX_RENAME_EXCHANGE && | if (args->flags & LINUX_RENAME_EXCHANGE && | ||||
args->flags & (LINUX_RENAME_NOREPLACE | | args->flags & (LINUX_RENAME_NOREPLACE | | ||||
LINUX_RENAME_WHITEOUT)) | LINUX_RENAME_WHITEOUT)) | ||||
return (EINVAL); | return (EINVAL); | ||||
#if 0 | #if 0 | ||||
/* | /* | ||||
* This spams the console on Ubuntu Focal. | * This spams the console on Ubuntu Focal. | ||||
* | * | ||||
* What's needed here is a general mechanism to let users know | * What's needed here is a general mechanism to let users know | ||||
* about missing features without hogging the system. | * about missing features without hogging the system. | ||||
*/ | */ | ||||
linux_msg(td, "renameat2 unsupported flags 0x%x", | linux_msg(td, "renameat2 unsupported flags 0x%x", | ||||
args->flags); | args->flags); | ||||
#endif | #endif | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; | olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; | ||||
newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; | newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; | ||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_renameat(td, olddfd, args->oldname, newdfd, | return (kern_renameat(td, olddfd, args->oldname, newdfd, | ||||
args->newname, UIO_USERSPACE)); | args->newname, UIO_USERSPACE)); | ||||
} | } | ||||
LCONVPATHEXIST_AT(args->oldname, &from, olddfd); | |||||
/* Expand LCONVPATHCREATE so that `from' can be freed on errors */ | |||||
error = linux_emul_convpath(args->newname, UIO_USERSPACE, &to, 1, newdfd); | |||||
if (to == NULL) { | |||||
LFREEPATH(from); | |||||
return (error); | |||||
} | |||||
error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE); | |||||
LFREEPATH(from); | |||||
LFREEPATH(to); | |||||
return (error); | |||||
} | |||||
#ifdef LINUX_LEGACY_SYSCALLS | #ifdef LINUX_LEGACY_SYSCALLS | ||||
int | int | ||||
linux_symlink(struct thread *td, struct linux_symlink_args *args) | linux_symlink(struct thread *td, struct linux_symlink_args *args) | ||||
{ | { | ||||
char *path, *to; | |||||
int error; | |||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_symlinkat(td, args->path, AT_FDCWD, args->to, | return (kern_symlinkat(td, args->path, AT_FDCWD, args->to, | ||||
UIO_USERSPACE)); | UIO_USERSPACE)); | ||||
} | } | ||||
LCONVPATHEXIST(args->path, &path); | |||||
/* Expand LCONVPATHCREATE so that `path' can be freed on errors */ | |||||
error = linux_emul_convpath(args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); | |||||
if (to == NULL) { | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE); | |||||
LFREEPATH(path); | |||||
LFREEPATH(to); | |||||
return (error); | |||||
} | |||||
#endif | #endif | ||||
int | int | ||||
linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) | linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) | ||||
{ | { | ||||
char *path, *to; | int dfd; | ||||
int error, dfd; | |||||
dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; | dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; | ||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_symlinkat(td, args->oldname, dfd, args->newname, | return (kern_symlinkat(td, args->oldname, dfd, args->newname, | ||||
UIO_USERSPACE)); | UIO_USERSPACE)); | ||||
} | } | ||||
LCONVPATHEXIST(args->oldname, &path); | |||||
/* Expand LCONVPATHCREATE so that `path' can be freed on errors */ | |||||
error = linux_emul_convpath(args->newname, UIO_USERSPACE, &to, 1, dfd); | |||||
if (to == NULL) { | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE); | |||||
LFREEPATH(path); | |||||
LFREEPATH(to); | |||||
return (error); | |||||
} | |||||
#ifdef LINUX_LEGACY_SYSCALLS | #ifdef LINUX_LEGACY_SYSCALLS | ||||
int | int | ||||
linux_readlink(struct thread *td, struct linux_readlink_args *args) | linux_readlink(struct thread *td, struct linux_readlink_args *args) | ||||
{ | { | ||||
char *name; | |||||
int error; | |||||
if (args->count <= 0) | if (args->count <= 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_readlinkat(td, AT_FDCWD, args->name, UIO_USERSPACE, | return (kern_readlinkat(td, AT_FDCWD, args->name, UIO_USERSPACE, | ||||
args->buf, UIO_USERSPACE, args->count)); | args->buf, UIO_USERSPACE, args->count)); | ||||
} | } | ||||
LCONVPATHEXIST(args->name, &name); | |||||
error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE, | |||||
args->buf, UIO_USERSPACE, args->count); | |||||
LFREEPATH(name); | |||||
return (error); | |||||
} | |||||
#endif | #endif | ||||
int | int | ||||
linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args) | linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args) | ||||
{ | { | ||||
char *name; | int dfd; | ||||
int error, dfd; | |||||
if (args->bufsiz <= 0) | if (args->bufsiz <= 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; | dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; | ||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_readlinkat(td, dfd, args->path, UIO_USERSPACE, | return (kern_readlinkat(td, dfd, args->path, UIO_USERSPACE, | ||||
args->buf, UIO_USERSPACE, args->bufsiz)); | args->buf, UIO_USERSPACE, args->bufsiz)); | ||||
} | } | ||||
LCONVPATHEXIST_AT(args->path, &name, dfd); | |||||
error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf, | |||||
UIO_USERSPACE, args->bufsiz); | |||||
LFREEPATH(name); | |||||
return (error); | |||||
} | |||||
int | int | ||||
linux_truncate(struct thread *td, struct linux_truncate_args *args) | linux_truncate(struct thread *td, struct linux_truncate_args *args) | ||||
{ | { | ||||
char *path; | |||||
int error; | |||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_truncate(td, args->path, UIO_USERSPACE, args->length)); | return (kern_truncate(td, args->path, UIO_USERSPACE, args->length)); | ||||
} | } | ||||
LCONVPATHEXIST(args->path, &path); | |||||
error = kern_truncate(td, path, UIO_SYSSPACE, args->length); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) | #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) | ||||
int | int | ||||
linux_truncate64(struct thread *td, struct linux_truncate64_args *args) | linux_truncate64(struct thread *td, struct linux_truncate64_args *args) | ||||
{ | { | ||||
char *path; | |||||
off_t length; | off_t length; | ||||
int error; | |||||
#if defined(__amd64__) && defined(COMPAT_LINUX32) | #if defined(__amd64__) && defined(COMPAT_LINUX32) | ||||
length = PAIR32TO64(off_t, args->length); | length = PAIR32TO64(off_t, args->length); | ||||
#else | #else | ||||
length = args->length; | length = args->length; | ||||
#endif | #endif | ||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_truncate(td, args->path, UIO_USERSPACE, length)); | return (kern_truncate(td, args->path, UIO_USERSPACE, length)); | ||||
} | } | ||||
LCONVPATHEXIST(args->path, &path); | |||||
error = kern_truncate(td, path, UIO_SYSSPACE, length); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ | #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ | ||||
int | int | ||||
linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) | linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) | ||||
{ | { | ||||
return (kern_ftruncate(td, args->fd, args->length)); | return (kern_ftruncate(td, args->fd, args->length)); | ||||
} | } | ||||
Show All 13 Lines | #endif | ||||
return (kern_ftruncate(td, args->fd, length)); | return (kern_ftruncate(td, args->fd, length)); | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef LINUX_LEGACY_SYSCALLS | #ifdef LINUX_LEGACY_SYSCALLS | ||||
int | int | ||||
linux_link(struct thread *td, struct linux_link_args *args) | linux_link(struct thread *td, struct linux_link_args *args) | ||||
{ | { | ||||
char *path, *to; | |||||
int error; | |||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_linkat(td, AT_FDCWD, AT_FDCWD, args->path, args->to, | return (kern_linkat(td, AT_FDCWD, AT_FDCWD, args->path, args->to, | ||||
UIO_USERSPACE, AT_SYMLINK_FOLLOW)); | UIO_USERSPACE, AT_SYMLINK_FOLLOW)); | ||||
} | } | ||||
LCONVPATHEXIST(args->path, &path); | |||||
/* Expand LCONVPATHCREATE so that `path' can be freed on errors */ | |||||
error = linux_emul_convpath(args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); | |||||
if (to == NULL) { | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE, | |||||
AT_SYMLINK_FOLLOW); | |||||
LFREEPATH(path); | |||||
LFREEPATH(to); | |||||
return (error); | |||||
} | |||||
#endif | #endif | ||||
int | int | ||||
linux_linkat(struct thread *td, struct linux_linkat_args *args) | linux_linkat(struct thread *td, struct linux_linkat_args *args) | ||||
{ | { | ||||
char *path, *to; | int olddfd, newdfd, flag; | ||||
int error, olddfd, newdfd, flag; | |||||
if (args->flag & ~(LINUX_AT_SYMLINK_FOLLOW | LINUX_AT_EMPTY_PATH)) | if (args->flag & ~(LINUX_AT_SYMLINK_FOLLOW | LINUX_AT_EMPTY_PATH)) | ||||
return (EINVAL); | return (EINVAL); | ||||
flag = (args->flag & LINUX_AT_SYMLINK_FOLLOW) != 0 ? AT_SYMLINK_FOLLOW : | flag = (args->flag & LINUX_AT_SYMLINK_FOLLOW) != 0 ? AT_SYMLINK_FOLLOW : | ||||
0; | 0; | ||||
flag |= (args->flag & LINUX_AT_EMPTY_PATH) != 0 ? AT_EMPTY_PATH : 0; | flag |= (args->flag & LINUX_AT_EMPTY_PATH) != 0 ? AT_EMPTY_PATH : 0; | ||||
olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; | olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; | ||||
newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; | newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; | ||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_linkat(td, olddfd, newdfd, args->oldname, | return (kern_linkat(td, olddfd, newdfd, args->oldname, | ||||
args->newname, UIO_USERSPACE, flag)); | args->newname, UIO_USERSPACE, flag)); | ||||
} | } | ||||
LCONVPATHEXIST_AT(args->oldname, &path, olddfd); | |||||
/* Expand LCONVPATHCREATE so that `path' can be freed on errors */ | |||||
error = linux_emul_convpath(args->newname, UIO_USERSPACE, &to, 1, newdfd); | |||||
if (to == NULL) { | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, flag); | |||||
LFREEPATH(path); | |||||
LFREEPATH(to); | |||||
return (error); | |||||
} | |||||
int | int | ||||
linux_fdatasync(struct thread *td, struct linux_fdatasync_args *uap) | linux_fdatasync(struct thread *td, struct linux_fdatasync_args *uap) | ||||
{ | { | ||||
return (kern_fsync(td, uap->fd, false)); | return (kern_fsync(td, uap->fd, false)); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 568 Lines • ▼ Show 20 Lines | linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) | ||||
return (fcntl_common(td, &fcntl_args)); | return (fcntl_common(td, &fcntl_args)); | ||||
} | } | ||||
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ | #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ | ||||
#ifdef LINUX_LEGACY_SYSCALLS | #ifdef LINUX_LEGACY_SYSCALLS | ||||
int | int | ||||
linux_chown(struct thread *td, struct linux_chown_args *args) | linux_chown(struct thread *td, struct linux_chown_args *args) | ||||
{ | { | ||||
char *path; | |||||
int error; | |||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, | return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, | ||||
args->uid, args->gid, 0)); | args->uid, args->gid, 0)); | ||||
} | } | ||||
LCONVPATHEXIST(args->path, &path); | |||||
error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, | |||||
args->gid, 0); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
#endif | #endif | ||||
int | int | ||||
linux_fchownat(struct thread *td, struct linux_fchownat_args *args) | linux_fchownat(struct thread *td, struct linux_fchownat_args *args) | ||||
{ | { | ||||
char *path; | int dfd, flag, unsupported; | ||||
int error, dfd, flag, unsupported; | |||||
unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH); | unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH); | ||||
if (unsupported != 0) { | if (unsupported != 0) { | ||||
linux_msg(td, "fchownat unsupported flag 0x%x", unsupported); | linux_msg(td, "fchownat unsupported flag 0x%x", unsupported); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : | flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : | ||||
AT_SYMLINK_NOFOLLOW; | AT_SYMLINK_NOFOLLOW; | ||||
flag |= (args->flag & LINUX_AT_EMPTY_PATH) == 0 ? 0 : | flag |= (args->flag & LINUX_AT_EMPTY_PATH) == 0 ? 0 : | ||||
AT_EMPTY_PATH; | AT_EMPTY_PATH; | ||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; | dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; | ||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_fchownat(td, dfd, args->filename, UIO_USERSPACE, | return (kern_fchownat(td, dfd, args->filename, UIO_USERSPACE, | ||||
args->uid, args->gid, flag)); | args->uid, args->gid, flag)); | ||||
} | } | ||||
LCONVPATHEXIST_AT(args->filename, &path, dfd); | |||||
error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid, | |||||
flag); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | |||||
#ifdef LINUX_LEGACY_SYSCALLS | #ifdef LINUX_LEGACY_SYSCALLS | ||||
int | int | ||||
linux_lchown(struct thread *td, struct linux_lchown_args *args) | linux_lchown(struct thread *td, struct linux_lchown_args *args) | ||||
{ | { | ||||
char *path; | |||||
int error; | |||||
if (!LUSECONVPATH(td)) { | |||||
return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->uid, | return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->uid, | ||||
args->gid, AT_SYMLINK_NOFOLLOW)); | args->gid, AT_SYMLINK_NOFOLLOW)); | ||||
} | |||||
LCONVPATHEXIST(args->path, &path); | |||||
error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, args->gid, | |||||
AT_SYMLINK_NOFOLLOW); | |||||
LFREEPATH(path); | |||||
return (error); | |||||
} | } | ||||
#endif | #endif | ||||
static int | static int | ||||
convert_fadvice(int advice) | convert_fadvice(int advice) | ||||
{ | { | ||||
switch (advice) { | switch (advice) { | ||||
case LINUX_POSIX_FADV_NORMAL: | case LINUX_POSIX_FADV_NORMAL: | ||||
▲ Show 20 Lines • Show All 269 Lines • Show Last 20 Lines |