static int smb_dir_open(struct inode *dir, struct file *file) { struct dentry *dentry = file->f_path.dentry; struct smb_sb_info *server; int error = 0; VERBOSE("(%s/%s)\n", dentry->d_parent->d_name.name, file->f_path.dentry->d_name.name); /* * Directory timestamps in the core protocol aren't updated * when a file is added, so we give them a very short TTL. */ lock_kernel(); server = server_from_dentry(dentry); if (server->opt.protocol < SMB_PROTOCOL_LANMAN2) { unsigned long age = jiffies - SMB_I(dir)->oldmtime; if (age > 2*HZ) smb_invalid_dir_cache(dir); } /* * Note: in order to allow the smbmount process to open the * mount point, we only revalidate if the connection is valid or * if the process is trying to access something other than the root. */ if (server->state == CONN_VALID || !IS_ROOT(dentry)) error = smb_revalidate_inode(dentry); unlock_kernel(); return error; }
/* * Note: in order to allow the smbclient process to open the * mount point, we don't revalidate if conn_pid is NULL. */ static int smb_dir_open(struct inode *dir, struct file *file) { struct dentry *dentry = file->f_dentry; struct smb_sb_info *server = server_from_dentry(dentry); int error = 0; #ifdef SMBFS_DEBUG_VERBOSE printk("smb_dir_open: (%s/%s)\n", dentry->d_parent->d_name.name, file->f_dentry->d_name.name); #endif /* * Directory timestamps in the core protocol aren't updated * when a file is added, so we give them a very short TTL. */ if (server->opt.protocol < SMB_PROTOCOL_LANMAN2) { unsigned long age = jiffies - dir->u.smbfs_i.oldmtime; if (age > 2*HZ) smb_invalid_dir_cache(dir); } if (server->conn_pid) error = smb_revalidate_inode(dentry); return error; }
int smb_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) { DEBUG1("create symlink %s -> %s/%s\n", oldname, DENTRY_PATH(dentry)); smb_invalid_dir_cache(dir); return smb_proc_symlink(server_from_dentry(dentry), dentry, oldname); }
/* * This is called to update the inode attributes after * we've made changes to a file or directory. */ static int smb_refresh_inode(struct dentry *dentry) { struct inode *inode = dentry->d_inode; int error; struct smb_fattr fattr; error = smb_proc_getattr(dentry, &fattr); if (!error) { smb_renew_times(dentry); /* * Check whether the type part of the mode changed, * and don't update the attributes if it did. * * And don't dick with the root inode */ if (inode->i_ino == 2) return error; if (S_ISLNK(inode->i_mode)) return error; /* VFS will deal with it */ if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) { smb_set_inode_attr(inode, &fattr); } else { /* * Big trouble! The inode has become a new object, * so any operations attempted on it are invalid. * * To limit damage, mark the inode as bad so that * subsequent lookup validations will fail. */ PARANOIA("%s/%s changed mode, %07o to %07o\n", DENTRY_PATH(dentry), inode->i_mode, fattr.f_mode); fattr.f_mode = inode->i_mode; /* save mode */ make_bad_inode(inode); inode->i_mode = fattr.f_mode; /* restore mode */ /* * No need to worry about unhashing the dentry: the * lookup validation will see that the inode is bad. * But we do want to invalidate the caches ... */ if (!S_ISDIR(inode->i_mode)) invalidate_remote_inode(inode); else smb_invalid_dir_cache(inode); error = -EIO; } } return error; }
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; }
static int smb_mkdir(struct inode *dir, const char *name, int len, int mode) { int error; if (!dir || !S_ISDIR(dir->i_mode)) { iput(dir); return -EINVAL; } if ((error = smb_proc_mkdir(dir, name, len)) == 0) { smb_invalid_dir_cache(dir->i_ino); } iput(dir); return error; }
static int smb_refill_dir_cache(struct smb_server *server, struct inode *dir, unsigned long f_pos) { int result; static struct semaphore sem = MUTEX; int i; ino_t ino; do { down(&sem); result = smb_proc_readdir(server, dir, f_pos, SMB_READDIR_CACHE_SIZE, c_entry); if (result <= 0) { smb_invalid_dir_cache(dir->i_ino); up(&sem); return result; } c_seen_eof = (result < SMB_READDIR_CACHE_SIZE); c_dev = dir->i_dev; c_ino = dir->i_ino; c_size = result; c_last_returned_index = 0; ino = smb_fresh_inodes(server, c_size); for (i = 0; i < c_size; i++) { c_entry[i].f_ino = ino; ino += 1; } up(&sem); } while ((c_dev != dir->i_dev) || (c_ino != dir->i_ino)); return result; }
static int smb_unlink(struct inode *dir, const char *name, int len) { int error; if (!dir || !S_ISDIR(dir->i_mode)) { printk("smb_unlink: inode is NULL or not a directory\n"); iput(dir); return -ENOENT; } if (smb_find_dir_inode(dir, name, len) != NULL) { error = -EBUSY; } else { if ((error = smb_proc_unlink(dir, name, len)) == 0) { smb_invalid_dir_cache(dir->i_ino); } } iput(dir); return error; }
/* DO MORE */ 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_uid != SMB_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) { 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; } if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0) { struct smb_dirent finfo; finfo.attr = 0; if ((attr->ia_valid & ATTR_CTIME) != 0) finfo.ctime = attr->ia_ctime; else finfo.ctime = inode->i_ctime; if ((attr->ia_valid & ATTR_MTIME) != 0) finfo.mtime = attr->ia_mtime; else finfo.mtime = inode->i_mtime; if ((attr->ia_valid & ATTR_ATIME) != 0) finfo.atime = attr->ia_atime; else finfo.atime = inode->i_atime; if ((error = smb_proc_setattr(SMB_SERVER(inode), inode, &finfo)) >= 0) { inode->i_ctime = finfo.ctime; inode->i_mtime = finfo.mtime; inode->i_atime = finfo.atime; } } fail: smb_invalid_dir_cache((unsigned long)(SMB_INOP(inode)->dir)); return error; }