return -1;
}
+static int skel_fcntl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, int cmd, va_list cmd_arg)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
static int skel_linux_setlease(struct vfs_handle_struct *handle,
struct files_struct *fsp, int leasetype)
{
.fallocate_fn = skel_fallocate,
.lock_fn = skel_lock,
.kernel_flock_fn = skel_kernel_flock,
+ .fcntl_fn = skel_fcntl,
.linux_setlease_fn = skel_linux_setlease,
.getlock_fn = skel_getlock,
.symlinkat_fn = skel_symlinkat,
return SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, share_mode, access_mask);
}
+static int skel_fcntl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, int cmd, va_list cmd_arg)
+{
+ void *arg;
+ va_list dup_cmd_arg;
+ int result;
+
+ va_copy(dup_cmd_arg, cmd_arg);
+ arg = va_arg(dup_cmd_arg, void *);
+ result = SMB_VFS_NEXT_FCNTL(handle, fsp, cmd, arg);
+ va_end(dup_cmd_arg);
+
+ return result;
+}
+
static int skel_linux_setlease(struct vfs_handle_struct *handle,
struct files_struct *fsp, int leasetype)
{
.fallocate_fn = skel_fallocate,
.lock_fn = skel_lock,
.kernel_flock_fn = skel_kernel_flock,
+ .fcntl_fn = skel_fcntl,
.linux_setlease_fn = skel_linux_setlease,
.getlock_fn = skel_getlock,
.symlinkat_fn = skel_symlinkat,
ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
int sys_fcntl_ptr(int fd, int cmd, void *arg);
int sys_fcntl_long(int fd, int cmd, long arg);
+int sys_fcntl_int(int fd, int cmd, int arg);
void update_stat_ex_mtime(struct stat_ex *dst, struct timespec write_ts);
void update_stat_ex_itime(struct stat_ex *dst, struct timespec itime);
void update_stat_ex_create_time(struct stat_ex *dst, struct timespec create_time);
SMBPROFILE_STATS_BASIC(syscall_fallocate) \
SMBPROFILE_STATS_BASIC(syscall_fcntl_lock) \
SMBPROFILE_STATS_BASIC(syscall_kernel_flock) \
+ SMBPROFILE_STATS_BASIC(syscall_fcntl) \
SMBPROFILE_STATS_BASIC(syscall_linux_setlease) \
SMBPROFILE_STATS_BASIC(syscall_fcntl_getlock) \
SMBPROFILE_STATS_BASIC(syscall_readlinkat) \
/* Version 42 - Move change_to_user_by_fsp() -> change_to_user_and_service_by_fsp() */
/* Version 42 - Move [un]become_user*() -> [un]become_user_without_service*() */
/* Version 42 - Move SMB_VFS_UNLINK -> SMB_VFS_UNLINKAT. */
+/* Version 42 - Add SMB_VFS_FCNTL */
#define SMB_VFS_INTERFACE_VERSION 42
bool (*lock_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, off_t offset, off_t count, int type);
int (*kernel_flock_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp,
uint32_t share_mode, uint32_t access_mask);
+ int (*fcntl_fn)(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, int cmd, va_list cmd_arg);
int (*linux_setlease_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, int leasetype);
bool (*getlock_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid);
int (*symlinkat_fn)(struct vfs_handle_struct *handle,
int smb_vfs_call_kernel_flock(struct vfs_handle_struct *handle,
struct files_struct *fsp, uint32_t share_mode,
uint32_t access_mask);
+int smb_vfs_call_fcntl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, int cmd, ...);
int smb_vfs_call_linux_setlease(struct vfs_handle_struct *handle,
struct files_struct *fsp, int leasetype);
bool smb_vfs_call_getlock(struct vfs_handle_struct *handle,
int vfs_not_implemented_kernel_flock(struct vfs_handle_struct *handle,
struct files_struct *fsp,
uint32_t share_mode, uint32_t access_mask);
+int vfs_not_implemented_fcntl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, int cmd, va_list cmd_arg);
int vfs_not_implemented_linux_setlease(struct vfs_handle_struct *handle,
struct files_struct *fsp, int leasetype);
bool vfs_not_implemented_getlock(vfs_handle_struct *handle, files_struct *fsp,
#define SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, share_mode, access_mask) \
smb_vfs_call_kernel_flock((handle)->next, (fsp), (share_mode), (access_mask))
+#define SMB_VFS_FCNTL(fsp, cmd, ...) \
+ smb_vfs_call_fcntl((fsp)->conn->vfs_handles, (fsp), (cmd), (__VA_ARGS__))
+#define SMB_VFS_NEXT_FCNTL(handle, fsp, cmd, ...) \
+ smb_vfs_call_fcntl((handle)->next, (fsp), (cmd), (__VA_ARGS__))
+
#define SMB_VFS_LINUX_SETLEASE(fsp, leasetype) \
smb_vfs_call_linux_setlease((fsp)->conn->vfs_handles, (fsp), (leasetype))
#define SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype) \
return ret;
}
+/*******************************************************************
+A fcntl wrapper that will deal with EINTR.
+********************************************************************/
+
+int sys_fcntl_int(int fd, int cmd, int arg)
+{
+ int ret;
+
+ do {
+ ret = fcntl(fd, cmd, arg);
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+
/****************************************************************************
Get/Set all the possible time fields from a stat struct as a timespec.
****************************************************************************/
return 0;
}
+static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
+ va_list cmd_arg)
+{
+ void *argp;
+ va_list dup_cmd_arg;
+ int result;
+ int val;
+
+ START_PROFILE(syscall_fcntl);
+
+ va_copy(dup_cmd_arg, cmd_arg);
+
+ switch(cmd) {
+ case F_SETLK:
+ case F_SETLKW:
+ case F_GETLK:
+#if defined(HAVE_OFD_LOCKS)
+ case F_OFD_SETLK:
+ case F_OFD_SETLKW:
+ case F_OFD_GETLK:
+#endif
+#if defined(HAVE_F_OWNER_EX)
+ case F_GETOWN_EX:
+ case F_SETOWN_EX:
+#endif
+#if defined(HAVE_RW_HINTS)
+ case F_GET_RW_HINT:
+ case F_SET_RW_HINT:
+ case F_GET_FILE_RW_HINT:
+ case F_SET_FILE_RW_HINT:
+#endif
+ argp = va_arg(dup_cmd_arg, void *);
+ result = sys_fcntl_ptr(fsp->fh->fd, cmd, argp);
+ break;
+ default:
+ val = va_arg(dup_cmd_arg, int);
+ result = sys_fcntl_int(fsp->fh->fd, cmd, val);
+ }
+
+ va_end(dup_cmd_arg);
+
+ END_PROFILE(syscall_fcntl);
+ return result;
+}
+
static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
{
bool result;
.fallocate_fn = vfswrap_fallocate,
.lock_fn = vfswrap_lock,
.kernel_flock_fn = vfswrap_kernel_flock,
+ .fcntl_fn = vfswrap_fcntl,
.linux_setlease_fn = vfswrap_linux_setlease,
.getlock_fn = vfswrap_getlock,
.symlinkat_fn = vfswrap_symlinkat,
SMB_VFS_OP_FALLOCATE,
SMB_VFS_OP_LOCK,
SMB_VFS_OP_KERNEL_FLOCK,
+ SMB_VFS_OP_FCNTL,
SMB_VFS_OP_LINUX_SETLEASE,
SMB_VFS_OP_GETLOCK,
SMB_VFS_OP_SYMLINKAT,
return result;
}
+static int smb_full_audit_fcntl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ int cmd, va_list cmd_arg)
+{
+ void *arg;
+ va_list dup_cmd_arg;
+ int result;
+
+ va_copy(dup_cmd_arg, cmd_arg);
+ arg = va_arg(dup_cmd_arg, void *);
+ result = SMB_VFS_NEXT_FCNTL(handle, fsp, cmd, arg);
+ va_end(dup_cmd_arg);
+
+ do_log(SMB_VFS_OP_FCNTL, (result >= 0), handle, "%s",
+ fsp_str_do_log(fsp));
+
+ return result;
+}
+
static int smb_full_audit_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
int leasetype)
{
.fallocate_fn = smb_full_audit_fallocate,
.lock_fn = smb_full_audit_lock,
.kernel_flock_fn = smb_full_audit_kernel_flock,
+ .fcntl_fn = smb_full_audit_fcntl,
.linux_setlease_fn = smb_full_audit_linux_setlease,
.getlock_fn = smb_full_audit_getlock,
.symlinkat_fn = smb_full_audit_symlinkat,
return -1;
}
+int vfs_not_implemented_fcntl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, int cmd,
+ va_list cmd_arg)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
int vfs_not_implemented_linux_setlease(struct vfs_handle_struct *handle,
struct files_struct *fsp, int leasetype)
{
.fallocate_fn = vfs_not_implemented_fallocate,
.lock_fn = vfs_not_implemented_lock,
.kernel_flock_fn = vfs_not_implemented_kernel_flock,
+ .fcntl_fn = vfs_not_implemented_fcntl,
.linux_setlease_fn = vfs_not_implemented_linux_setlease,
.getlock_fn = vfs_not_implemented_getlock,
.symlinkat_fn = vfs_not_implemented_symlinkat,
return result;
}
+static int smb_time_audit_fcntl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ int cmd, va_list cmd_arg)
+{
+ void *arg;
+ va_list dup_cmd_arg;
+ int result;
+ struct timespec ts1,ts2;
+ double timediff;
+
+ va_copy(dup_cmd_arg, cmd_arg);
+ arg = va_arg(dup_cmd_arg, void *);
+ clock_gettime_mono(&ts1);
+ result = SMB_VFS_NEXT_FCNTL(handle, fsp, cmd, arg);
+ clock_gettime_mono(&ts2);
+ va_end(dup_cmd_arg);
+
+ timediff = nsec_time_diff(&ts2,&ts1)*1.0e-9;
+ if (timediff > audit_timeout) {
+ smb_time_audit_log_fsp("kernel_flock", timediff, fsp);
+ }
+
+ return result;
+}
+
static int smb_time_audit_linux_setlease(vfs_handle_struct *handle,
files_struct *fsp,
int leasetype)
.fallocate_fn = smb_time_audit_fallocate,
.lock_fn = smb_time_audit_lock,
.kernel_flock_fn = smb_time_audit_kernel_flock,
+ .fcntl_fn = smb_time_audit_fcntl,
.linux_setlease_fn = smb_time_audit_linux_setlease,
.getlock_fn = smb_time_audit_getlock,
.symlinkat_fn = smb_time_audit_symlinkat,
access_mask);
}
+int smb_vfs_call_fcntl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, int cmd, ...)
+{
+ int result;
+ va_list cmd_arg;
+
+ VFS_FIND(fcntl);
+
+ va_start(cmd_arg, cmd);
+ result = handle->fns->fcntl_fn(handle, fsp, cmd, cmd_arg);
+ va_end(cmd_arg);
+
+ return result;
+}
+
int smb_vfs_call_linux_setlease(struct vfs_handle_struct *handle,
struct files_struct *fsp, int leasetype)
{
execute=True,
msg="Checking whether fcntl lock supports open file description locks")
+ conf.CHECK_CODE('''
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+
+int main(void)
+{
+ int sockfd, ret;
+ struct f_owner_ex owner, get_owner;
+
+ sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sockfd == -1) {
+ goto err;
+ }
+
+ owner.type = F_OWNER_PID;
+ owner.pid = getpid();
+
+ ret = fcntl(sockfd, F_SETOWN_EX, &owner);
+ if (ret == -1) {
+ goto err;
+ }
+
+ ret = fcntl(sockfd, F_GETOWN_EX, &get_owner);
+ if (ret == -1) {
+ goto err;
+ }
+
+ if (get_owner.type != F_OWNER_PID) {
+ goto err;
+ }
+
+ if (get_owner.pid != getpid()) {
+ goto err;
+ }
+
+ close(sockfd);
+ exit(0);
+err:
+ close(sockfd);
+ exit(1);
+}''',
+ 'HAVE_F_OWNER_EX',
+ addmain=False,
+ execute=True,
+ msg="Checking whether fcntl supports flags to send direct I/O availability signals")
+
+ conf.CHECK_CODE('''
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#define DATA "hinttest.fcntl"
+
+int main(void)
+{
+ uint64_t *hint, get_hint;
+ int fd;
+
+ fd = open(DATA, O_RDONLY | O_CREAT | O_EXCL);
+ if (fd == -1) {
+ goto err;
+ }
+
+ *hint = RWH_WRITE_LIFE_SHORT;
+ int ret = fcntl(fd, F_SET_RW_HINT, hint);
+ if (ret == -1) {
+ goto err;
+ }
+
+ ret = fcntl(fd, F_GET_RW_HINT, &get_hint);
+ if (ret == -1) {
+ goto err;
+ }
+
+ if (get_hint != RWH_WRITE_LIFE_SHORT) {
+ goto err;
+ }
+
+ *hint = RWH_WRITE_LIFE_EXTREME;
+ ret = fcntl(fd, F_SET_FILE_RW_HINT, hint);
+ if (ret == -1) {
+ goto err;
+ }
+
+ ret = fcntl(fd, F_GET_FILE_RW_HINT, &get_hint);
+ if (ret == -1) {
+ goto err;
+ }
+
+ if (get_hint != RWH_WRITE_LIFE_EXTREME) {
+ goto err;
+ }
+
+ close(fd);
+ unlink(DATA);
+ exit(0);
+err:
+ close(fd);
+ unlink(DATA);
+ exit(1);
+}''',
+ 'HAVE_RW_HINTS',
+ addmain=False,
+ execute=True,
+ msg="Checking whether fcntl supports setting/geting hints")
+
conf.CHECK_STRUCTURE_MEMBER('struct stat', 'st_mtim.tv_nsec',
define='HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC') # Linux, Solaris
conf.CHECK_STRUCTURE_MEMBER('struct stat', 'st_mtimensec',