long name_to_handle_at(int dfd, const char __user * name, struct file_handle __user * handle, int flag) { int follow; long ret = -EINVAL; struct nameidata nd; struct file *file = NULL; if(!capable(CAP_DAC_OVERRIDE)) { ret = -EPERM; goto err_out; } if((flag & ~AT_SYMLINK_FOLLOW) != 0) goto err_out; if(name == NULL && dfd != AT_FDCWD) { file = fget(dfd); if(file) nd.dentry = file->f_dentry; else { ret = -EBADF; goto err_out; } } else { follow = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0; ret = __user_walk_fd(dfd, name, follow, &nd); if(ret) goto err_out; } ret = do_sys_name_to_handle(&nd, handle); if(file) fput(file); else path_release(&nd); err_out: return ret; }
/** * sys_name_to_handle_at: convert name to handle * @dfd: directory relative to which name is interpreted if not absolute * @name: name that should be converted to handle. * @handle: resulting file handle * @mnt_id: mount id of the file system containing the file * @flag: flag value to indicate whether to follow symlink or not * * @handle->handle_size indicate the space available to store the * variable part of the file handle in bytes. If there is not * enough space, the field is updated to return the minimum * value required. */ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name, struct file_handle __user *, handle, int __user *, mnt_id, int, flag) { struct path path; int lookup_flags; int err; if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) return -EINVAL; lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0; if (flag & AT_EMPTY_PATH) lookup_flags |= LOOKUP_EMPTY; err = user_path_at(dfd, name, lookup_flags, &path); if (!err) { err = do_sys_name_to_handle(&path, handle, mnt_id); path_put(&path); } return err; }