URL
https://opencores.org/ocsvn/or1k_old/or1k_old/trunk
Subversion Repositories or1k_old
[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [fs/] [smbfs/] [inode.c] - Rev 1782
Compare with Previous | Blame | View Log
/* * inode.c * * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke * */ #include <linux/module.h> #include <asm/system.h> #include <asm/segment.h> #include <linux/sched.h> #include <linux/smb_fs.h> #include <linux/smbno.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/stat.h> #include <linux/errno.h> #include <linux/locks.h> #include <linux/fcntl.h> #include <linux/malloc.h> extern int close_fp(struct file *filp); static void smb_put_inode(struct inode *); static void smb_read_inode(struct inode *); static void smb_put_super(struct super_block *); static void smb_statfs(struct super_block *, struct statfs *, int bufsiz); static struct super_operations smb_sops = { smb_read_inode, /* read inode */ smb_notify_change, /* notify change */ NULL, /* write inode */ smb_put_inode, /* put inode */ smb_put_super, /* put superblock */ NULL, /* write superblock */ smb_statfs, /* stat filesystem */ NULL }; /* smb_read_inode: Called from iget, it only traverses the allocated smb_inode_info's and initializes the inode from the data found there. It does not allocate or deallocate anything. */ static void smb_read_inode(struct inode *inode) { /* Our task should be extremely simple here. We only have to look up the information somebody else (smb_iget) put into the inode tree. */ struct smb_server *server = SMB_SERVER(inode); struct smb_inode_info *inode_info = smb_find_inode(server, inode->i_ino); if (inode_info == NULL) { /* Ok, now we're in trouble. The inode info is not there. What should we do now??? */ printk("smb_read_inode: inode %ld info not found\n", inode->i_ino); return; } inode_info->state = SMB_INODE_VALID; SMB_INOP(inode) = inode_info; inode->i_mode = inode_info->finfo.f_mode; inode->i_nlink = inode_info->finfo.f_nlink; inode->i_uid = inode_info->finfo.f_uid; inode->i_gid = inode_info->finfo.f_gid; inode->i_rdev = inode_info->finfo.f_rdev; inode->i_size = inode_info->finfo.f_size; inode->i_mtime = inode_info->finfo.f_mtime; inode->i_ctime = inode_info->finfo.f_ctime; inode->i_atime = inode_info->finfo.f_atime; inode->i_blksize = inode_info->finfo.f_blksize; inode->i_blocks = inode_info->finfo.f_blocks; if (S_ISREG(inode->i_mode)) { inode->i_op = &smb_file_inode_operations; } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &smb_dir_inode_operations; } else { inode->i_op = NULL; } } static void smb_put_inode(struct inode *inode) { struct smb_server *server = SMB_SERVER(inode); struct smb_inode_info *info = SMB_INOP(inode); __u32 mtime = inode->i_mtime; if (inode->i_count > 1) { printk("smb_put_inode: in use device %s, inode %ld count=%ld\n", kdevname(inode->i_dev), inode->i_ino, inode->i_count); return; } if (S_ISDIR(inode->i_mode)) { smb_invalid_dir_cache(inode->i_ino); } else { /* * Clear the length so the info structure can't be found. */ info->finfo.len = 0; } clear_inode(inode); /* * We don't want the inode to be reused as free if we block here, * so temporarily increment i_count. */ inode->i_count++; if (info) { if (info->finfo.opened != 0) { if (smb_proc_close(server, info->finfo.fileid, mtime)) { /* We can't do anything but complain. */ printk("smb_put_inode: could not close %s\n", info->finfo.name); } } smb_free_inode_info(info); } else printk("smb_put_inode: no inode info??\n"); inode->i_count--; } static void smb_put_super(struct super_block *sb) { struct smb_server *server = &(SMB_SBP(sb)->s_server); smb_proc_disconnect(server); smb_dont_catch_keepalive(server); close_fp(server->sock_file); lock_super(sb); smb_free_all_inodes(server); smb_vfree(server->packet); server->packet = NULL; sb->s_dev = 0; smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info)); unlock_super(sb); MOD_DEC_USE_COUNT; } struct smb_mount_data_v4 { int version; unsigned int fd; uid_t mounted_uid; struct sockaddr_in addr; char server_name[17]; char client_name[17]; char service[64]; char root_path[64]; char username[64]; char password[64]; unsigned short max_xmit; uid_t uid; gid_t gid; mode_t file_mode; mode_t dir_mode; }; static int smb_get_mount_data(struct smb_mount_data *target, void *source) { struct smb_mount_data_v4 *v4 = (struct smb_mount_data_v4 *) source; struct smb_mount_data *cur = (struct smb_mount_data *) source; if (source == NULL) { return 1; } if (cur->version == SMB_MOUNT_VERSION) { memcpy(target, cur, sizeof(struct smb_mount_data)); return 0; } if (v4->version == 4) { target->version = 5; target->fd = v4->fd; target->mounted_uid = v4->mounted_uid; target->addr = v4->addr; memcpy(target->server_name, v4->server_name, 17); memcpy(target->client_name, v4->client_name, 17); memcpy(target->service, v4->service, 64); memcpy(target->root_path, v4->root_path, 64); memcpy(target->username, v4->username, 64); memcpy(target->password, v4->password, 64); target->max_xmit = v4->max_xmit; target->uid = v4->uid; target->gid = v4->gid; target->file_mode = v4->file_mode; target->dir_mode = v4->dir_mode; memset(target->domain, 0, 64); strcpy(target->domain, "?"); return 0; } return 1; } struct super_block * smb_read_super(struct super_block *sb, void *raw_data, int silent) { struct smb_mount_data 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; MOD_INC_USE_COUNT; if (smb_get_mount_data(&data, raw_data) != 0) { printk("smb_read_super: wrong data argument\n"); sb->s_dev = 0; MOD_DEC_USE_COUNT; return NULL; } fd = data.fd; if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) { printk("smb_read_super: invalid file descriptor\n"); sb->s_dev = 0; MOD_DEC_USE_COUNT; return NULL; } if (!S_ISSOCK(filp->f_inode->i_mode)) { printk("smb_read_super: not a socket!\n"); sb->s_dev = 0; MOD_DEC_USE_COUNT; 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"); sb->s_dev = 0; MOD_DEC_USE_COUNT; 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); error = smb_proc_connect(server); unlock_super(sb); if (error < 0) { sb->s_dev = 0; DPRINTK("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"); goto fail; } smb_init_root_dirent(server, &(server->root.finfo)); if (!(sb->s_mounted = iget(sb, smb_info_ino(&(server->root))))) { sb->s_dev = 0; printk("smb_read_super: get root inode failed\n"); goto fail; } return sb; fail: if (server->packet != NULL) { smb_vfree(server->packet); server->packet = NULL; } filp->f_count -= 1; smb_dont_catch_keepalive(server); smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info)); MOD_DEC_USE_COUNT; return NULL; } static void smb_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) { int error; struct smb_dskattr attr; struct statfs tmp; error = smb_proc_dskattr(sb, &attr); if (error) { printk("smb_statfs: dskattr error = %d\n", -error); attr.total = attr.allocblocks = attr.blocksize = attr.free = 0; } tmp.f_type = SMB_SUPER_MAGIC; tmp.f_bsize = attr.blocksize * attr.allocblocks; tmp.f_blocks = attr.total; tmp.f_bfree = attr.free; tmp.f_bavail = attr.free; tmp.f_files = -1; tmp.f_ffree = -1; tmp.f_namelen = SMB_MAXPATHLEN; memcpy_tofs(buf, &tmp, bufsiz); } int smb_notify_change(struct inode *inode, struct iattr *attr) { int error = 0; if ((error = inode_change_ok(inode, attr)) < 0) return error; if (((attr->ia_valid & ATTR_UID) && (attr->ia_uid != SMB_SERVER(inode)->m.uid))) return -EPERM; if (((attr->ia_valid & ATTR_GID) && (attr->ia_gid != SMB_SERVER(inode)->m.gid))) return -EPERM; if (attr->ia_valid & ATTR_MODE) { struct smb_dirent *fold = SMB_FINFO(inode); struct smb_dirent finfo; if (attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)) return -EPERM; memset((char *)&finfo, 0, sizeof(finfo)); finfo.attr = fold->attr; if((attr->ia_mode & 0200) == 0) finfo.attr |= aRONLY; else finfo.attr &= ~aRONLY; if ((error = smb_proc_setattr(SMB_SERVER(inode), inode, &finfo)) >= 0) { fold->attr = finfo.attr; if ((attr->ia_mode & 0200) == 0) inode->i_mode &= ~0222; else inode->i_mode |= 0222; } } if ((attr->ia_valid & ATTR_SIZE) != 0) { if ((error = smb_make_open(inode, O_WRONLY)) < 0) goto fail; if ((error = smb_proc_trunc(SMB_SERVER(inode), SMB_FINFO(inode)->fileid, attr->ia_size)) < 0) goto fail; } /* ATTR_CTIME and ATTR_ATIME can not be set via SMB, so ignore it. */ if (attr->ia_valid & ATTR_MTIME) { if (smb_make_open(inode, O_WRONLY) != 0) error = -EACCES; else inode->i_mtime = attr->ia_mtime; } fail: smb_invalid_dir_cache(smb_info_ino(SMB_INOP(inode)->dir)); return error; } #ifdef DEBUG_SMB_MALLOC int smb_malloced; int smb_current_kmalloced; int smb_current_vmalloced; #endif static struct file_system_type smb_fs_type = { smb_read_super, "smbfs", 0, NULL }; int init_smb_fs(void) { return register_filesystem(&smb_fs_type); } #ifdef MODULE int init_module(void) { int status; DPRINTK("smbfs: init_module called\n"); #ifdef DEBUG_SMB_MALLOC smb_malloced = 0; smb_current_kmalloced = 0; smb_current_vmalloced = 0; #endif smb_init_dir_cache(); if ((status = init_smb_fs()) == 0) register_symtab(0); return status; } void cleanup_module(void) { DPRINTK("smbfs: cleanup_module called\n"); smb_free_dir_cache(); unregister_filesystem(&smb_fs_type); #ifdef DEBUG_SMB_MALLOC printk("smb_malloced: %d\n", smb_malloced); printk("smb_current_kmalloced: %d\n", smb_current_kmalloced); printk("smb_current_vmalloced: %d\n", smb_current_vmalloced); #endif } #endif