📄 proc.c
字号:
ts.tv_nsec = do_div(t, 10000000) * 100; ts.tv_sec = t; return ts;}/* Convert the Unix UTC into NT time */static u64smb_unixutc2ntutc(struct timespec ts){ /* Note: timezone conversion is probably wrong. */ /* return ((u64)utc2local(server, t)) * 10000000 + NTFS_TIME_OFFSET; */ return ((u64)ts.tv_sec) * 10000000 + ts.tv_nsec/100 + NTFS_TIME_OFFSET;}#define MAX_FILE_MODE 6static mode_t file_mode[] = { S_IFREG, S_IFDIR, S_IFLNK, S_IFCHR, S_IFBLK, S_IFIFO, S_IFSOCK};static int smb_filetype_to_mode(u32 filetype){ if (filetype > MAX_FILE_MODE) { PARANOIA("Filetype out of range: %d\n", filetype); return S_IFREG; } return file_mode[filetype];}static u32 smb_filetype_from_mode(int mode){ if (S_ISREG(mode)) return UNIX_TYPE_FILE; if (S_ISDIR(mode)) return UNIX_TYPE_DIR; if (S_ISLNK(mode)) return UNIX_TYPE_SYMLINK; if (S_ISCHR(mode)) return UNIX_TYPE_CHARDEV; if (S_ISBLK(mode)) return UNIX_TYPE_BLKDEV; if (S_ISFIFO(mode)) return UNIX_TYPE_FIFO; if (S_ISSOCK(mode)) return UNIX_TYPE_SOCKET; return UNIX_TYPE_UNKNOWN;}/*****************************************************************************//* *//* Support section. *//* *//*****************************************************************************/__u32smb_len(__u8 * p){ return ((*(p+1) & 0x1) << 16L) | (*(p+2) << 8L) | *(p+3);}static __u16smb_bcc(__u8 * packet){ int pos = SMB_HEADER_LEN + SMB_WCT(packet) * sizeof(__u16); return WVAL(packet, pos);}/* smb_valid_packet: We check if packet fulfills the basic requirements of a smb packet */static intsmb_valid_packet(__u8 * packet){ return (packet[4] == 0xff && packet[5] == 'S' && packet[6] == 'M' && packet[7] == 'B' && (smb_len(packet) + 4 == SMB_HEADER_LEN + SMB_WCT(packet) * 2 + smb_bcc(packet)));}/* smb_verify: We check if we got the answer we expected, and if we got enough data. If bcc == -1, we don't care. */static intsmb_verify(__u8 * packet, int command, int wct, int bcc){ if (SMB_CMD(packet) != command) goto bad_command; if (SMB_WCT(packet) < wct) goto bad_wct; if (bcc != -1 && smb_bcc(packet) < bcc) goto bad_bcc; return 0;bad_command: printk(KERN_ERR "smb_verify: command=%x, SMB_CMD=%x??\n", command, SMB_CMD(packet)); goto fail;bad_wct: printk(KERN_ERR "smb_verify: command=%x, wct=%d, SMB_WCT=%d??\n", command, wct, SMB_WCT(packet)); goto fail;bad_bcc: printk(KERN_ERR "smb_verify: command=%x, bcc=%d, SMB_BCC=%d??\n", command, bcc, smb_bcc(packet));fail: return -EIO;}/* * Returns the maximum read or write size for the "payload". Making all of the * packet fit within the negotiated max_xmit size. * * N.B. Since this value is usually computed before locking the server, * the server's packet size must never be decreased! */static inline intsmb_get_xmitsize(struct smb_sb_info *server, int overhead){ return server->opt.max_xmit - overhead;}/* * Calculate the maximum read size */intsmb_get_rsize(struct smb_sb_info *server){ /* readX has 12 parameters, read has 5 */ int overhead = SMB_HEADER_LEN + 12 * sizeof(__u16) + 2 + 1 + 2; int size = smb_get_xmitsize(server, overhead); VERBOSE("xmit=%d, size=%d\n", server->opt.max_xmit, size); return size;}/* * Calculate the maximum write size */intsmb_get_wsize(struct smb_sb_info *server){ /* writeX has 14 parameters, write has 5 */ int overhead = SMB_HEADER_LEN + 14 * sizeof(__u16) + 2 + 1 + 2; int size = smb_get_xmitsize(server, overhead); VERBOSE("xmit=%d, size=%d\n", server->opt.max_xmit, size); return size;}/* * Convert SMB error codes to -E... errno values. */intsmb_errno(struct smb_request *req){ int errcls = req->rq_rcls; int error = req->rq_err; char *class = "Unknown"; VERBOSE("errcls %d code %d from command 0x%x\n", errcls, error, SMB_CMD(req->rq_header)); if (errcls == ERRDOS) { switch (error) { case ERRbadfunc: return -EINVAL; case ERRbadfile: case ERRbadpath: return -ENOENT; case ERRnofids: return -EMFILE; case ERRnoaccess: return -EACCES; case ERRbadfid: return -EBADF; case ERRbadmcb: return -EREMOTEIO; case ERRnomem: return -ENOMEM; case ERRbadmem: return -EFAULT; case ERRbadenv: case ERRbadformat: return -EREMOTEIO; case ERRbadaccess: return -EACCES; case ERRbaddata: return -E2BIG; case ERRbaddrive: return -ENXIO; case ERRremcd: return -EREMOTEIO; case ERRdiffdevice: return -EXDEV; case ERRnofiles: return -ENOENT; case ERRbadshare: return -ETXTBSY; case ERRlock: return -EDEADLK; case ERRfilexists: return -EEXIST; case ERROR_INVALID_PARAMETER: return -EINVAL; case ERROR_DISK_FULL: return -ENOSPC; case ERROR_INVALID_NAME: return -ENOENT; case ERROR_DIR_NOT_EMPTY: return -ENOTEMPTY; case ERROR_NOT_LOCKED: return -ENOLCK; case ERROR_ALREADY_EXISTS: return -EEXIST; default: class = "ERRDOS"; goto err_unknown; } } else if (errcls == ERRSRV) { switch (error) { /* N.B. This is wrong ... EIO ? */ case ERRerror: return -ENFILE; case ERRbadpw: return -EINVAL; case ERRbadtype: case ERRtimeout: return -EIO; case ERRaccess: return -EACCES; /* * This is a fatal error, as it means the "tree ID" * for this connection is no longer valid. We map * to a special error code and get a new connection. */ case ERRinvnid: return -EBADSLT; default: class = "ERRSRV"; goto err_unknown; } } else if (errcls == ERRHRD) { switch (error) { case ERRnowrite: return -EROFS; case ERRbadunit: return -ENODEV; case ERRnotready: return -EUCLEAN; case ERRbadcmd: case ERRdata: return -EIO; case ERRbadreq: return -ERANGE; case ERRbadshare: return -ETXTBSY; case ERRlock: return -EDEADLK; case ERRdiskfull: return -ENOSPC; default: class = "ERRHRD"; goto err_unknown; } } else if (errcls == ERRCMD) { class = "ERRCMD"; } else if (errcls == SUCCESS) { return 0; /* This is the only valid 0 return */ }err_unknown: printk(KERN_ERR "smb_errno: class %s, code %d from command 0x%x\n", class, error, SMB_CMD(req->rq_header)); return -EIO;}/* smb_request_ok: We expect the server to be locked. Then we do the request and check the answer completely. When smb_request_ok returns 0, you can be quite sure that everything went well. When the answer is <=0, the returned number is a valid unix errno. */static intsmb_request_ok(struct smb_request *req, int command, int wct, int bcc){ int result; req->rq_resp_wct = wct; req->rq_resp_bcc = bcc; result = smb_add_request(req); if (result != 0) { DEBUG1("smb_request failed\n"); goto out; } if (smb_valid_packet(req->rq_header) != 0) { PARANOIA("invalid packet!\n"); goto out; } result = smb_verify(req->rq_header, command, wct, bcc);out: return result;}/* * This implements the NEWCONN ioctl. It installs the server pid, * sets server->state to CONN_VALID, and wakes up the waiting process. */intsmb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt){ struct file *filp; struct sock *sk; int error; VERBOSE("fd=%d, pid=%d\n", opt->fd, current->pid); smb_lock_server(server); /* * Make sure we don't already have a valid connection ... */ error = -EINVAL; if (server->state == CONN_VALID) goto out; error = -EACCES; if (current->uid != server->mnt->mounted_uid && !capable(CAP_SYS_ADMIN)) goto out; error = -EBADF; filp = fget(opt->fd); if (!filp) goto out; if (!smb_valid_socket(filp->f_path.dentry->d_inode)) goto out_putf; server->sock_file = filp; server->conn_pid = get_pid(task_pid(current)); server->opt = *opt; server->generation += 1; server->state = CONN_VALID; error = 0; if (server->conn_error) { /* * conn_error is the returncode we originally decided to * drop the old connection on. This message should be positive * and not make people ask questions on why smbfs is printing * error messages ... */ printk(KERN_INFO "SMB connection re-established (%d)\n", server->conn_error); server->conn_error = 0; } /* * Store the server in sock user_data (Only used by sunrpc) */ sk = SOCKET_I(filp->f_path.dentry->d_inode)->sk; sk->sk_user_data = server; /* chain into the data_ready callback */ server->data_ready = xchg(&sk->sk_data_ready, smb_data_ready); /* check if we have an old smbmount that uses seconds for the serverzone */ if (server->opt.serverzone > 12*60 || server->opt.serverzone < -12*60) server->opt.serverzone /= 60; /* now that we have an established connection we can detect the server type and enable bug workarounds */ if (server->opt.protocol < SMB_PROTOCOL_LANMAN2) install_ops(server->ops, &smb_ops_core); else if (server->opt.protocol == SMB_PROTOCOL_LANMAN2) install_ops(server->ops, &smb_ops_os2); else if (server->opt.protocol == SMB_PROTOCOL_NT1 && (server->opt.max_xmit < 0x1000) && !(server->opt.capabilities & SMB_CAP_NT_SMBS)) { /* FIXME: can we kill the WIN95 flag now? */ server->mnt->flags |= SMB_MOUNT_WIN95; VERBOSE("detected WIN95 server\n"); install_ops(server->ops, &smb_ops_win95); } else { /* * Samba has max_xmit 65535 * NT4spX has max_xmit 4536 (or something like that) * win2k has ... */ VERBOSE("detected NT1 (Samba, NT4/5) server\n"); install_ops(server->ops, &smb_ops_winNT); } /* FIXME: the win9x code wants to modify these ... (seek/trunc bug) */ if (server->mnt->flags & SMB_MOUNT_OLDATTR) { server->ops->getattr = smb_proc_getattr_core; } else if (server->mnt->flags & SMB_MOUNT_DIRATTR) { server->ops->getattr = smb_proc_getattr_ff; } /* Decode server capabilities */ if (server->opt.capabilities & SMB_CAP_LARGE_FILES) { /* Should be ok to set this now, as no one can access the mount until the connection has been established. */ SB_of(server)->s_maxbytes = ~0ULL >> 1; VERBOSE("LFS enabled\n"); } if (server->opt.capabilities & SMB_CAP_UNICODE) { server->mnt->flags |= SMB_MOUNT_UNICODE; VERBOSE("Unicode enabled\n"); } else { server->mnt->flags &= ~SMB_MOUNT_UNICODE; }#if 0 /* flags we may test for other patches ... */ if (server->opt.capabilities & SMB_CAP_LARGE_READX) { VERBOSE("Large reads enabled\n"); } if (server->opt.capabilities & SMB_CAP_LARGE_WRITEX) { VERBOSE("Large writes enabled\n"); }#endif if (server->opt.capabilities & SMB_CAP_UNIX) { struct inode *inode; VERBOSE("Using UNIX CIFS extensions\n"); install_ops(server->ops, &smb_ops_unix); inode = SB_of(server)->s_root->d_inode; if (inode) inode->i_op = &smb_dir_inode_operations_unix; } VERBOSE("protocol=%d, max_xmit=%d, pid=%d capabilities=0x%x\n", server->opt.protocol, server->opt.max_xmit, pid_nr(server->conn_pid), server->opt.capabilities); /* FIXME: this really should be done by smbmount. */ if (server->opt.max_xmit > SMB_MAX_PACKET_SIZE) { server->opt.max_xmit = SMB_MAX_PACKET_SIZE; } smb_unlock_server(server); smbiod_wake_up(); if (server->opt.capabilities & SMB_CAP_UNIX) smb_proc_query_cifsunix(server); server->conn_complete++; wake_up_interruptible_all(&server->conn_wq); return error;out: smb_unlock_server(server); smbiod_wake_up(); return error;out_putf: fput(filp); goto out;}/* smb_setup_header: We completely set up the packet. You only have to insert the command-specific fields */__u8 *smb_setup_header(struct smb_request *req, __u8 command, __u16 wct, __u16 bcc){ __u32 xmit_len = SMB_HEADER_LEN + wct * sizeof(__u16) + bcc + 2; __u8 *p = req->rq_header; struct smb_sb_info *server = req->rq_server; p = smb_encode_smb_length(p, xmit_len - 4); *p++ = 0xff; *p++ = 'S'; *p++ = 'M'; *p++ = 'B'; *p++ = command; memset(p, '\0', 19); p += 19; p += 8; if (server->opt.protocol > SMB_PROTOCOL_CORE) { int flags = SMB_FLAGS_CASELESS_PATHNAMES; int flags2 = SMB_FLAGS2_LONG_PATH_COMPONENTS | SMB_FLAGS2_EXTENDED_ATTRIBUTES; /* EA? not really ... */ *(req->rq_header + smb_flg) = flags; if (server->mnt->flags & SMB_MOUNT_UNICODE) flags2 |= SMB_FLAGS2_UNICODE_STRINGS; WSET(req->rq_header, smb_flg2, flags2); } *p++ = wct; /* wct */ p += 2 * wct; WSET(p, 0, bcc); /* Include the header in the data to send */ req->rq_iovlen = 1; req->rq_iov[0].iov_base = req->rq_header; req->rq_iov[0].iov_len = xmit_len - bcc; return req->rq_buffer;}static voidsmb_setup_bcc(struct smb_request *req, __u8 *p){ u16 bcc = p - req->rq_buffer; u8 *pbcc = req->rq_header + SMB_HEADER_LEN + 2*SMB_WCT(req->rq_header); WSET(pbcc, 0, bcc); smb_encode_smb_length(req->rq_header, SMB_HEADER_LEN + 2*SMB_WCT(req->rq_header) - 2 + bcc); /* Include the "bytes" in the data to send */ req->rq_iovlen = 2; req->rq_iov[1].iov_base = req->rq_buffer; req->rq_iov[1].iov_len = bcc;}static intsmb_proc_seek(struct smb_sb_info *server, __u16 fileid, __u16 mode, off_t offset){ int result; struct smb_request *req;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -