📄 proc.c
字号:
*/static intsmb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry, struct smb_fattr *fattr){ char *param = server->temp_buf, *mask = param + 12; __u16 date, time; unsigned char *resp_data = NULL; unsigned char *resp_param = NULL; int resp_data_len = 0; int resp_param_len = 0; int mask_len, result;retry: mask_len = smb_encode_path(server, mask, SMB_MAXNAMELEN+1, dentry, NULL); if (mask_len < 0) { result = mask_len; goto out; } VERBOSE("name=%s, len=%d\n", mask, mask_len); WSET(param, 0, aSYSTEM | aHIDDEN | aDIR); WSET(param, 2, 1); /* max count */ WSET(param, 4, 1); /* close after this call */ WSET(param, 6, 1); /* info_level */ DSET(param, 8, 0); result = smb_trans2_request(server, TRANSACT2_FINDFIRST, 0, NULL, 12 + mask_len, param, &resp_data_len, &resp_data, &resp_param_len, &resp_param); if (result < 0) { if (smb_retry(server)) goto retry; goto out; } if (server->rcls != 0) { result = smb_errno(server);#ifdef SMBFS_PARANOIA if (result != -ENOENT) PARANOIA("error for %s, rcls=%d, err=%d\n", mask, server->rcls, server->err);#endif goto out; } /* Make sure we got enough data ... */ result = -EINVAL; if (resp_data_len < 22 || WVAL(resp_param, 2) != 1) { PARANOIA("bad result for %s, len=%d, count=%d\n", mask, resp_data_len, WVAL(resp_param, 2)); goto out; } /* * Decode the response into the fattr ... */ date = WVAL(resp_data, 0); time = WVAL(resp_data, 2); fattr->f_ctime = date_dos2unix(server, date, time); date = WVAL(resp_data, 4); time = WVAL(resp_data, 6); fattr->f_atime = date_dos2unix(server, date, time); date = WVAL(resp_data, 8); time = WVAL(resp_data, 10); fattr->f_mtime = date_dos2unix(server, date, time); VERBOSE("name=%s, date=%x, time=%x, mtime=%ld\n", mask, date, time, fattr->f_mtime); fattr->f_size = DVAL(resp_data, 12); /* ULONG allocation size */ fattr->attr = WVAL(resp_data, 20); result = 0;out: return result;}/* * Note: called with the server locked. */static intsmb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir, struct smb_fattr *fattr){ int result; char *p; retry: p = smb_setup_header(server, SMBgetatr, 0, 0); result = smb_simple_encode_path(server, &p, dir, NULL); if (result < 0) goto out; smb_setup_bcc(server, p); if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0) { if (smb_retry(server)) goto retry; goto out; } fattr->attr = WVAL(server->packet, smb_vwv0); fattr->f_mtime = local2utc(server, DVAL(server->packet, smb_vwv1)); fattr->f_size = DVAL(server->packet, smb_vwv3); fattr->f_ctime = fattr->f_mtime; fattr->f_atime = fattr->f_mtime; #ifdef SMBFS_DEBUG_TIMESTAMP printk("getattr_core: %s/%s, mtime=%ld\n", DENTRY_PATH(dir), fattr->f_mtime);#endif result = 0;out: return result;}/* * Note: called with the server locked. * * Bugs Noted: * (1) Win 95 swaps the date and time fields in the standard info level. */static intsmb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir, struct smb_fattr *attr){ char *p, *param = server->temp_buf; __u16 date, time; int off_date = 0, off_time = 2; unsigned char *resp_data = NULL; unsigned char *resp_param = NULL; int resp_data_len = 0; int resp_param_len = 0; int result; retry: WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */ DSET(param, 2, 0); result = smb_encode_path(server, param+6, SMB_MAXNAMELEN+1, dir, NULL); if (result < 0) goto out; p = param + 6 + result; result = smb_trans2_request(server, TRANSACT2_QPATHINFO, 0, NULL, p - param, param, &resp_data_len, &resp_data, &resp_param_len, &resp_param); if (result < 0) { if (smb_retry(server)) goto retry; goto out; } if (server->rcls != 0) { VERBOSE("for %s: result=%d, rcls=%d, err=%d\n", ¶m[6], result, server->rcls, server->err); result = smb_errno(server); goto out; } result = -ENOENT; if (resp_data_len < 22) { PARANOIA("not enough data for %s, len=%d\n", ¶m[6], resp_data_len); goto out; } /* * Kludge alert: Win 95 swaps the date and time field, * contrary to the CIFS docs and Win NT practice. */ if (server->mnt->flags & SMB_MOUNT_WIN95) { off_date = 2; off_time = 0; } date = WVAL(resp_data, off_date); time = WVAL(resp_data, off_time); attr->f_ctime = date_dos2unix(server, date, time); date = WVAL(resp_data, 4 + off_date); time = WVAL(resp_data, 4 + off_time); attr->f_atime = date_dos2unix(server, date, time); date = WVAL(resp_data, 8 + off_date); time = WVAL(resp_data, 8 + off_time); attr->f_mtime = date_dos2unix(server, date, time);#ifdef SMBFS_DEBUG_TIMESTAMP printk(KERN_DEBUG "getattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n", DENTRY_PATH(dir), date, time, attr->f_mtime);#endif attr->f_size = DVAL(resp_data, 12); attr->attr = WVAL(resp_data, 20); result = 0;out: return result;}/* * Note: called with the server locked */static intsmb_proc_do_getattr(struct smb_sb_info *server, struct dentry *dir, struct smb_fattr *fattr){ int result; struct inode *inode = dir->d_inode; smb_init_dirent(server, fattr); /* * Select whether to use core or trans2 getattr. * Win 95 appears to break with the trans2 getattr. */ if (server->opt.protocol < SMB_PROTOCOL_LANMAN2 || (server->mnt->flags & (SMB_MOUNT_OLDATTR|SMB_MOUNT_WIN95)) ) { result = smb_proc_getattr_core(server, dir, fattr); } else { if (server->mnt->flags & SMB_MOUNT_DIRATTR) result = smb_proc_getattr_ff(server, dir, fattr); else result = smb_proc_getattr_trans2(server, dir, fattr); } /* * None of the getattr versions here can make win9x return the right * filesize if there are changes made to an open file. * A seek-to-end does return the right size, but we only need to do * that on files we have written. */ if (server->mnt->flags & SMB_MOUNT_WIN95 && inode && inode->u.smbfs_i.flags & SMB_F_LOCALWRITE && smb_is_open(inode)) { __u16 fileid = inode->u.smbfs_i.fileid; fattr->f_size = smb_proc_seek(server, fileid, 2, 0); } smb_finish_dirent(server, fattr); return result;}intsmb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr){ struct smb_sb_info *server = server_from_dentry(dir); int result; smb_lock_server(server); result = smb_proc_do_getattr(server, dir, fattr); smb_unlock_server(server); return result;}/* * Called with the server locked. Because of bugs in the * core protocol, we use this only to set attributes. See * smb_proc_settime() below for timestamp handling. * * Bugs Noted: * (1) If mtime is non-zero, both Win 3.1 and Win 95 fail * with an undocumented error (ERRDOS code 50). Setting * mtime to 0 allows the attributes to be set. * (2) The extra parameters following the name string aren't * in the CIFS docs, but seem to be necessary for operation. */static intsmb_proc_setattr_core(struct smb_sb_info *server, struct dentry *dentry, __u16 attr){ char *p; int result; retry: p = smb_setup_header(server, SMBsetatr, 8, 0); WSET(server->packet, smb_vwv0, attr); DSET(server->packet, smb_vwv1, 0); /* mtime */ WSET(server->packet, smb_vwv3, 0); /* reserved values */ WSET(server->packet, smb_vwv4, 0); WSET(server->packet, smb_vwv5, 0); WSET(server->packet, smb_vwv6, 0); WSET(server->packet, smb_vwv7, 0); result = smb_simple_encode_path(server, &p, dentry, NULL); if (result < 0) goto out; if (p + 2 > (char *)server->packet + server->packet_size) { result = -ENAMETOOLONG; goto out; } *p++ = 4; *p++ = 0; smb_setup_bcc(server, p); result = smb_request_ok(server, SMBsetatr, 0, 0); if (result < 0) { if (smb_retry(server)) goto retry; goto out; } result = 0;out: return result;}/* * Because of bugs in the trans2 setattr messages, we must set * attributes and timestamps separately. The core SMBsetatr * message seems to be the only reliable way to set attributes. */intsmb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr){ struct smb_sb_info *server = server_from_dentry(dir); int result; VERBOSE("setting %s/%s, open=%d\n", DENTRY_PATH(dir), smb_is_open(dir->d_inode)); smb_lock_server(server); result = smb_proc_setattr_core(server, dir, fattr->attr); smb_unlock_server(server); return result;}/* * Called with the server locked. Sets the timestamps for an * file open with write permissions. */static intsmb_proc_setattr_ext(struct smb_sb_info *server, struct inode *inode, struct smb_fattr *fattr){ __u16 date, time; int result; retry: smb_setup_header(server, SMBsetattrE, 7, 0); WSET(server->packet, smb_vwv0, inode->u.smbfs_i.fileid); /* We don't change the creation time */ WSET(server->packet, smb_vwv1, 0); WSET(server->packet, smb_vwv2, 0); date_unix2dos(server, fattr->f_atime, &date, &time); WSET(server->packet, smb_vwv3, date); WSET(server->packet, smb_vwv4, time); date_unix2dos(server, fattr->f_mtime, &date, &time); WSET(server->packet, smb_vwv5, date); WSET(server->packet, smb_vwv6, time);#ifdef SMBFS_DEBUG_TIMESTAMP printk(KERN_DEBUG "smb_proc_setattr_ext: date=%d, time=%d, mtime=%ld\n", date, time, fattr->f_mtime);#endif result = smb_request_ok(server, SMBsetattrE, 0, 0); if (result < 0) { if (smb_retry(server)) goto retry; goto out; } result = 0;out: return result;}/* * Note: called with the server locked. * * Bugs Noted: * (1) The TRANSACT2_SETPATHINFO message under Win NT 4.0 doesn't * set the file's attribute flags. */static intsmb_proc_setattr_trans2(struct smb_sb_info *server, struct dentry *dir, struct smb_fattr *fattr){ __u16 date, time; char *p, *param = server->temp_buf; unsigned char *resp_data = NULL; unsigned char *resp_param = NULL; int resp_data_len = 0; int resp_param_len = 0; int result; char data[26]; retry: WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */ DSET(param, 2, 0); result = smb_encode_path(server, param+6, SMB_MAXNAMELEN+1, dir, NULL); if (result < 0) goto out; p = param + 6 + result; WSET(data, 0, 0); /* creation time */ WSET(data, 2, 0); date_unix2dos(server, fattr->f_atime, &date, &time); WSET(data, 4, date); WSET(data, 6, time); date_unix2dos(server, fattr->f_mtime, &date, &time); WSET(data, 8, date); WSET(data, 10, time);#ifdef SMBFS_DEBUG_TIMESTAMP printk(KERN_DEBUG "setattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n", DENTRY_PATH(dir), date, time, fattr->f_mtime);#endif DSET(data, 12, 0); /* size */ DSET(data, 16, 0); /* blksize */ WSET(data, 20, 0); /* attr */ DSET(data, 22, 0); /* ULONG EA size */ result = smb_trans2_request(server, TRANSACT2_SETPATHINFO, 26, data, p - param, param, &resp_data_len, &resp_data, &resp_param_len, &resp_param); if (result < 0) { if (smb_retry(server)) goto retry; goto out; } result = 0; if (server->rcls != 0) result = smb_errno(server);out: return result;}/* * Set the modify and access timestamps for a file. * * Incredibly enough, in all of SMB there is no message to allow * setting both attributes and timestamps at once. * * Bugs Noted: * (1) Win 95 doesn't support the TRANSACT2_SETFILEINFO message * with info level 1 (INFO_STANDARD). * (2) Win 95 seems not to support setting directory timestamps. * (3) Under the core protocol apparently the only way to set the * timestamp is to open and close the file. */intsmb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr){ struct smb_sb_info *server = server_from_dentry(dentry); struct inode *inode = dentry->d_inode; int result; VERBOSE("setting %s/%s, open=%d\n", DENTRY_PATH(dentry), smb_is_open(inode)); smb_lock_server(server); /* setting the time on a Win95 server fails (tridge) */ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 && !(server->mnt->flags & SMB_MOUNT_WIN95)) { if (smb_is_open(inode) && inode->u.smbfs_i.access != SMB_O_RDONLY) result = smb_proc_setattr_ext(server, inode, fattr); else result = smb_proc_setattr_trans2(server, dentry, fattr); } else { /* * Fail silently on directories ... timestamp can't be set? */ result = 0; if (S_ISREG(inode->i_mode)) { /* * Set the mtime by opening and closing the file. * Note that the file is opened read-only, but this * still allows us to set the date (tridge) */ result = -EACCES; if (!smb_is_open(inode)) smb_proc_open(server, dentry, SMB_O_RDONLY); if (smb_is_open(inode)) { inode->i_mtime = fattr->f_mtime; result = smb_proc_close_inode(server, inode); } } } smb_unlock_server(server); return result;}intsmb_proc_dskattr(struct super_block *sb, struct statfs *attr){ struct smb_sb_info *server = &(sb->u.smbfs_sb); int result; char *p; long unit; smb_lock_server(server); retry: smb_setup_header(server, SMBdskattr, 0, 0); if ((result = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) { if (smb_retry(server)) goto retry; goto out; } p = SMB_VWV(server->packet); unit = (WVAL(p, 2) * WVAL(p, 4)) >> SMB_ST_BLKSHIFT; attr->f_blocks = WVAL(p, 0) * unit; attr->f_bsize = SMB_ST_BLKSIZE; attr->f_bavail = attr->f_bfree = WVAL(p, 6) * unit; result = 0;out: smb_unlock_server(server); return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -