/* * inode.c * * Copyright (C) 1995 by Volker Lendecke * */ #include #ifdef MODULE #include #include #else #define MOD_INC_USE_COUNT #define MOD_DEC_USE_COUNT #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "ncplib.h" extern int close_fp(struct file *filp); static void ncp_put_inode(struct inode *); static void ncp_read_inode(struct inode *); static void ncp_put_super(struct super_block *); static int ncp_notify_change(struct inode *inode, struct iattr *attr); static struct super_operations ncp_sops = { ncp_read_inode, /* read inode */ ncp_notify_change, /* notify change */ NULL, /* write inode */ ncp_put_inode, /* put inode */ ncp_put_super, /* put superblock */ NULL, /* write superblock */ NULL, /* stat filesystem */ NULL }; /* ncp_read_inode: Called from iget, it only traverses the allocated ncp_inode_info's and initializes the inode from the data found there. It does not allocate or deallocate anything. */ static void ncp_read_inode(struct inode *inode) { /* Our task should be extremely simple here. We only have to look up the infomation somebody else (ncp_iget) put into the inode tree. The address of this information is the inode->i_ino. Just to make sure everything went well, we check it's there. */ struct ncp_inode_info *inode_info = (struct ncp_inode_info *)(inode->i_ino); #if 1 struct ncp_inode_info *root = &(NCP_SERVER(inode)->root); struct ncp_inode_info *check_info = root; do { if (inode_info == check_info) { if (check_info->state == INODE_LOOKED_UP) { DDPRINTK("ncp_read_inode: found it!\n"); goto good; } else { printk("ncp_read_inode: " "state != INODE_LOOKED_UP\n"); return; } } check_info = check_info->next; } while (check_info != root); /* Ok, now we're in trouble. The inode info is not there. What should we do now??? */ printk("ncp_read_inode: inode info not found\n"); return; good: #endif inode_info->state = INODE_VALID; NCP_INOP(inode) = inode_info; if (NCP_INOP(inode)->finfo.attr & aDIR) inode->i_mode = NCP_SERVER(inode)->m.dir_mode; else inode->i_mode = NCP_SERVER(inode)->m.file_mode; DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode); inode->i_nlink = 1; inode->i_uid = NCP_SERVER(inode)->m.uid; inode->i_gid = NCP_SERVER(inode)->m.gid; inode->i_size = NCP_INOP(inode)->finfo.size; inode->i_blksize = 1024; inode->i_rdev = 0; if ((inode->i_blksize != 0) && (inode->i_size != 0)) inode->i_blocks = (inode->i_size - 1) / inode->i_blksize + 1; else inode->i_blocks = 0; inode->i_mtime = NCP_INOP(inode)->finfo.mtime; inode->i_ctime = NCP_INOP(inode)->finfo.ctime; inode->i_atime = NCP_INOP(inode)->finfo.atime; if (S_ISREG(inode->i_mode)) inode->i_op = &ncp_file_inode_operations; else if (S_ISDIR(inode->i_mode)) inode->i_op = &ncp_dir_inode_operations; else inode->i_op = NULL; } static void ncp_put_inode(struct inode *inode) { struct ncp_dirent *finfo = NCP_FINFO(inode); if (finfo->opened != 0) { if (ncp_close_file(NCP_SERVER(inode), finfo->file_id) != 0) { /* We can't do anything but complain. */ printk("ncp_put_inode: could not close\n"); } } ncp_free_inode_info(NCP_INOP(inode)); if (S_ISDIR(inode->i_mode)) { DPRINTK("ncp_put_inode: put directory %ld\n", inode->i_ino); ncp_invalid_dir_cache(inode->i_ino); } clear_inode(inode); } struct super_block * ncp_read_super(struct super_block *sb, void *raw_data, int silent) { struct ncp_mount_data *data = (struct ncp_mount_data *) raw_data; struct ncp_server *server; struct file *ncp_filp; struct file *wdog_filp; kdev_t dev = sb->s_dev; int error; if (!data) { printk("ncp_read_super: missing data argument\n"); sb->s_dev = 0; return NULL; } if (data->version != NCP_MOUNT_VERSION) { printk("ncp warning: mount version %s than kernel\n", (data->version < NCP_MOUNT_VERSION) ? "older" : "newer"); } if ( (data->ncp_fd >= NR_OPEN) || ((ncp_filp = current->files->fd[data->ncp_fd]) == NULL) || (!S_ISSOCK(ncp_filp->f_inode->i_mode))) { printk("ncp_read_super: invalid ncp socket\n"); sb->s_dev = 0; return NULL; } if ( (data->wdog_fd >= NR_OPEN) || ((wdog_filp = current->files->fd[data->wdog_fd]) == NULL) || (!S_ISSOCK(wdog_filp->f_inode->i_mode))) { printk("ncp_read_super: invalid wdog socket\n"); sb->s_dev = 0; return NULL; } /* We must malloc our own super-block info */ server = (struct ncp_server *)ncp_kmalloc(sizeof(struct ncp_server), GFP_KERNEL); if (server == NULL) { printk("ncp_read_super: could not alloc ncp_server\n"); return NULL; } ncp_filp->f_count += 1; wdog_filp->f_count += 1; lock_super(sb); NCP_SBP(sb) = server; sb->s_blocksize = 1024; /* Eh... Is this correct? */ sb->s_blocksize_bits = 10; sb->s_magic = NCP_SUPER_MAGIC; sb->s_dev = dev; sb->s_op = &ncp_sops; server->ncp_filp = ncp_filp; server->wdog_filp = wdog_filp; server->lock = 0; server->wait = NULL; server->packet = NULL; server->buffer_size = 0; 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; server->packet_size = NCP_PACKET_SIZE; server->packet = ncp_kmalloc(NCP_PACKET_SIZE, GFP_KERNEL); if (server->packet == NULL) { printk("ncpfs: could not alloc packet\n"); error = -ENOMEM; unlock_super(sb); goto fail; } ncp_init_root(server); /* * Make the connection to the server */ if (ncp_catch_watchdog(server) != 0) { printk("ncp_read_super: Could not catch watchdog\n"); error = -EINVAL; unlock_super(sb); goto fail; } ncp_lock_server(server); error = ncp_connect(server); ncp_unlock_server(server); unlock_super(sb); if (error < 0) { sb->s_dev = 0; printk("ncp_read_super: Failed connection, bailing out " "(error = %d).\n", -error); ncp_kfree_s(server->packet, server->packet_size); ncp_dont_catch_watchdog(server); goto fail; } DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int)NCP_SBP(sb)); if (!(sb->s_mounted = iget(sb, (int)&(server->root)))) { sb->s_dev = 0; printk("ncp_read_super: get root inode failed\n"); goto disconnect; } if (ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE, &(server->buffer_size)) != 0) { sb->s_dev = 0; printk("ncp_read_super: could not get bufsize\n"); goto disconnect; } DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size); if (ncp_login_user(server, server->m.username, server->m.password) != 0) { sb->s_dev = 0; printk("ncp_read_super: login failed\n"); goto disconnect; } MOD_INC_USE_COUNT; return sb; disconnect: ncp_lock_server(server); ncp_disconnect(server); ncp_unlock_server(server); ncp_kfree_s(server->packet, server->packet_size); ncp_dont_catch_watchdog(server); fail: ncp_filp->f_count -= 1; wdog_filp->f_count -= 1; ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server)); return NULL; } static void ncp_put_super(struct super_block *sb) { struct ncp_server *server = NCP_SBP(sb); lock_super(sb); ncp_lock_server(server); ncp_disconnect(server); ncp_unlock_server(server); close_fp(server->ncp_filp); ncp_dont_catch_watchdog(server); close_fp(server->wdog_filp); ncp_free_all_inodes(server); ncp_kfree_s(server->packet, server->packet_size); sb->s_dev = 0; ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server)); NCP_SBP(sb) = NULL; unlock_super(sb); MOD_DEC_USE_COUNT; } /* DO MORE */ static int ncp_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 != NCP_SERVER(inode)->m.uid))) return -EPERM; if (((attr->ia_valid & ATTR_GID) && (attr->ia_uid != NCP_SERVER(inode)->m.gid))) return -EPERM; if (((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)))) return -EPERM; if ((attr->ia_valid & ATTR_SIZE) != 0) { struct ncp_file_info finfo; struct ncp_dirent *dirent = NCP_FINFO(inode); DPRINTK("ncpfs: trying to change size of %s to %ld\n", dirent->path, attr->ia_size); if (attr->ia_size != 0) { return -EPERM; } if (NCP_FINFO(inode)->opened != 0) { ncp_close_file(NCP_SERVER(inode), dirent->file_id); dirent->opened = 0; } if (ncp_create_file(NCP_SERVER(inode), 0, dirent->path, 0, &finfo) == 0) { ncp_close_file(NCP_SERVER(inode), finfo.file_id); dirent->opened = 0; } error = 0; } ncp_invalid_dir_cache((unsigned long)(NCP_INOP(inode)->dir)); return error; } #ifdef DEBUG_NCP_MALLOC int ncp_malloced; int ncp_current_malloced; #endif #ifdef MODULE char kernel_version[] = UTS_RELEASE; /* looks ugly, taken from gcc-info */ /* static void *shut_up_gcc = (&shut_up_gcc, kernel_version);*/ static struct file_system_type ncp_fs_type = { ncp_read_super, "ncpfs", 0, NULL }; int init_module( void) { DPRINTK("ncpfs: init_module called\n"); #ifdef DEBUG_NCP_MALLOC ncp_malloced = 0; ncp_current_malloced = 0; #endif ncp_init_dir_cache(); register_filesystem(&ncp_fs_type); return 0; } void cleanup_module(void) { DPRINTK("ncpfs: cleanup_module called\n"); ncp_free_dir_cache(); unregister_filesystem(&ncp_fs_type); #ifdef DEBUG_NCP_MALLOC printk("ncp_malloced: %d\n", ncp_malloced); printk("ncp_current_malloced: %d\n", ncp_current_malloced); #endif } #endif