static int sdcardfskk_mkdir(struct inode *dir, struct dentry *dentry, int mode) { int err = 0; int make_nomedia_in_obb = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; struct sdcardfskk_sb_info *sbi = SDCARDFSKK_SB(dentry->d_sb); const struct cred *saved_cred = NULL; struct sdcardfskk_inode_info *pi = SDCARDFSKK_I(dir); char *page_buf; char *nomedia_dir_name; char *nomedia_fullpath; int fullpath_namelen; int touch_err = 0; int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); err = -EACCES; goto out_eacces; } /* save current_cred and override it */ OVERRIDE_CRED(SDCARDFSKK_SB(dir->i_sb), saved_cred); /* check disk space */ if (!check_min_free_space(dentry, 0, 1)) { printk(KERN_INFO "sdcardfskk: No minimum free space.\n"); err = -ENOSPC; goto out_revert; } /* the lower_dentry is negative here */ sdcardfskk_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; /* set last 16bytes of mode field to 0775 */ mode = (mode & S_IFMT) | 00775; err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode); if (err) goto out; /* if it is a local obb dentry, setup it with the base obbpath */ if(need_graft_path(dentry)) { err = setup_obb_dentry(dentry, &lower_path); if(err) { /* if the sbi->obbpath is not available, the lower_path won't be * changed by setup_obb_dentry() but the lower path is saved to * its orig_path. this dentry will be revalidated later. * but now, the lower_path should be NULL */ sdcardfskk_put_reset_lower_path(dentry); /* the newly created lower path which saved to its orig_path or * the lower_path is the base obbpath. * therefore, an additional path_get is required */ path_get(&lower_path); } else make_nomedia_in_obb = 1; } err = sdcardfskk_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, sdcardfskk_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); /* update number of links on parent directory */ dir->i_nlink = sdcardfskk_lower_inode(dir)->i_nlink; if ((sbi->options.derive == DERIVE_UNIFIED) && (!strcasecmp(dentry->d_name.name, "obb")) && (pi->perm == PERM_ANDROID) && (pi->userid == 0)) make_nomedia_in_obb = 1; /* When creating /Android/data and /Android/obb, mark them as .nomedia */ if (make_nomedia_in_obb || ((pi->perm == PERM_ANDROID) && (!strcasecmp(dentry->d_name.name, "data")))) { page_buf = (char *)__get_free_page(GFP_KERNEL); if (!page_buf) { printk(KERN_ERR "sdcardfskk: failed to allocate page buf\n"); goto out; } nomedia_dir_name = d_absolute_path(&lower_path, page_buf, PAGE_SIZE); if (IS_ERR(nomedia_dir_name)) { free_page((unsigned long)page_buf); printk(KERN_ERR "sdcardfskk: failed to get .nomedia dir name\n"); goto out; } fullpath_namelen = page_buf + PAGE_SIZE - nomedia_dir_name - 1; fullpath_namelen += strlen("/.nomedia"); nomedia_fullpath = kzalloc(fullpath_namelen + 1, GFP_KERNEL); if (!nomedia_fullpath) { free_page((unsigned long)page_buf); printk(KERN_ERR "sdcardfskk: failed to allocate .nomedia fullpath buf\n"); goto out; } strcpy(nomedia_fullpath, nomedia_dir_name); free_page((unsigned long)page_buf); strcat(nomedia_fullpath, "/.nomedia"); touch_err = touch(nomedia_fullpath, 0664); if (touch_err) { printk(KERN_ERR "sdcardfskk: failed to touch(%s): %d\n", nomedia_fullpath, touch_err); kfree(nomedia_fullpath); goto out; } kfree(nomedia_fullpath); } out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); sdcardfskk_put_lower_path(dentry, &lower_path); out_revert: REVERT_CRED(saved_cred); out_eacces: return err; }
static struct inode *sdcardfskk_iget(struct super_block *sb, struct inode *lower_inode) { struct sdcardfskk_inode_info *info; struct inode *inode; /* the new inode to return */ int err; inode = iget5_locked(sb, /* our superblock */ /* * hashval: we use inode number, but we can * also use "(unsigned long)lower_inode" * instead. */ lower_inode->i_ino, /* hashval */ sdcardfskk_inode_test, /* inode comparison function */ sdcardfskk_inode_set, /* inode init function */ lower_inode); /* data passed to test+set fxns */ if (!inode) { err = -EACCES; iput(lower_inode); return ERR_PTR(err); } /* if found a cached inode, then just return it */ if (!(inode->i_state & I_NEW)) return inode; /* initialize new inode */ info = SDCARDFSKK_I(inode); inode->i_ino = lower_inode->i_ino; if (!igrab(lower_inode)) { err = -ESTALE; return ERR_PTR(err); } sdcardfskk_set_lower_inode(inode, lower_inode); inode->i_version++; /* use different set of inode ops for symlinks & directories */ if (S_ISDIR(lower_inode->i_mode)) inode->i_op = &sdcardfskk_dir_iops; else if (S_ISLNK(lower_inode->i_mode)) inode->i_op = &sdcardfskk_symlink_iops; else inode->i_op = &sdcardfskk_main_iops; /* use different set of file ops for directories */ if (S_ISDIR(lower_inode->i_mode)) inode->i_fop = &sdcardfskk_dir_fops; else inode->i_fop = &sdcardfskk_main_fops; inode->i_mapping->a_ops = &sdcardfskk_aops; inode->i_atime.tv_sec = 0; inode->i_atime.tv_nsec = 0; inode->i_mtime.tv_sec = 0; inode->i_mtime.tv_nsec = 0; inode->i_ctime.tv_sec = 0; inode->i_ctime.tv_nsec = 0; /* properly initialize special inodes */ if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) || S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode)) init_special_inode(inode, lower_inode->i_mode, lower_inode->i_rdev); /* all well, copy inode attributes, don't need to hold i_mutex here */ sdcardfskk_copy_inode_attr(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); fix_derived_permission(inode); unlock_new_inode(inode); return inode; }
static void sdcardfskk_destroy_inode(struct inode *inode) { kmem_cache_free(sdcardfskk_inode_cachep, SDCARDFSKK_I(inode)); }