static int smb_create(struct inode *dir, const char *name, int len, int mode, struct inode **result) { int error; struct smb_dirent entry; struct smb_inode_info *new_inode_info; *result = NULL; if (!dir || !S_ISDIR(dir->i_mode)) { printk("smb_create: inode is NULL or not a directory\n"); iput(dir); return -ENOENT; } new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info), GFP_KERNEL); if (new_inode_info == NULL) { iput(dir); return -ENOMEM; } error = smb_proc_create(dir, name, len, 0, CURRENT_TIME); if (error < 0) { smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info)); iput(dir); return error; } smb_invalid_dir_cache(dir->i_ino); if ((error = smb_proc_getattr(dir, name, len, &entry)) < 0) { smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info)); iput(dir); return error; } entry.f_ino = smb_fresh_inodes(SMB_SERVER(dir), 1); new_inode_info->finfo = entry; if ((*result = smb_iget(dir, new_inode_info)) == NULL) { iput(dir); return error; } iput(dir); return 0; }
void smb_free_inode_info(struct smb_inode_info *i) { if (i == NULL) { printk("smb_free_inode: i == NULL\n"); return; } i->state = SMB_INODE_CACHED; while ((i->nused == 0) && (i->state == SMB_INODE_CACHED)) { struct smb_inode_info *dir = i->dir; i->next->prev = i->prev; i->prev->next = i->next; smb_kfree_s(i, sizeof(struct smb_inode_info)); if (dir == NULL) { return; } dir->nused -= 1; i = dir; } }
static void smb_put_super(struct super_block *sb) { struct smb_server *server = &(SMB_SBP(sb)->s_server); smb_proc_disconnect(server); close_fp(server->sock_file); lock_super(sb); smb_free_all_inodes(server); smb_kfree_s(server->packet, server->max_xmit); sb->s_dev = 0; smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info)); unlock_super(sb); MOD_DEC_USE_COUNT; }
static int smb_lookup(struct inode *dir, const char *name, int len, struct inode **result) { struct smb_dirent finfo; struct smb_inode_info *result_info; int error; int found_in_cache; struct smb_inode_info *new_inode_info = NULL; *result = NULL; if (!dir || !S_ISDIR(dir->i_mode)) { printk("smb_lookup: inode is NULL or not a directory.\n"); iput(dir); return -ENOENT; } DDPRINTK("smb_lookup: %s\n", name); /* Fast cheat for . */ if (len == 0 || (len == 1 && name[0] == '.')) { *result = dir; return 0; } /* ..and for .. */ if (len == 2 && name[0] == '.' && name[1] == '.') { struct smb_inode_info *parent = SMB_INOP(dir)->dir; if (parent->state == SMB_INODE_CACHED) { parent->state = SMB_INODE_LOOKED_UP; } *result = iget(dir->i_sb, smb_info_ino(parent)); iput(dir); if (*result == 0) { return -EACCES; } return 0; } result_info = smb_find_dir_inode(dir, name, len); in_tree: if (result_info != NULL) { if (result_info->state == SMB_INODE_CACHED) { result_info->state = SMB_INODE_LOOKED_UP; } *result = iget(dir->i_sb, smb_info_ino(result_info)); iput(dir); if (new_inode_info != NULL) { smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info)); } if (*result == NULL) { return -EACCES; } return 0; } /* If the file is in the dir cache, we do not have to ask the server. */ found_in_cache = 0; if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino) && (c_size != 0)) { int first = c_last_returned_index; int i; i = first; do { if (compare_filename(SMB_SERVER(dir), name, len, &(c_entry[i])) == 0) { finfo = c_entry[i]; found_in_cache = 1; break; } i = (i + 1) % c_size; } while (i != first); } if (found_in_cache == 0) { DPRINTK("smb_lookup: not found in cache: %s\n", name); if (len > SMB_MAXNAMELEN) { iput(dir); return -ENAMETOOLONG; } error = smb_proc_getattr(dir, name, len, &finfo); if (error < 0) { iput(dir); return error; } finfo.f_ino = smb_fresh_inodes(SMB_SERVER(dir), 1); } new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info), GFP_KERNEL); /* Here somebody else might have inserted the inode */ result_info = smb_find_dir_inode(dir, name, len); if (result_info != NULL) { goto in_tree; } if (new_inode_info == NULL) { iput(dir); return -ENOMEM; } new_inode_info->finfo = finfo; DPRINTK("attr: %x\n", finfo.attr); if ((*result = smb_iget(dir, new_inode_info)) == NULL) { iput(dir); return -EACCES; } DDPRINTK("smb_lookup: %s => %lu\n", name, (unsigned long) result_info); iput(dir); return 0; }
/* Hmm, should we do this like the NFS mount command does? Guess so.. */ struct super_block * smb_read_super(struct super_block *sb, void *raw_data, int silent) { struct smb_mount_data *data = (struct smb_mount_data *) raw_data; struct smb_server *server; struct smb_sb_info *smb_sb; unsigned int fd; struct file *filp; kdev_t dev = sb->s_dev; int error; if (!data) { printk("smb_read_super: missing data argument\n"); sb->s_dev = 0; return NULL; } fd = data->fd; if (data->version != SMB_MOUNT_VERSION) { printk("smb warning: mount version %s than kernel\n", (data->version < SMB_MOUNT_VERSION) ? "older" : "newer"); } if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) { printk("smb_read_super: invalid file descriptor\n"); sb->s_dev = 0; return NULL; } if (!S_ISSOCK(filp->f_inode->i_mode)) { printk("smb_read_super: not a socket!\n"); sb->s_dev = 0; return NULL; } /* We must malloc our own super-block info */ smb_sb = (struct smb_sb_info *)smb_kmalloc(sizeof(struct smb_sb_info), GFP_KERNEL); if (smb_sb == NULL) { printk("smb_read_super: could not alloc smb_sb_info\n"); return NULL; } filp->f_count += 1; lock_super(sb); SMB_SBP(sb) = smb_sb; sb->s_blocksize = 1024; /* Eh... Is this correct? */ sb->s_blocksize_bits = 10; sb->s_magic = SMB_SUPER_MAGIC; sb->s_dev = dev; sb->s_op = &smb_sops; server = &(SMB_SBP(sb)->s_server); server->sock_file = filp; server->lock = 0; server->wait = NULL; server->packet = NULL; server->max_xmit = data->max_xmit; if (server->max_xmit <= 0) server->max_xmit = SMB_DEF_MAX_XMIT; server->tid = 0; server->pid = current->pid; server->mid = current->pid + 20; server->m = *data; server->m.file_mode = (server->m.file_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG; server->m.dir_mode = (server->m.dir_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR; smb_init_root(server); /* * Make the connection to the server */ error = smb_proc_connect(server); unlock_super(sb); if (error < 0) { sb->s_dev = 0; printk("smb_read_super: Failed connection, bailing out " "(error = %d).\n", -error); goto fail; } if (server->protocol >= PROTOCOL_LANMAN2) server->case_handling = CASE_DEFAULT; else server->case_handling = CASE_LOWER; if ((error = smb_proc_dskattr(sb, &(SMB_SBP(sb)->s_attr))) < 0) { sb->s_dev = 0; printk("smb_read_super: could not get super block " "attributes\n"); smb_kfree_s(server->packet, server->max_xmit); goto fail; } if ((error = smb_stat_root(server)) < 0) { sb->s_dev = 0; printk("smb_read_super: could not get root dir attributes\n"); smb_kfree_s(server->packet, server->max_xmit); goto fail; } DPRINTK("smb_read_super : %u %u %u %u\n", SMB_SBP(sb)->s_attr.total, SMB_SBP(sb)->s_attr.blocksize, SMB_SBP(sb)->s_attr.allocblocks, SMB_SBP(sb)->s_attr.free); DPRINTK("smb_read_super: SMB_SBP(sb) = %x\n", (int)SMB_SBP(sb)); if (!(sb->s_mounted = iget(sb, (int)&(server->root)))) { sb->s_dev = 0; printk("smb_read_super: get root inode failed\n"); smb_kfree_s(server->packet, server->max_xmit); goto fail; } MOD_INC_USE_COUNT; return sb; fail: filp->f_count -= 1; smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info)); return NULL; }