X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=linux_module%2Fiface-file.c;h=1df1d6d590f5bd1237cdde5d93bcb2895f01bd8e;hb=dc41a5e6b7601dcdf9eb2ac84dbf297cac037f5b;hp=965023a3da02cb3374b4acfb6cf605c0ca0d35ab;hpb=a9a6c3664c8fdbdb9841a55d1a2fca7f4fa8f5de;p=palacios.git diff --git a/linux_module/iface-file.c b/linux_module/iface-file.c index 965023a..1df1d6d 100644 --- a/linux_module/iface-file.c +++ b/linux_module/iface-file.c @@ -4,6 +4,8 @@ #include +#include +#include #include #include #include @@ -16,6 +18,7 @@ static struct list_head global_files; +#define isprint(a) ((a >= ' ') && (a <= '~')) struct palacios_file { struct file * filp; @@ -39,6 +42,138 @@ struct vm_file_state { +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,37) + 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; @@ -69,9 +204,12 @@ static void * palacios_file_open(const char * path, int mode, void * private_dat } + pfile->mode |= O_LARGEFILE; + + pfile->filp = filp_open(path, pfile->mode, 0); - if (pfile->filp == NULL) { + if (IS_ERR(pfile->filp)) { printk("Cannot open file: %s\n", path); return NULL; } @@ -170,6 +308,7 @@ static struct v3_file_hooks palacios_file_hooks = { .read = palacios_file_read, .write = palacios_file_write, .size = palacios_file_size, + .mkdir = palacios_file_mkdir, }; @@ -198,6 +337,7 @@ static int guest_file_init(struct v3_guest * guest, void ** vm_data) { *vm_data = state; + return 0; }