static int dev_mkdir(const char *name, mode_t mode) { struct nameidata nd; struct dentry *dentry; int err; err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, name, LOOKUP_PARENT, &nd); if (err) return err; dentry = lookup_create(&nd, 1); if (!IS_ERR(dentry)) { err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); if (!err) /* mark as kernel-created inode */ dentry->d_inode->i_private = &dev_mnt; dput(dentry); } else { err = PTR_ERR(dentry); } mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); return err; }
long link_by_fd(int file_fd, int newdfd, const char __user * newname) { int error; int fput_needed; struct file *filep; struct nameidata nd; struct dentry *new_dentry; filep = fget_light(file_fd, &fput_needed); if(!filep) return -EBADF; error = __user_walk_fd(newdfd, newname, LOOKUP_PARENT, &nd); if(error) goto file_out; error = -EXDEV; if(filep->f_vfsmnt != nd.mnt) goto out_release; new_dentry = lookup_create(&nd, 0); error = PTR_ERR(new_dentry); if(!IS_ERR(new_dentry)) { error = vfs_link(filep->f_dentry, nd.dentry->d_inode, new_dentry); dput(new_dentry); } mutex_unlock(&nd.dentry->d_inode->i_mutex); out_release: path_release(&nd); file_out: fput_light(filep, fput_needed); return error; }
/* On success, returns with parent_inode->i_sem taken. */ static int hwgfs_decode( hwgfs_handle_t dir, const char *name, int is_dir, struct inode **parent_inode, struct dentry **dentry) { struct nameidata nd; int error; if (!dir) dir = hwgfs_vfsmount->mnt_sb->s_root; memset(&nd, 0, sizeof(nd)); nd.flags = LOOKUP_PARENT; nd.mnt = mntget(hwgfs_vfsmount); nd.dentry = dget(dir); error = walk_parents_mkdir(&name, &nd, is_dir); if (unlikely(error)) return error; error = path_walk(name, &nd); if (unlikely(error)) return error; *dentry = lookup_create(&nd, is_dir); if (IS_ERR(*dentry)) return PTR_ERR(*dentry); *parent_inode = (*dentry)->d_parent->d_inode; return 0; }
/* Differs in that the balancing up() takes place on error */ static struct dentry *cr_lookup_create(struct nameidata *nd, int is_dir) { struct dentry *dentry; dentry = lookup_create(nd, is_dir); if (IS_ERR(dentry)) { cr_inode_unlock(nd->nd_dentry->d_inode); } return dentry; }
static int create_path(const char *nodepath) { char *path; struct nameidata nd; int err = 0; struct vfsmount *dev_mnt = ve_devmnt(); path = kstrdup(nodepath, GFP_KERNEL); if (!path) return -ENOMEM; err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, path, LOOKUP_PARENT, &nd); if (err == 0) { struct dentry *dentry; /* create directory right away */ dentry = lookup_create(&nd, 1); if (!IS_ERR(dentry)) { err = vfs_mkdir(nd.path.dentry->d_inode, dentry, 0755); dput(dentry); } mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); } else if (err == -ENOENT) { char *s; /* parent directories do not exist, create them */ s = path; while (1) { s = strchr(s, '/'); if (!s) break; s[0] = '\0'; err = dev_mkdir(path, 0755); if (err && err != -EEXIST) break; s[0] = '/'; s++; } } kfree(path); return err; }
static int walk_parents_mkdir( const char **path, struct nameidata *nd, int is_dir) { char *slash; char buf[strlen(*path)+1]; int error; while ((slash = strchr(*path, '/')) != NULL) { int len = slash - *path; memcpy(buf, *path, len); buf[len] = '\0'; error = path_walk(buf, nd); if (unlikely(error)) return error; nd->dentry = lookup_create(nd, is_dir); nd->flags |= LOOKUP_PARENT; if (IS_ERR(nd->dentry)) return PTR_ERR(nd->dentry); if (!nd->dentry->d_inode) error = vfs_mkdir(nd->dentry->d_parent->d_inode, nd->dentry, 0755); up(&nd->dentry->d_parent->d_inode->i_sem); if (unlikely(error)) return error; *path += len + 1; } return 0; }
int devtmpfs_create_node(struct device *dev) { const char *tmp = NULL; const char *nodename; const struct cred *curr_cred; mode_t mode = 0; struct nameidata nd; struct dentry *dentry; int err; if (!dev_mnt) return 0; nodename = device_get_devnode(dev, &mode, &tmp); if (!nodename) return -ENOMEM; if (mode == 0) mode = 0600; if (is_blockdev(dev)) mode |= S_IFBLK; else mode |= S_IFCHR; curr_cred = override_creds(&init_cred); err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, nodename, LOOKUP_PARENT, &nd); if (err == -ENOENT) { create_path(nodename); err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, nodename, LOOKUP_PARENT, &nd); } if (err) goto out; dentry = lookup_create(&nd, 0); if (!IS_ERR(dentry)) { err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, dev->devt); if (!err) { struct iattr newattrs; /* fixup possibly umasked mode */ newattrs.ia_mode = mode; newattrs.ia_valid = ATTR_MODE; mutex_lock(&dentry->d_inode->i_mutex); notify_change(dentry, &newattrs); mutex_unlock(&dentry->d_inode->i_mutex); /* mark as kernel-created inode */ dentry->d_inode->i_private = &dev_mnt; } dput(dentry); } else { err = PTR_ERR(dentry); } mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); out: kfree(tmp); revert_creds(curr_cred); return err; }
int file_mkdir(const char * pathname, unsigned short perms, int recurse) { /* Welcome to the jungle... */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,41) /* 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(2,6,41) { 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,38) 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(KERN_ERR "%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; }
int devtmpfs_create_node(struct device *dev) { const char *tmp = NULL; const char *nodename; const struct cred *curr_cred; struct user_beancounter *curr_ub; mode_t mode = 0; struct nameidata nd; struct dentry *dentry; int err; struct vfsmount *dev_mnt = ve_devmnt(); if (!dev_mnt) return 0; nodename = device_get_devnode(dev, &mode, &tmp); if (!nodename) return -ENOMEM; if (mode == 0) mode = 0600; if (is_blockdev(dev)) mode |= S_IFBLK; else mode |= S_IFCHR; curr_ub = set_exec_ub(&ub0); curr_cred = override_creds(&init_cred); err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, nodename, LOOKUP_PARENT, &nd); if (err == -ENOENT) { /* create missing parent directories */ create_path(nodename); err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, nodename, LOOKUP_PARENT, &nd); if (err) goto out; } dentry = lookup_create(&nd, 0); if (!IS_ERR(dentry)) { int umask; umask = sys_umask(0000); err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, dev->devt); sys_umask(umask); /* mark as kernel created inode */ if (!err) dentry->d_inode->i_private = &dev_mnt; dput(dentry); } else { err = PTR_ERR(dentry); } mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); out: kfree(tmp); revert_creds(curr_cred); (void)set_exec_ub(curr_ub); return err; }