int cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) { int rc = -EOPNOTSUPP; unsigned int xid; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink; struct cifs_tcon *pTcon; char *full_path = NULL; struct inode *newinode = NULL; xid = get_xid(); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { rc = PTR_ERR(tlink); goto symlink_exit; } pTcon = tlink_tcon(tlink); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; goto symlink_exit; } cifs_dbg(FYI, "Full path: %s\n", full_path); cifs_dbg(FYI, "symname is %s\n", symname); /* BB what if DFS and this volume is on different share? BB */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname); else if (pTcon->unix_ext) rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, cifs_sb->local_nls); /* else rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName, cifs_sb_target->local_nls); */ if (rc == 0) { if (pTcon->unix_ext) rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, xid); else rc = cifs_get_inode_info(&newinode, full_path, NULL, inode->i_sb, xid, NULL); if (rc != 0) { cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n", rc); } else { d_instantiate(direntry, newinode); } } symlink_exit: kfree(full_path); cifs_put_tlink(tlink); free_xid(xid); return rc; }
queue_stats_reply( body_type queue_stats , std::uint16_t const flags = 0 , std::uint32_t const xid = get_xid()) : basic_multipart_reply{flags, std::move(queue_stats), xid} { }
queue_stats_request( std::uint32_t const queue_id , std::uint32_t const port_no , std::uint32_t const xid = get_xid()) noexcept : basic_multipart_request{0, body_type{port_no, queue_id}, xid} { }
static int cifs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); struct TCP_Server_Info *server = tcon->ses->server; unsigned int xid; int rc = 0; xid = get_xid(); /* * PATH_MAX may be too long - it would presumably be total path, * but note that some servers (includinng Samba 3) have a shorter * maximum path. * * Instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO. */ buf->f_namelen = PATH_MAX; buf->f_files = 0; /* undefined */ buf->f_ffree = 0; /* unlimited */ if (server->ops->queryfs) rc = server->ops->queryfs(xid, tcon, buf); free_xid(xid); return 0; }
flow_removed( oxm_match match , std::uint16_t const priority , std::uint64_t const cookie , protocol::ofp_flow_removed_reason const reason , std::uint8_t const table_id , v13::elapsed_time const& elapsed_time , v13::timeouts const& timeouts , v13::counters const& counters , std::uint32_t const xid = get_xid()) : flow_removed_{ protocol::ofp_header{ version(), type(), match.calc_ofp_length(sizeof(ofp_type)), xid } , cookie , priority , std::uint8_t(reason) , table_id , elapsed_time.duration_sec() , elapsed_time.duration_nsec() , timeouts.idle_timeout() , timeouts.hard_timeout() , counters.packet_count() , counters.byte_count() } , match_(std::move(match)) { }
meter_config_reply( body_type meter_config , std::uint16_t const flags = 0 , std::uint32_t const xid = get_xid()) : basic_multipart_reply{flags, std::move(meter_config), xid} { }
int cifs_removexattr(struct dentry *direntry, const char *ea_name) { int rc = -EOPNOTSUPP; #ifdef CONFIG_CIFS_XATTR unsigned int xid; struct cifs_sb_info *cifs_sb; struct tcon_link *tlink; struct cifs_tcon *pTcon; struct super_block *sb; char *full_path = NULL; if (direntry == NULL) return -EIO; if (direntry->d_inode == NULL) return -EIO; sb = direntry->d_inode->i_sb; if (sb == NULL) return -EIO; cifs_sb = CIFS_SB(sb); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); pTcon = tlink_tcon(tlink); xid = get_xid(); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; goto remove_ea_exit; } if (ea_name == NULL) { cifs_dbg(FYI, "Null xattr names not supported\n"); } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN))) { cifs_dbg(FYI, "illegal xattr request %s (only user namespace supported)\n", ea_name); /* BB what if no namespace prefix? */ /* Should we just pass them to server, except for system and perhaps security prefixes? */ } else { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) goto remove_ea_exit; ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ if (pTcon->ses->server->ops->set_EA) rc = pTcon->ses->server->ops->set_EA(xid, pTcon, full_path, ea_name, NULL, (__u16)0, cifs_sb->local_nls, cifs_remap(cifs_sb)); } remove_ea_exit: kfree(full_path); free_xid(xid); cifs_put_tlink(tlink); #endif return rc; }
switch_config_base(ofp_config_flags const flags, std::uint16_t const miss_send_len , std::uint32_t const xid = get_xid()) : config_{ {OFP_VERSION, T::message_type, sizeof(config_), xid} , std::uint16_t(flags), miss_send_len } { }
packet_out(std::vector<std::uint8_t> data, std::uint16_t const in_port , action_list actions, std::uint32_t const xid = get_xid()) : packet_out{ OFP_NO_BUFFER, in_port , std::move(actions), std::move(data), xid } { }
const char * cifs_get_link(struct dentry *direntry, struct inode *inode, struct delayed_call *done) { int rc = -ENOMEM; unsigned int xid; char *full_path = NULL; char *target_path = NULL; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink = NULL; struct cifs_tcon *tcon; struct TCP_Server_Info *server; if (!direntry) return ERR_PTR(-ECHILD); xid = get_xid(); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { free_xid(xid); return ERR_CAST(tlink); } tcon = tlink_tcon(tlink); server = tcon->ses->server; full_path = build_path_from_dentry(direntry); if (!full_path) { free_xid(xid); cifs_put_tlink(tlink); return ERR_PTR(-ENOMEM); } cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, inode); rc = -EACCES; /* * First try Minshall+French Symlinks, if configured * and fallback to UNIX Extensions Symlinks. */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) rc = query_mf_symlink(xid, tcon, cifs_sb, full_path, &target_path); if (rc != 0 && server->ops->query_symlink) rc = server->ops->query_symlink(xid, tcon, full_path, &target_path, cifs_sb); kfree(full_path); free_xid(xid); cifs_put_tlink(tlink); if (rc != 0) { kfree(target_path); return ERR_PTR(rc); } set_delayed_call(done, kfree_link, target_path); return target_path; }
void * cifs_follow_link(struct dentry *direntry, struct nameidata *nd) { struct inode *inode = d_inode(direntry); int rc = -ENOMEM; unsigned int xid; char *full_path = NULL; char *target_path = NULL; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink = NULL; struct cifs_tcon *tcon; struct TCP_Server_Info *server; xid = get_xid(); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { rc = PTR_ERR(tlink); tlink = NULL; goto out; } tcon = tlink_tcon(tlink); server = tcon->ses->server; full_path = build_path_from_dentry(direntry); if (!full_path) goto out; cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, inode); rc = -EACCES; /* * First try Minshall+French Symlinks, if configured * and fallback to UNIX Extensions Symlinks. */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) rc = query_mf_symlink(xid, tcon, cifs_sb, full_path, &target_path); if (rc != 0 && server->ops->query_symlink) rc = server->ops->query_symlink(xid, tcon, full_path, &target_path, cifs_sb); kfree(full_path); out: if (rc != 0) { kfree(target_path); target_path = ERR_PTR(rc); } free_xid(xid); if (tlink) cifs_put_tlink(tlink); nd_set_link(nd, target_path); return NULL; }
int main(int argc, char **argv){ dub_init(); dub_dbg("IXICON! >> %s", argv[1]); load_ixicon(argv[1]); dub_dbg("IX <%s> XID <%u>", argv[2], get_xid(argv[2])); }
explicit flow_delete_strict( flow_entry const& entry , std::uint16_t const out_port = OFPP_NONE , std::uint32_t const xid = get_xid()) : flow_mod_{ {OFP_VERSION, message_type, sizeof(flow_mod_), xid} , entry.ofp_match(), 0, command_type, 0, 0 , entry.priority(), 0, out_port, 0 } { }
ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) { ssize_t rc = -EOPNOTSUPP; #ifdef CONFIG_CIFS_XATTR unsigned int xid; struct cifs_sb_info *cifs_sb; struct tcon_link *tlink; struct cifs_tcon *pTcon; struct super_block *sb; char *full_path; if (direntry == NULL) return -EIO; if (direntry->d_inode == NULL) return -EIO; sb = direntry->d_inode->i_sb; if (sb == NULL) return -EIO; cifs_sb = CIFS_SB(sb); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) return -EOPNOTSUPP; tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); pTcon = tlink_tcon(tlink); xid = get_xid(); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; goto list_ea_exit; } /* return dos attributes as pseudo xattr */ /* return alt name if available as pseudo attr */ /* if proc/fs/cifs/streamstoxattr is set then search server for EAs or streams to returns as xattrs */ if (pTcon->ses->server->ops->query_all_EAs) rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, full_path, NULL, data, buf_size, cifs_sb->local_nls, cifs_remap(cifs_sb)); list_ea_exit: kfree(full_path); free_xid(xid); cifs_put_tlink(tlink); #endif return rc; }
static int cifs_clone_file_range(struct file *src_file, loff_t off, struct file *dst_file, loff_t destoff, u64 len) { struct inode *src_inode = file_inode(src_file); struct inode *target_inode = file_inode(dst_file); struct cifsFileInfo *smb_file_src = src_file->private_data; struct cifsFileInfo *smb_file_target = dst_file->private_data; struct cifs_tcon *target_tcon = tlink_tcon(smb_file_target->tlink); unsigned int xid; int rc; cifs_dbg(FYI, "clone range\n"); xid = get_xid(); if (!src_file->private_data || !dst_file->private_data) { rc = -EBADF; cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n"); goto out; } /* * Note: cifs case is easier than btrfs since server responsible for * checks for proper open modes and file type and if it wants * server could even support copy of range where source = target */ lock_two_nondirectories(target_inode, src_inode); if (len == 0) len = src_inode->i_size - off; cifs_dbg(FYI, "about to flush pages\n"); /* should we flush first and last page first */ truncate_inode_pages_range(&target_inode->i_data, destoff, PAGE_ALIGN(destoff + len)-1); if (target_tcon->ses->server->ops->duplicate_extents) rc = target_tcon->ses->server->ops->duplicate_extents(xid, smb_file_src, smb_file_target, off, len, destoff); else rc = -EOPNOTSUPP; /* force revalidate of size and timestamps of target file now that target is updated on the server */ CIFS_I(target_inode)->time = 0; /* although unlocking in the reverse order from locking is not strictly necessary here it is a little cleaner to be consistent */ unlock_two_nondirectories(src_inode, target_inode); out: free_xid(xid); return rc; }
flow_add( flow_entry entry , std::uint16_t const flags = 0 , std::uint32_t const buffer_id = protocol::OFP_NO_BUFFER , std::uint32_t const xid = get_xid()) : flow_add{ entry.id().match(), entry.id().priority() , entry.cookie() , std::move(entry).actions() , v10::timeouts{0, 0}, flags, buffer_id, xid } { }
flow_delete_strict( match_set const& match, std::uint16_t const priority , std::uint16_t const out_port = OFPP_NONE , std::uint32_t const xid = get_xid()) : flow_mod_{ v10_detail::ofp_header{ OFP_VERSION, message_type, sizeof(flow_mod_), xid } , match.ofp_match(), 0, command_type, 0, 0 , priority, 0, out_port, 0 } { }
/* Set an ACL on the server */ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, struct inode *inode, const char *path, int aclflag) { int oplock = 0; unsigned int xid; int rc, access_flags, create_options = 0; struct cifs_tcon *tcon; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); struct cifs_fid fid; struct cifs_open_parms oparms; if (IS_ERR(tlink)) return PTR_ERR(tlink); tcon = tlink_tcon(tlink); xid = get_xid(); if (backup_cred(cifs_sb)) create_options |= CREATE_OPEN_BACKUP_INTENT; if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP) access_flags = WRITE_OWNER; else access_flags = WRITE_DAC; oparms.tcon = tcon; oparms.cifs_sb = cifs_sb; oparms.desired_access = access_flags; oparms.share_access = FILE_SHARE_ALL; oparms.create_options = create_options; oparms.disposition = FILE_OPEN; oparms.path = path; oparms.fid = &fid; oparms.reconnect = false; rc = CIFS_open(xid, &oparms, &oplock, NULL); if (rc) { cifs_dbg(VFS, "Unable to open file to set ACL\n"); goto out; } rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag); cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc); CIFSSMBClose(xid, tcon, fid.netfid); out: free_xid(xid); cifs_put_tlink(tlink); return rc; }
static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, u32 *pacllen) { struct cifs_ntsd *pntsd = NULL; int oplock = 0; unsigned int xid; int rc, create_options = 0; struct cifs_tcon *tcon; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); struct cifs_fid fid; struct cifs_open_parms oparms; if (IS_ERR(tlink)) return ERR_CAST(tlink); tcon = tlink_tcon(tlink); xid = get_xid(); if (backup_cred(cifs_sb)) create_options |= CREATE_OPEN_BACKUP_INTENT; oparms.tcon = tcon; oparms.cifs_sb = cifs_sb; oparms.desired_access = READ_CONTROL; oparms.share_access = FILE_SHARE_ALL; oparms.create_options = create_options; oparms.disposition = FILE_OPEN; oparms.path = path; oparms.fid = &fid; oparms.reconnect = false; rc = CIFS_open(xid, &oparms, &oplock, NULL); if (!rc) { rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen); CIFSSMBClose(xid, tcon, fid.netfid); } cifs_put_tlink(tlink); free_xid(xid); cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen); if (rc) return ERR_PTR(rc); return pntsd; }
int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, bool excl) { int rc; unsigned int xid = get_xid(); /* * BB below access is probably too much for mknod to request * but we have to do query and setpathinfo so requesting * less could fail (unless we want to request getatr and setatr * permissions (only). At least for POSIX we do not have to * request so much. */ unsigned oflags = O_EXCL | O_CREAT | O_RDWR; struct tcon_link *tlink; struct cifs_tcon *tcon; struct TCP_Server_Info *server; struct cifs_fid fid; __u32 oplock; int created = FILE_CREATED; cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %s and dentry = 0x%p\n", inode, direntry->d_name.name, direntry); tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb)); rc = PTR_ERR(tlink); if (IS_ERR(tlink)) goto out_free_xid; tcon = tlink_tcon(tlink); server = tcon->ses->server; if (server->ops->new_lease_key) server->ops->new_lease_key(&fid); rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, &oplock, &fid, &created); if (!rc && server->ops->close) server->ops->close(xid, tcon, &fid); cifs_put_tlink(tlink); out_free_xid: free_xid(xid); return rc; }
/* Set an ACL on the server */ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, struct inode *inode, const char *path, int aclflag) { int oplock = 0; unsigned int xid; int rc, access_flags, create_options = 0; __u16 fid; struct cifs_tcon *tcon; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); tcon = tlink_tcon(tlink); xid = get_xid(); if (backup_cred(cifs_sb)) create_options |= CREATE_OPEN_BACKUP_INTENT; if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP) access_flags = WRITE_OWNER; else access_flags = WRITE_DAC; rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags, create_options, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { cERROR(1, "Unable to open file to set ACL"); goto out; } rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag); cFYI(DBG2, "SetCIFSACL rc = %d", rc); CIFSSMBClose(xid, tcon, fid); out: free_xid(xid); cifs_put_tlink(tlink); return rc; }
flow_removed( flow_entry entry , protocol::ofp_flow_removed_reason const reason , std::uint8_t const table_id , v13::elapsed_time const& elapsed_time , v13::timeouts const& timeouts , v13::counters const& counters , std::uint32_t const xid = get_xid()) : flow_removed{ std::move(entry).match() , entry.priority(), entry.cookie() , reason , table_id , elapsed_time , timeouts , counters , xid } { }
meter_features_reply( std::uint32_t const max_meter , std::uint32_t const band_types , std::uint32_t const capabilities , std::uint8_t const max_bands , std::uint8_t const max_color , std::uint32_t const xid = get_xid()) noexcept : basic_multipart_reply{ 0 , body_type{ max_meter , band_types , capabilities , max_bands , max_color , { 0, 0 } } , xid } { }
flow_add( v10::match const& match , std::uint16_t const priority , std::uint64_t const cookie , action_list actions , v10::timeouts const& timeouts , std::uint16_t const flags = 0 , std::uint32_t const buffer_id = protocol::OFP_NO_BUFFER , std::uint32_t const xid = get_xid()) : flow_mod_base{ match , priority , cookie , std::move(actions) , timeouts.idle_timeout() , timeouts.hard_timeout() , flags , buffer_id , xid } { }
static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid, u32 *pacllen) { struct cifs_ntsd *pntsd = NULL; unsigned int xid; int rc; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return ERR_CAST(tlink); xid = get_xid(); rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen); free_xid(xid); cifs_put_tlink(tlink); cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen); if (rc) return ERR_PTR(rc); return pntsd; }
int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, bool excl) { int rc; unsigned int xid = get_xid(); /* * BB below access is probably too much for mknod to request * but we have to do query and setpathinfo so requesting * less could fail (unless we want to request getatr and setatr * permissions (only). At least for POSIX we do not have to * request so much. */ unsigned oflags = O_EXCL | O_CREAT | O_RDWR; struct tcon_link *tlink; __u16 fileHandle; __u32 oplock; int created = FILE_CREATED; cFYI(1, "cifs_create parent inode = 0x%p name is: %s and dentry = 0x%p", inode, direntry->d_name.name, direntry); tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb)); rc = PTR_ERR(tlink); if (IS_ERR(tlink)) goto out_free_xid; rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, &oplock, &fileHandle, &created); if (!rc) CIFSSMBClose(xid, tlink_tcon(tlink), fileHandle); cifs_put_tlink(tlink); out_free_xid: free_xid(xid); return rc; }
static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, u32 *pacllen) { struct cifs_ntsd *pntsd = NULL; int oplock = 0; unsigned int xid; int rc, create_options = 0; __u16 fid; struct cifs_tcon *tcon; struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return ERR_CAST(tlink); tcon = tlink_tcon(tlink); xid = get_xid(); if (backup_cred(cifs_sb)) create_options |= CREATE_OPEN_BACKUP_INTENT; rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, create_options, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); CIFSSMBClose(xid, tcon, fid); } cifs_put_tlink(tlink); free_xid(xid); cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen); if (rc) return ERR_PTR(rc); return pntsd; }
/* * Create a vfsmount that we can automount */ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) { struct dfs_info3_param *referrals = NULL; unsigned int num_referrals = 0; struct cifs_sb_info *cifs_sb; struct cifs_ses *ses; char *full_path; unsigned int xid; int i; int rc; struct vfsmount *mnt; struct tcon_link *tlink; cifs_dbg(FYI, "in %s\n", __func__); BUG_ON(IS_ROOT(mntpt)); /* * The MSDFS spec states that paths in DFS referral requests and * responses must be prefixed by a single '\' character instead of * the double backslashes usually used in the UNC. This function * gives us the latter, so we must adjust the result. */ mnt = ERR_PTR(-ENOMEM); full_path = build_path_from_dentry(mntpt); if (full_path == NULL) goto cdda_exit; cifs_sb = CIFS_SB(d_inode(mntpt)->i_sb); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { mnt = ERR_CAST(tlink); goto free_full_path; } ses = tlink_tcon(tlink)->ses; xid = get_xid(); rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls, &num_referrals, &referrals, cifs_remap(cifs_sb)); free_xid(xid); cifs_put_tlink(tlink); mnt = ERR_PTR(-ENOENT); for (i = 0; i < num_referrals; i++) { int len; dump_referral(referrals + i); /* connect to a node */ len = strlen(referrals[i].node_name); if (len < 2) { cifs_dbg(VFS, "%s: Net Address path too short: %s\n", __func__, referrals[i].node_name); mnt = ERR_PTR(-EINVAL); break; } mnt = cifs_dfs_do_refmount(cifs_sb, full_path, referrals + i); cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n", __func__, referrals[i].node_name, mnt); if (!IS_ERR(mnt)) goto success; } /* no valid submounts were found; return error from get_dfs_path() by * preference */ if (rc != 0) mnt = ERR_PTR(rc); success: free_dfs_info_array(referrals, num_referrals); free_full_path: kfree(full_path); cdda_exit: cifs_dbg(FYI, "leaving %s\n" , __func__); return mnt; }
struct dentry * cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, unsigned int flags) { unsigned int xid; int rc = 0; /* to get around spurious gcc warning, set to zero here */ struct cifs_sb_info *cifs_sb; struct tcon_link *tlink; struct cifs_tcon *pTcon; struct inode *newInode = NULL; char *full_path = NULL; xid = get_xid(); cifs_dbg(FYI, "parent inode = 0x%p name is: %s and dentry = 0x%p\n", parent_dir_inode, direntry->d_name.name, direntry); /* check whether path exists */ cifs_sb = CIFS_SB(parent_dir_inode->i_sb); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { free_xid(xid); return (struct dentry *)tlink; } pTcon = tlink_tcon(tlink); rc = check_name(direntry); if (rc) goto lookup_out; /* can not grab the rename sem here since it would deadlock in the cases (beginning of sys_rename itself) in which we already have the sb rename sem */ full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; goto lookup_out; } if (direntry->d_inode != NULL) { cifs_dbg(FYI, "non-NULL inode in lookup\n"); } else { cifs_dbg(FYI, "NULL inode in lookup\n"); } cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, direntry->d_inode); if (pTcon->unix_ext) { rc = cifs_get_inode_info_unix(&newInode, full_path, parent_dir_inode->i_sb, xid); } else { rc = cifs_get_inode_info(&newInode, full_path, NULL, parent_dir_inode->i_sb, xid, NULL); } if ((rc == 0) && (newInode != NULL)) { d_add(direntry, newInode); /* since paths are not looked up by component - the parent directories are presumed to be good here */ renew_parental_timestamps(direntry); } else if (rc == -ENOENT) { rc = 0; direntry->d_time = jiffies; d_add(direntry, NULL); /* if it was once a directory (but how can we tell?) we could do shrink_dcache_parent(direntry); */ } else if (rc != -EACCES) { cifs_dbg(VFS, "Unexpected lookup error %d\n", rc); /* We special case check for Access Denied - since that is a common return code */ } lookup_out: kfree(full_path); cifs_put_tlink(tlink); free_xid(xid); return ERR_PTR(rc); }
int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, dev_t device_number) { int rc = -EPERM; unsigned int xid; int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL; struct cifs_sb_info *cifs_sb; struct tcon_link *tlink; struct cifs_tcon *pTcon; struct cifs_io_parms io_parms; char *full_path = NULL; struct inode *newinode = NULL; int oplock = 0; u16 fileHandle; FILE_ALL_INFO *buf = NULL; unsigned int bytes_written; struct win_dev *pdev; if (!old_valid_dev(device_number)) return -EINVAL; cifs_sb = CIFS_SB(inode->i_sb); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); pTcon = tlink_tcon(tlink); xid = get_xid(); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; goto mknod_out; } if (pTcon->unix_ext) { struct cifs_unix_set_info_args args = { .mode = mode & ~current_umask(), .ctime = NO_CHANGE_64, .atime = NO_CHANGE_64, .mtime = NO_CHANGE_64, .device = device_number, }; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { args.uid = current_fsuid(); args.gid = current_fsgid(); } else { args.uid = INVALID_UID; /* no change */ args.gid = INVALID_GID; /* no change */ } rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) goto mknod_out; rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, xid); if (rc == 0) d_instantiate(direntry, newinode); goto mknod_out; } if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) goto mknod_out; cifs_dbg(FYI, "sfu compat create special file\n"); buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); if (buf == NULL) { kfree(full_path); rc = -ENOMEM; free_xid(xid); return rc; } if (backup_cred(cifs_sb)) create_options |= CREATE_OPEN_BACKUP_INTENT; rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE, GENERIC_WRITE, create_options, &fileHandle, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) goto mknod_out; /* BB Do not bother to decode buf since no local inode yet to put * timestamps in, but we can reuse it safely */ pdev = (struct win_dev *)buf; io_parms.netfid = fileHandle; io_parms.pid = current->tgid; io_parms.tcon = pTcon; io_parms.offset = 0; io_parms.length = sizeof(struct win_dev); if (S_ISCHR(mode)) { memcpy(pdev->type, "IntxCHR", 8); pdev->major = cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number)); rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, NULL, 0); } else if (S_ISBLK(mode)) { memcpy(pdev->type, "IntxBLK", 8); pdev->major = cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number)); rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, NULL, 0); } /* else if (S_ISFIFO) */ CIFSSMBClose(xid, pTcon, fileHandle); d_drop(direntry); /* FIXME: add code here to set EAs */ mknod_out: kfree(full_path); kfree(buf); free_xid(xid); cifs_put_tlink(tlink); return rc; }