/*
* Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#include <linux/ctype.h>
#include <linux/dcache.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/slab.h>
#include <linux/statfs.h>
#include <linux/types.h>
#include <asm/uaccess.h>
#include "os.h"
static struct inode *get_inode(struct super_block *, struct dentry *);
struct hppfs_data {
struct list_head list;
char contents[PAGE_SIZE - sizeof(struct list_head)];
};
struct hppfs_private {
struct file *proc_file;
int host_fd;
loff_t len;
struct hppfs_data *contents;
};
struct hppfs_inode_info {
struct dentry *proc_dentry;
struct inode vfs_inode;
};
static inline struct hppfs_inode_info *HPPFS_I(struct inode *inode)
{
return container_of(inode, struct hppfs_inode_info, vfs_inode);
}
#define HPPFS_SUPER_MAGIC 0xb00000ee
static const struct super_operations hppfs_sbops;
static int is_pid(struct dentry *dentry)
{
struct super_block *sb;
int i;
sb = dentry->d_sb;
if (dentry->d_parent != sb->s_root)
return 0;
for (i = 0; i < dentry->d_name.len; i++) {
if (!isdigit(dentry->d_name.name[i]))
return 0;
}
return 1;
}
static char *dentry_name(struct dentry *dentry, int extra)
{
struct dentry *parent;
char *root, *name;
const char *seg_name;
int len, seg_len;
len = 0;
parent = dentry;
while (parent->d_parent != parent) {
if (is_pid(parent))
len += strlen("pid") + 1;
else len += parent->d_name.len + 1;
parent = parent->d_parent;
}
root = "proc";
len += strlen(root);
name = kmalloc(len + extra + 1, GFP_KERNEL);
if (name == NULL)
return NULL;
name[len] = '\0';
parent = dentry;
while (parent->d_parent != parent) {
if (is_pid(parent)) {
seg_name = "pid";
seg_len = strlen("pid");
}
else {
seg_name = parent->d_name.name;
seg_len = parent->d_name.len;
}
len -= seg_len + 1;
name[len] = '/';
strncpy(&name[len + 1], seg_name, seg_len);
parent = parent->d_parent;
}
strncpy(name, root, strlen(root));
return name;
}
static int file_removed(struct dentry *dentry, const char *file)
{
char *host_file;
int extra, fd;
extra = 0;
if (file != NULL)
extra += strlen(file) + 1;
host_file = dentry_name(dentry, extra + strlen("/remove"));
if (host_file == NULL) {
printk(KERN_ERR "file_removed : allocation failed\n");
return -ENOMEM;
}
if (file != NULL) {
strcat(host_file, "/");
strcat(host_file, file);
}
strcat(host_file, "/remove");
fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
kfree(host_file);
if (fd > 0) {
os_close_file(fd);
return 1;
}
return 0;
}
static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
struct nameidata *nd)
{
struct dentry *proc_dentry, *new, *parent;
struct inode *inode;
int err, deleted;
deleted = file_removed(dentry, NULL);
if (deleted < 0)
return ERR_PTR(deleted);
else if (deleted)
return ERR_PTR(-ENOENT);
err = -ENOMEM;
parent = HPPFS_I(ino)->proc_dentry;
mutex_lock(&parent->d_inode->i_mutex);
proc_dentry = d_lookup(parent, &dentry->d_name);
if (proc_dentry == NULL) {
proc_dentry = d_alloc(parent, &dentry->d_name);
if (proc_dentry == NULL) {
mutex_unlock(&parent->d_inode->i_mutex);
goto out;
}
new = (*parent->d_inode->i_op->lookup)(parent->d_inode,
proc_dentry, NULL);
if (new) {
dput(proc_dentry);
proc_dentry = new;
}
}
mutex_unlock(&parent->d_inode->i_mutex);
if (IS_ERR(proc_dentry))
return proc_dentry;
err = -ENOMEM;
inode = get_inode(ino->i_sb,