????
| Current Path : /var/lib/dkms/file_protector/1.1-1578/source/ |
| Current File : //var/lib/dkms/file_protector/1.1-1578/source/file_handle_tools.h |
/**
@file file_handle_tools.h
@brief Tools for creating and working with file handles
@details Copyright (c) 2024 Acronis International GmbH
@author Bruce Wang (bruce.wang@acronis.com)
@since $Id: $
*/
#pragma once
#include "compat.h"
#include "memory.h"
typedef struct {
uint32_t handle_bytes;
int handle_type;
int mnt_id;
unsigned char* f_handle;
} file_handle_info_t;
#ifndef BPF_PROGRAM
// init_empty initialize message enough so 'free' can work
static inline void file_handle_info_init_empty(file_handle_info_t* info)
{
info->f_handle = NULL;
}
#ifndef FILEID_INVALID
#define FILEID_INVALID 0xff
#endif
// It is a bit counterintuitive but 'info->mnt_id' is always filled in despite the return value.
// If 'f_handle' is non-null, it can be used
static inline int file_handle_info_make_with_alloc_flags(file_handle_info_t* info, const struct path *path, bool nowait)
{
int dwords = MAX_HANDLE_SZ >> 2;
struct dentry *dentry = path->dentry;
struct vfsmount* mnt = path->mnt;
info->mnt_id = mnt ? get_mnt_id(mnt) : 0;
info->f_handle = NULL;
info->handle_bytes = 0;
#ifdef HAVE_EXPORTFS_ENCODE_INODE_FH
if (!dentry || !dentry->d_inode || !dentry->d_inode->i_sb || !dentry->d_inode->i_sb->s_export_op) {
return -EFAULT;
}
#else
if (!dentry || !dentry->d_sb || !dentry->d_sb->s_export_op) {
return -EFAULT;
}
#endif
info->f_handle = kmem_cache_alloc(g_handles_cache, mem_flags(nowait));
if (!info->f_handle) {
return -ENOMEM;
}
// Returns an enum fid_type or a negative on errno.
info->handle_type = exportfs_encode_fh(dentry, (struct fid *)info->f_handle, &dwords, 0);
// original codes are here: https://elixir.bootlin.com/linux/v6.16.1/source/fs/fhandle.c#L64
if (info->handle_type < 0 || info->handle_type == FILEID_INVALID)
{
goto err;
}
info->handle_bytes = dwords * sizeof(u32);
if (info->handle_bytes > MAX_HANDLE_SZ) {
info->handle_bytes = MAX_HANDLE_SZ;
}
return 0;
err:
kmem_cache_free(g_handles_cache, info->f_handle);
info->f_handle = NULL;
info->handle_bytes = 0;
return info->handle_type;
}
static inline int file_handle_info_make(file_handle_info_t* info, const struct path *path)
{
return file_handle_info_make_with_alloc_flags(info, path, false /*nowait*/);
}
static inline int file_handle_info_make_nowait(file_handle_info_t* info, const struct path *path)
{
return file_handle_info_make_with_alloc_flags(info, path, true /*nowait*/);
}
static inline void file_handle_info_free(file_handle_info_t* info) {
if (info->f_handle) {
kmem_cache_free(g_handles_cache, info->f_handle);
}
}
#endif