#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/version.h>
#include <linux/file.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
static struct list_head global_files;
+#define isprint(a) ((a >= ' ') && (a <= '~'))
struct palacios_file {
struct file * filp;
+static int palacios_file_mkdir(const char * pathname, unsigned short perms, int recurse);
+
+static int mkdir_recursive(const char * path, unsigned short perms) {
+ char * tmp_str = NULL;
+ char * dirname_ptr;
+ char * tmp_iter;
+
+ tmp_str = kmalloc(strlen(path) + 1, GFP_KERNEL);
+ memset(tmp_str, 0, strlen(path) + 1);
+ strncpy(tmp_str, path, strlen(path));
+
+ dirname_ptr = tmp_str;
+ tmp_iter = tmp_str;
+
+ // parse path string, call palacios_file_mkdir recursively.
+
+
+ while (dirname_ptr != NULL) {
+ int done = 0;
+
+ while ((*tmp_iter != '/') &&
+ (*tmp_iter != '\0')) {
+
+ if ( (!isprint(*tmp_iter))) {
+ printk("Invalid character in path name (%d)\n", *tmp_iter);
+ return -1;
+ } else {
+ tmp_iter++;
+ }
+ }
+
+ if (*tmp_iter == '/') {
+ *tmp_iter = '\0';
+ } else {
+ done = 1;
+ }
+
+ // Ignore empty directories
+ if ((tmp_iter - dirname_ptr) > 1) {
+ if (palacios_file_mkdir(tmp_str, perms, 0) != 0) {
+ printk("Could not create directory (%s)\n", tmp_str);
+ return -1;
+ }
+ }
+
+ if (done) {
+ break;
+ } else {
+ *tmp_iter = '/';
+ }
+
+ tmp_iter++;
+
+ dirname_ptr = tmp_iter;
+ }
+
+ kfree(tmp_str);
+
+ return 0;
+}
+
+static int palacios_file_mkdir(const char * pathname, unsigned short perms, int recurse) {
+ /* Welcome to the jungle... */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)
+ /* DO NOT REFERENCE THIS VARIABLE */
+ /* It only exists to provide version compatibility */
+ struct path tmp_path;
+#endif
+
+ struct path * path_ptr = NULL;
+ struct dentry * dentry;
+ int ret = 0;
+
+
+
+ if (recurse != 0) {
+ return mkdir_recursive(pathname, perms);
+ }
+
+ /* Before Linux 3.1 this was somewhat more difficult */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)
+ {
+ struct nameidata nd;
+
+ // I'm not 100% sure about the version here, but it was around this time that the API changed
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
+ ret = kern_path_parent(pathname, &nd);
+#else
+
+ if (path_lookup(pathname, LOOKUP_DIRECTORY | LOOKUP_FOLLOW, &nd) == 0) {
+ return 0;
+ }
+
+ if (path_lookup(pathname, LOOKUP_PARENT | LOOKUP_FOLLOW, &nd) != 0) {
+ return -1;
+ }
+#endif
+
+ if (ret != 0) {
+ printk("%s:%d - Error: kern_path_parent() returned error for (%s)\n", __FILE__, __LINE__,
+ pathname);
+ return -1;
+ }
+
+ dentry = lookup_create(&nd, 1);
+ path_ptr = &(nd.path);
+ }
+#else
+ {
+ dentry = kern_path_create(AT_FDCWD, pathname, &tmp_path, 1);
+
+ if (IS_ERR(dentry)) {
+ return 0;
+ }
+
+ path_ptr = &tmp_path;
+ }
+#endif
+
+
+ if (!IS_ERR(dentry)) {
+ ret = vfs_mkdir(path_ptr->dentry->d_inode, dentry, perms);
+ }
+
+ mutex_unlock(&(path_ptr->dentry->d_inode->i_mutex));
+ path_put(path_ptr);
+
+ return ret;
+}
+
+
static void * palacios_file_open(const char * path, int mode, void * private_data) {
struct v3_guest * guest = (struct v3_guest *)private_data;
struct palacios_file * pfile = NULL;
.read = palacios_file_read,
.write = palacios_file_write,
.size = palacios_file_size,
+ .mkdir = palacios_file_mkdir,
};
*vm_data = state;
+
return 0;
}
+#ifdef V3_CONFIG_FILE
+#include <interfaces/vmm_file.h>
+
+
+struct file_ctx {
+ v3_file_t file;
+ uint64_t offset;
+ char * filename;
+};
+
+
+static void * dir_open_chkpt(char * url, chkpt_mode_t mode) {
+ if (mode == SAVE) {
+ if (v3_mkdir(url, 0755, 1) != 0) {
+ return NULL;
+ }
+ }
+
+ return url;
+}
+
+
+
+static int dir_close_chkpt(void * store_data) {
+ return 0;
+}
+
+static void * dir_open_ctx(void * store_data,
+ void * parent_ctx,
+ char * name) {
+
+ char * url = store_data;
+ struct file_ctx * ctx = NULL;
+
+
+ ctx = V3_Malloc(sizeof(struct file_ctx));
+ memset(ctx, 0, sizeof(struct file_ctx));
+
+ ctx->filename = V3_Malloc(strlen(url) + strlen(name) + 5);
+ memset(ctx->filename, 0, strlen(url) + strlen(name) + 5);
+
+ snprintf(ctx->filename, strlen(url) + strlen(name) + 5, "%s/%s", url, name);
+
+
+ ctx->file = v3_file_open(NULL, ctx->filename, FILE_OPEN_MODE_READ | FILE_OPEN_MODE_WRITE | FILE_OPEN_MODE_CREATE);
+
+ return ctx;
+}
+
+static int dir_close_ctx(void * store_data, void * ctx) {
+ struct file_ctx * file_ctx = ctx;
+
+ v3_file_close(file_ctx->file);
+
+ V3_Free(file_ctx->filename);
+ V3_Free(file_ctx);
+
+ return 0;
+}
+
+static int dir_save(void * store_data, void * ctx,
+ char * tag, uint64_t len, void * buf) {
+ struct file_ctx * file_ctx = ctx;
+ uint64_t ret = 0;
+
+ ret = v3_file_write(file_ctx->file, buf, len, file_ctx->offset);
+
+ file_ctx->offset += ret;
+
+ return 0;
+}
+
+static int dir_load(void * store_data, void * ctx,
+ char * tag, uint64_t len, void * buf) {
+ struct file_ctx * file_ctx = ctx;
+ uint64_t ret = 0;
+
+ ret = v3_file_read(file_ctx->file, buf, len, file_ctx->offset);
+
+ file_ctx->offset += ret;
+
+ return 0;
+}
+
+
+static struct chkpt_interface dir_store = {
+ .name = "DIR",
+ .open_chkpt = dir_open_chkpt,
+ .close_chkpt = dir_close_chkpt,
+ .open_ctx = dir_open_ctx,
+ .close_ctx = dir_close_ctx,
+ .save = dir_save,
+ .load = dir_load
+};
+
+register_chkpt_store(dir_store);
+
+
+
+#endif
+
+
+