📄 proc.c
字号:
result = -ENOENT; if (!inode) { printk(KERN_ERR "smb_open: no inode for dentry %s/%s\n", DENTRY_PATH(dentry)); goto out; } if (!smb_is_open(inode)) { struct smb_sb_info *server = server_from_inode(inode); smb_lock_server(server); result = 0; if (!smb_is_open(inode)) result = smb_proc_open(server, dentry, wish); smb_unlock_server(server); if (result) { PARANOIA("%s/%s open failed, result=%d\n", DENTRY_PATH(dentry), result); goto out; } /* * A successful open means the path is still valid ... */ smb_renew_times(dentry); } /* * Check whether the access is compatible with the desired mode. */ result = 0; if (inode->u.smbfs_i.access != wish && inode->u.smbfs_i.access != SMB_O_RDWR) { PARANOIA("%s/%s access denied, access=%x, wish=%x\n", DENTRY_PATH(dentry), inode->u.smbfs_i.access, wish); result = -EACCES; }out: return result;}/* We're called with the server locked */static int smb_proc_close(struct smb_sb_info *server, __u16 fileid, __u32 mtime){ smb_setup_header(server, SMBclose, 3, 0); WSET(server->packet, smb_vwv0, fileid); DSET(server->packet, smb_vwv1, utc2local(server, mtime)); return smb_request_ok(server, SMBclose, 0, 0);}/* * Called with the server locked. * * Win NT 4.0 has an apparent bug in that it fails to update the * modify time when writing to a file. As a workaround, we update * both modify and access time locally, and post the times to the * server when closing the file. */static int smb_proc_close_inode(struct smb_sb_info *server, struct inode * ino){ int result = 0; if (smb_is_open(ino)) { /* * We clear the open flag in advance, in case another * process observes the value while we block below. */ ino->u.smbfs_i.open = 0; /* * Kludge alert: SMB timestamps are accurate only to * two seconds ... round the times to avoid needless * cache invalidations! */ if (ino->i_mtime & 1) ino->i_mtime--; if (ino->i_atime & 1) ino->i_atime--; /* * If the file is open with write permissions, * update the time stamps to sync mtime and atime. */ if ((server->opt.protocol >= SMB_PROTOCOL_LANMAN2) && !(ino->u.smbfs_i.access == SMB_O_RDONLY)) { struct smb_fattr fattr; smb_get_inode_attr(ino, &fattr); smb_proc_setattr_ext(server, ino, &fattr); } result = smb_proc_close(server, ino->u.smbfs_i.fileid, ino->i_mtime); /* * Force a revalidation after closing ... some servers * don't post the size until the file has been closed. */ if (server->opt.protocol < SMB_PROTOCOL_NT1) ino->u.smbfs_i.oldmtime = 0; ino->u.smbfs_i.closed = jiffies; } return result;}intsmb_close(struct inode *ino){ int result = 0; if (smb_is_open(ino)) { struct smb_sb_info *server = server_from_inode(ino); smb_lock_server(server); result = smb_proc_close_inode(server, ino); smb_unlock_server(server); } return result;}/* * This is used to close a file following a failed instantiate. * Since we don't have an inode, we can't use any of the above. */intsmb_close_fileid(struct dentry *dentry, __u16 fileid){ struct smb_sb_info *server = server_from_dentry(dentry); int result; smb_lock_server(server); result = smb_proc_close(server, fileid, CURRENT_TIME); smb_unlock_server(server); return result;}/* In smb_proc_read and smb_proc_write we do not retry, because the file-id would not be valid after a reconnection. */intsmb_proc_read(struct inode *inode, off_t offset, int count, char *data){ struct smb_sb_info *server = server_from_inode(inode); __u16 returned_count, data_len; unsigned char *buf; int result; smb_lock_server(server); smb_setup_header(server, SMBread, 5, 0); buf = server->packet; WSET(buf, smb_vwv0, inode->u.smbfs_i.fileid); WSET(buf, smb_vwv1, count); DSET(buf, smb_vwv2, offset); WSET(buf, smb_vwv4, 0); result = smb_request_ok(server, SMBread, 5, -1); if (result < 0) goto out; returned_count = WVAL(server->packet, smb_vwv0); buf = SMB_BUF(server->packet); data_len = WVAL(buf, 1); /* we can NOT simply trust the data_len given by the server ... */ if (data_len > server->packet_size - (buf+3 - server->packet)) { printk(KERN_ERR "smb_proc_read: invalid data length!! " "%d > %d - (%p - %p)\n", data_len, server->packet_size, buf+3, server->packet); result = -EIO; goto out; } memcpy(data, buf+3, data_len); if (returned_count != data_len) { printk(KERN_NOTICE "smb_proc_read: returned != data_len\n"); printk(KERN_NOTICE "smb_proc_read: ret_c=%d, data_len=%d\n", returned_count, data_len); } result = data_len;out: VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n", inode->i_ino, inode->u.smbfs_i.fileid, count, result); smb_unlock_server(server); return result;}intsmb_proc_write(struct inode *inode, off_t offset, int count, const char *data){ struct smb_sb_info *server = server_from_inode(inode); int result; __u8 *p; __u16 fileid = inode->u.smbfs_i.fileid; VERBOSE("ino=%ld, fileid=%d, count=%d@%ld, packet_size=%d\n", inode->i_ino, inode->u.smbfs_i.fileid, count, offset, server->packet_size); smb_lock_server(server); p = smb_setup_header(server, SMBwrite, 5, count + 3); WSET(server->packet, smb_vwv0, fileid); WSET(server->packet, smb_vwv1, count); DSET(server->packet, smb_vwv2, offset); WSET(server->packet, smb_vwv4, 0); *p++ = 1; WSET(p, 0, count); memcpy(p+2, data, count); result = smb_request_ok(server, SMBwrite, 1, 0); if (result >= 0) result = WVAL(server->packet, smb_vwv0); smb_unlock_server(server); return result;}intsmb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid){ struct smb_sb_info *server = server_from_dentry(dentry); char *p; int result; smb_lock_server(server); retry: p = smb_setup_header(server, SMBcreate, 3, 0); WSET(server->packet, smb_vwv0, attr); DSET(server->packet, smb_vwv1, utc2local(server, ctime)); result = smb_simple_encode_path(server, &p, dentry, NULL); if (result < 0) goto out; smb_setup_bcc(server, p); result = smb_request_ok(server, SMBcreate, 1, 0); if (result < 0) { if (smb_retry(server)) goto retry; goto out; } *fileid = WVAL(server->packet, smb_vwv0); result = 0;out: smb_unlock_server(server); return result;}intsmb_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry){ struct smb_sb_info *server = server_from_dentry(old_dentry); char *p; int result; smb_lock_server(server); retry: p = smb_setup_header(server, SMBmv, 1, 0); WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN | aDIR); result = smb_simple_encode_path(server, &p, old_dentry, NULL); if (result < 0) goto out; result = smb_simple_encode_path(server, &p, new_dentry, NULL); if (result < 0) goto out; smb_setup_bcc(server, p); if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) { if (smb_retry(server)) goto retry; goto out; } result = 0;out: smb_unlock_server(server); return result;}/* * Code common to mkdir and rmdir. */static intsmb_proc_generic_command(struct dentry *dentry, __u8 command){ struct smb_sb_info *server = server_from_dentry(dentry); char *p; int result; smb_lock_server(server); retry: p = smb_setup_header(server, command, 0, 0); result = smb_simple_encode_path(server, &p, dentry, NULL); if (result < 0) goto out; smb_setup_bcc(server, p); result = smb_request_ok(server, command, 0, 0); if (result < 0) { if (smb_retry(server)) goto retry; goto out; } result = 0;out: smb_unlock_server(server); return result;}intsmb_proc_mkdir(struct dentry *dentry){ return smb_proc_generic_command(dentry, SMBmkdir);}intsmb_proc_rmdir(struct dentry *dentry){ return smb_proc_generic_command(dentry, SMBrmdir);}#if SMBFS_POSIX_UNLINK/* * Removes readonly attribute from a file. Used by unlink to give posix * semantics. * Note: called with the server locked. */static intsmb_set_rw(struct dentry *dentry,struct smb_sb_info *server){ int result; struct smb_fattr fattr; /* first get current attribute */ result = smb_proc_do_getattr(server, dentry, &fattr); if (result < 0) return result; /* if RONLY attribute is set, remove it */ if (fattr.attr & aRONLY) { /* read only attribute is set */ fattr.attr &= ~aRONLY; result = smb_proc_setattr_core(server, dentry, fattr.attr); } return result;}#endifintsmb_proc_unlink(struct dentry *dentry){ struct smb_sb_info *server = server_from_dentry(dentry); int flag = 0; char *p; int result; smb_lock_server(server); retry: p = smb_setup_header(server, SMBunlink, 1, 0); WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN); result = smb_simple_encode_path(server, &p, dentry, NULL); if (result < 0) goto out; smb_setup_bcc(server, p); if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) {#if SMBFS_POSIX_UNLINK if (result == -EACCES && !flag) { /* Posix semantics is for the read-only state of a file to be ignored in unlink(). In the SMB world a unlink() is refused on a read-only file. To make things easier for unix users we try to override the files permission if the unlink fails with the right error. This introduces a race condition that could lead to a file being written by someone who shouldn't have access, but as far as I can tell that is unavoidable */ /* remove RONLY attribute and try again */ result = smb_set_rw(dentry,server); if (result == 0) { flag = 1; goto retry; } }#endif if (smb_retry(server)) goto retry; goto out; } result = 0;out: smb_unlock_server(server); return result;}/* * Called with the server locked */intsmb_proc_flush(struct smb_sb_info *server, __u16 fileid){ smb_setup_header(server, SMBflush, 1, 0); WSET(server->packet, smb_vwv0, fileid); return smb_request_ok(server, SMBflush, 0, 0);}intsmb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length){ char *p; int result; smb_lock_server(server);retry: p = smb_setup_header(server, SMBwrite, 5, 3); WSET(server->packet, smb_vwv0, fid); WSET(server->packet, smb_vwv1, 0); DSET(server->packet, smb_vwv2, length); WSET(server->packet, smb_vwv4, 0); *p++ = 1; WSET(p, 0, 0); if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) { if (smb_retry(server)) goto retry; goto out; } /* * win9x doesn't appear to update the size immediately. * It will return the old file size after the truncate, * confusing smbfs. * NT and Samba return the new value immediately. */ if (server->mnt->flags & SMB_MOUNT_WIN95) smb_proc_flush(server, fid);out: smb_unlock_server(server); return result;}static voidsmb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr){ memset(fattr, 0, sizeof(*fattr)); fattr->f_nlink = 1; fattr->f_uid = server->mnt->uid; fattr->f_gid = server->mnt->gid; fattr->f_blksize = SMB_ST_BLKSIZE;}static voidsmb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr){ fattr->f_mode = server->mnt->file_mode; if (fattr->attr & aDIR) { fattr->f_mode = server->mnt->dir_mode; fattr->f_size = SMB_ST_BLKSIZE; } /* Check the read-only flag */ if (fattr->attr & aRONLY) fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); /* How many 512 byte blocks do we need for this file? */ fattr->f_blocks = 0; if (fattr->f_size != 0) fattr->f_blocks = 1 + ((fattr->f_size-1) >> 9); return;}voidsmb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr){ smb_init_dirent(server, fattr); fattr->attr = aDIR; fattr->f_ino = 2; /* traditional root inode number */ fattr->f_mtime = CURRENT_TIME; smb_finish_dirent(server, fattr);}/* * Decode a dirent for old protocols * * qname is filled with the decoded, and possibly translated, name. * fattr receives decoded attributes * * Bugs Noted: * (1) Pathworks servers may pad the name with extra spaces. */static char *smb_decode_short_dirent(struct smb_sb_info *server, char *p, struct qstr *qname, struct smb_fattr *fattr){ int len; /* * SMB doesn't have a concept of inode numbers ... */ smb_init_dirent(server, fattr); fattr->f_ino = 0; /* FIXME: do we need this? */ p += SMB_STATUS_SIZE; /* reserved (search_status) */ fattr->attr = *p; fattr->f_mtime = date_dos2unix(server, WVAL(p, 3), WVAL(p, 1)); fattr->f_size = DVAL(p, 5); fattr->f_ctime = fattr->f_mtime; fattr->f_atime = fattr->f_mtime; qname->name = p + 9; len = strnlen(qname->name, 12);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -