patch-2.1.66 linux/fs/smbfs/proc.c
Next file: linux/fs/smbfs/sock.c
Previous file: linux/fs/smbfs/inode.c
Back to the patch index
Back to the overall index
- Lines: 911
- Date:
Mon Nov 24 10:30:40 1997
- Orig file:
v2.1.65/linux/fs/smbfs/proc.c
- Orig date:
Sat Nov 1 11:04:27 1997
diff -u --recursive --new-file v2.1.65/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
@@ -17,6 +17,7 @@
#include <linux/fcntl.h>
#include <linux/dcache.h>
#include <linux/dirent.h>
+
#include <linux/smb_fs.h>
#include <linux/smbno.h>
#include <linux/smb_mount.h>
@@ -24,6 +25,7 @@
#include <asm/string.h>
#define SMBFS_PARANOIA 1
+/* #define SMBFS_DEBUG_TIMESTAMP 1 */
/* #define SMBFS_DEBUG_VERBOSE 1 */
/* #define pr_debug printk */
@@ -36,6 +38,9 @@
#define SMB_DIRINFO_SIZE 43
#define SMB_STATUS_SIZE 21
+static int smb_proc_setfile_trans2(struct smb_sb_info *, struct inode *,
+ struct smb_fattr *);
+
static inline int
min(int a, int b)
{
@@ -171,24 +176,25 @@
extern struct timezone sys_tz;
-static int
-utc2local(int time)
+static time_t
+utc2local(time_t time)
{
return time - sys_tz.tz_minuteswest * 60;
}
-static int
-local2utc(int time)
+static time_t
+local2utc(time_t time)
{
return time + sys_tz.tz_minuteswest * 60;
}
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
-static int
-date_dos2unix(unsigned short time, unsigned short date)
+static time_t
+date_dos2unix(__u16 date, __u16 time)
{
- int month, year, secs;
+ int month, year;
+ time_t secs;
month = ((date >> 5) & 15) - 1;
year = date >> 9;
@@ -203,14 +209,15 @@
/* Convert linear UNIX date to a MS-DOS time/date pair. */
static void
-date_unix2dos(int unix_date, __u8 * date, __u8 * time)
+date_unix2dos(int unix_date, __u16 *date, __u16 *time)
{
int day, year, nl_day, month;
unix_date = utc2local(unix_date);
- WSET(time, 0,
- (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
- (((unix_date / 3600) % 24) << 11));
+ *time = (unix_date % 60) / 2 +
+ (((unix_date / 60) % 60) << 5) +
+ (((unix_date / 3600) % 24) << 11);
+
day = unix_date / 86400 - 3652;
year = day / 365;
if ((year + 3) / 4 + 365 * year > day)
@@ -227,12 +234,10 @@
if (day_n[month] > nl_day)
break;
}
- WSET(date, 0,
- nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
+ *date = nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9);
}
-
/*****************************************************************************/
/* */
/* Support section. */
@@ -272,9 +277,27 @@
static int
smb_verify(__u8 * packet, int command, int wct, int bcc)
{
- return (SMB_CMD(packet) == command &&
- SMB_WCT(packet) >= wct &&
- (bcc == -1 || SMB_BCC(packet) >= bcc)) ? 0 : -EIO;
+ 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("smb_verify: command=%x, SMB_CMD=%x??\n",
+ command, SMB_CMD(packet));
+ goto fail;
+bad_wct:
+ printk("smb_verify: command=%x, wct=%d, SMB_WCT=%d??\n",
+ command, wct, SMB_WCT(packet));
+ goto fail;
+bad_bcc:
+ printk("smb_verify: command=%x, bcc=%d, SMB_BCC=%d??\n",
+ command, bcc, SMB_BCC(packet));
+fail:
+ return -EIO;
}
/*
@@ -327,15 +350,18 @@
}
static int
-smb_errno(int errcls, int error)
+smb_errno(struct smb_sb_info *server)
{
+ int errcls = server->rcls;
+ int error = server->err;
+ char *class = "Unknown";
+
if (errcls == ERRDOS)
switch (error)
{
case ERRbadfunc:
return EINVAL;
case ERRbadfile:
- return ENOENT;
case ERRbadpath:
return ENOENT;
case ERRnofids:
@@ -351,7 +377,6 @@
case ERRbadmem:
return EFAULT;
case ERRbadenv:
- return EREMOTEIO;
case ERRbadformat:
return EREMOTEIO;
case ERRbadaccess:
@@ -364,7 +389,7 @@
return EREMOTEIO;
case ERRdiffdevice:
return EXDEV;
- case ERRnofiles:
+ case ERRnofiles: /* Why is this mapped to 0?? */
return 0;
case ERRbadshare:
return ETXTBSY;
@@ -372,18 +397,19 @@
return EDEADLK;
case ERRfilexists:
return EEXIST;
- case 87:
+ case 87: /* should this map to 0?? */
return 0; /* Unknown error!! */
case 123: /* Invalid name?? e.g. .tmp* */
return ENOENT;
+ case 145: /* Win NT 4.0: non-empty directory? */
+ return EBUSY;
/* This next error seems to occur on an mv when
* the destination exists */
case 183:
return EEXIST;
default:
- printk("smb_errno: ERRDOS code %d, returning EIO\n",
- error);
- return EIO;
+ class = "ERRDOS";
+ goto err_unknown;
} else if (errcls == ERRSRV)
switch (error)
{
@@ -396,9 +422,8 @@
case ERRaccess:
return EACCES;
default:
- printk("smb_errno: ERRSRV code %d, returning EIO\n",
- error);
- return EIO;
+ class = "ERRSRV";
+ goto err_unknown;
} else if (errcls == ERRHRD)
switch (error)
{
@@ -409,7 +434,6 @@
case ERRnotready:
return EUCLEAN;
case ERRbadcmd:
- return EIO;
case ERRdata:
return EIO;
case ERRbadreq:
@@ -419,15 +443,15 @@
case ERRlock:
return EDEADLK;
default:
- printk("smb_errno: ERRHRD code %d, returning EIO\n",
- error);
- return EIO;
+ class = "ERRHRD";
+ goto err_unknown;
} else if (errcls == ERRCMD)
- {
- printk("smb_errno: ERRCMD code %d, returning EIO\n", error);
- return EIO;
- }
- return 0;
+ class = "ERRCMD";
+
+err_unknown:
+ printk("smb_errno: class %s, code %d from command %x\n",
+ class, error, SMB_CMD(server->packet));
+ return EIO;
}
static inline void
@@ -526,31 +550,51 @@
static int
smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc)
{
- int result = 0;
+ int result = -EIO;
s->rcls = 0;
s->err = 0;
/* Make sure we have a connection */
- if (s->state != CONN_VALID && !smb_retry(s))
+ if (s->state != CONN_VALID)
{
- result = -EIO;
- } else if (smb_request(s) < 0)
+ if (!smb_retry(s))
+ goto out;
+ }
+
+ if (smb_request(s) < 0)
{
pr_debug("smb_request failed\n");
- result = -EIO;
- } else if (smb_valid_packet(s->packet) != 0)
- {
- pr_debug("not a valid packet!\n");
- result = -EIO;
- } else if (s->rcls != 0)
+ goto out;
+ }
+ if (smb_valid_packet(s->packet) != 0)
{
- result = -smb_errno(s->rcls, s->err);
- } else if (smb_verify(s->packet, command, wct, bcc) != 0)
+#ifdef SMBFS_PARANOIA
+printk("smb_request_ok: invalid packet!\n");
+#endif
+ goto out;
+ }
+
+ /*
+ * Check for server errors. The current smb_errno() routine
+ * is squashing some error codes, but I don't think this is
+ * correct: after a server error the packet won't be valid.
+ */
+ if (s->rcls != 0)
{
- pr_debug("smb_verify failed\n");
- result = -EIO;
+ result = -smb_errno(s);
+ if (!result)
+ printk("smb_request_ok: rcls=%d, err=%d mapped to 0\n",
+ s->rcls, s->err);
+ /*
+ * Exit now even if the error was squashed ...
+ * packet verify will fail anyway.
+ */
+ goto out;
}
+ result = smb_verify(s->packet, command, wct, bcc);
+
+out:
return result;
}
@@ -693,18 +737,21 @@
/*
* We're called with the server locked, and we leave it that way.
- * Set the permissions to be consistent with the desired access.
*/
-
static int
-smb_proc_open(struct smb_sb_info *server, struct dentry *dir, int wish)
+smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish)
{
- struct inode *ino = dir->d_inode;
+ struct inode *ino = dentry->d_inode;
int mode, read_write = 0x42, read_only = 0x40;
int error;
char *p;
+ /*
+ * Attempt to open r/w, unless there are no write privileges.
+ */
mode = read_write;
+ if (!(ino->i_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
+ mode = read_only;
#if 0
if (!(wish & (O_WRONLY | O_RDWR)))
mode = read_only;
@@ -715,7 +762,7 @@
WSET(server->packet, smb_vwv0, mode);
WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);
*p++ = 4;
- p = smb_encode_path(server, p, dir, NULL);
+ p = smb_encode_path(server, p, dentry, NULL);
smb_setup_bcc(server, p);
error = smb_request_ok(server, SMBopen, 7, 0);
@@ -728,8 +775,8 @@
(error == -EACCES || error == -ETXTBSY || error == -EROFS))
{
#ifdef SMBFS_PARANOIA
-printk("smb_proc_open: %s/%s open failed, error=%d, retrying R/O\n",
-dir->d_parent->d_name.name, dir->d_name.name, error);
+printk("smb_proc_open: %s/%s R/W failed, error=%d, retrying R/O\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, error);
#endif
mode = read_only;
goto retry;
@@ -742,25 +789,31 @@
/* smb_vwv2 has mtime */
/* smb_vwv4 has size */
ino->u.smbfs_i.access = WVAL(server->packet, smb_vwv6);
- ino->u.smbfs_i.access &= 3;
+ ino->u.smbfs_i.access &= SMB_ACCMASK;
/* N.B. Suppose the open failed?? */
ino->u.smbfs_i.open = server->generation;
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_open: error=%d, access=%d\n", error, ino->u.smbfs_i.access);
+#ifdef SMBFS_PARANOIA
+if (error)
+printk("smb_proc_open: %s/%s failed, error=%d, access=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,error,ino->u.smbfs_i.access);
#endif
return error;
}
+/*
+ * Make sure the file is open, and check that the access
+ * is compatible with the desired access.
+ */
int
smb_open(struct dentry *dentry, int wish)
{
- struct inode *i = dentry->d_inode;
+ struct inode *inode = dentry->d_inode;
int result;
result = -ENOENT;
- if (!i)
+ if (!inode)
{
printk("smb_open: no inode for dentry %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
@@ -772,12 +825,12 @@
* currently open, we can be sure that the file isn't about
* to be closed. (See smb_close_dentry() below.)
*/
- if (!smb_is_open(i))
+ if (!smb_is_open(inode))
{
- struct smb_sb_info *server = SMB_SERVER(i);
+ struct smb_sb_info *server = SMB_SERVER(inode);
smb_lock_server(server);
result = 0;
- if (!smb_is_open(i))
+ if (!smb_is_open(inode))
result = smb_proc_open(server, dentry, wish);
smb_unlock_server(server);
if (result)
@@ -794,14 +847,20 @@
smb_renew_times(dentry);
}
- result = -EACCES;
- if (((wish == O_RDONLY) && ((i->u.smbfs_i.access == O_RDONLY)
- || (i->u.smbfs_i.access == O_RDWR)))
- || ((wish == O_WRONLY) && ((i->u.smbfs_i.access == O_WRONLY)
- || (i->u.smbfs_i.access == O_RDWR)))
- || ((wish == O_RDWR) && (i->u.smbfs_i.access == O_RDWR)))
- result = 0;
-
+ /*
+ * 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)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_open: %s/%s access denied, access=%x, wish=%x\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+inode->u.smbfs_i.access, wish);
+#endif
+ result = -EACCES;
+ }
out:
return result;
}
@@ -818,7 +877,12 @@
}
/*
- * Called with the server locked
+ * 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
+ * the attributes if the file has been modified locally (we want to
+ * keep modify and access times in sync ...)
*/
static int
smb_proc_close_inode(struct smb_sb_info *server, struct inode * ino)
@@ -827,12 +891,43 @@
if (smb_is_open(ino))
{
/*
+ * Check whether to update locally-modified attributes at
+ * closing time. This is necessary to keep the modify and
+ * access times in sync.
+ *
+ * Kludge alert: If we're using trans2 getattr messages,
+ * the timestamps are accurate only to two seconds ...
+ * we must round the time to avoid cache invalidations!
+ */
+ if (ino->u.smbfs_i.access == SMB_O_RDWR ||
+ ino->u.smbfs_i.access == SMB_O_WRONLY) {
+ struct smb_fattr fattr;
+
+ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) {
+ if (ino->i_mtime & 1)
+ ino->i_mtime--;
+ if (ino->i_atime & 1)
+ ino->i_atime--;
+ }
+ smb_get_inode_attr(ino, &fattr);
+ smb_proc_setfile_trans2(server, ino, &fattr);
+ }
+
+ /*
* We clear the open flag in advance, in case another
* process observes the value while we block below.
*/
ino->u.smbfs_i.open = 0;
result = smb_proc_close(server, ino->u.smbfs_i.fileid,
ino->i_mtime);
+ ino->u.smbfs_i.cache_valid &= ~SMB_F_LOCALWRITE;
+ /*
+ * 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;
}
@@ -892,6 +987,22 @@
}
}
+/*
+ * 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.
+ */
+int
+smb_close_fileid(struct dentry *dentry, __u16 fileid)
+{
+ struct smb_sb_info *server = server_from_dentry(dentry);
+ int result = 0;
+
+ 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. */
@@ -972,11 +1083,11 @@
int
smb_proc_create(struct dentry *dir, struct qstr *name,
- __u16 attr, time_t ctime)
+ __u16 attr, time_t ctime, __u16 *fileid)
{
struct smb_sb_info *server;
- int error;
char *p;
+ int error;
server = server_from_dentry(dir);
smb_lock_server(server);
@@ -989,13 +1100,14 @@
p = smb_encode_path(server, p, dir, name);
smb_setup_bcc(server, p);
- if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0)
+ error = smb_request_ok(server, SMBcreate, 1, 0);
+ if (error < 0)
{
if (smb_retry(server))
goto retry;
goto out;
}
- smb_proc_close(server, WVAL(server->packet, smb_vwv0), CURRENT_TIME);
+ *fileid = WVAL(server->packet, smb_vwv0);
error = 0;
out:
@@ -1164,14 +1276,19 @@
static void
smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
{
- fattr->f_mode = server->mnt->file_mode;
if (fattr->attr & aDIR)
{
+ /* N.B. check for read-only directories */
fattr->f_mode = server->mnt->dir_mode;
fattr->f_size = 512;
+ } else
+ {
+ fattr->f_mode = server->mnt->file_mode;
+ if (fattr->attr & aRONLY)
+ fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
}
- fattr->f_blocks = 0; /* already set to zero? */
+ fattr->f_blocks = 0;
if ((fattr->f_blksize != 0) && (fattr->f_size != 0))
{
fattr->f_blocks =
@@ -1519,7 +1636,7 @@
WSET(param, 10, 8 + 4 + 2); /* resume required +
close on end +
continue */
- if (server->mnt->version & 1)
+ if (server->mnt->version & SMB_FIX_WIN95)
{
/* Windows 95 is not able to deliver answers
* to FIND_NEXT fast enough, so sleep 0.2 sec
@@ -1557,7 +1674,7 @@
printk("smb_proc_readdir_long: rcls=%d, err=%d, breaking\n",
server->rcls, server->err);
#endif
- entries = -smb_errno(server->rcls, server->err);
+ entries = -smb_errno(server);
break;
}
#ifdef SMBFS_PARANOIA
@@ -1669,15 +1786,16 @@
return smb_proc_readdir_short(server, dir, fpos, cachep);
}
+/*
+ * Note: called with the server locked.
+ */
static int
smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,
- struct qstr *name, struct smb_fattr *attr)
+ struct qstr *name, struct smb_fattr *fattr)
{
int result;
char *p;
- smb_lock_server(server);
-
retry:
p = smb_setup_header(server, SMBgetatr, 0, 0);
*p++ = 4;
@@ -1690,32 +1808,38 @@
goto retry;
goto out;
}
- attr->attr = WVAL(server->packet, smb_vwv0);
- attr->f_ctime = attr->f_atime = attr->f_mtime =
- local2utc(DVAL(server->packet, smb_vwv1));
- attr->f_size = DVAL(server->packet, smb_vwv3);
+ fattr->attr = WVAL(server->packet, smb_vwv0);
+ fattr->f_mtime = local2utc(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",
+dir->d_name.name, name->name, fattr->f_mtime);
+#endif
result = 0;
out:
- smb_unlock_server(server);
return result;
}
+/*
+ * Note: called with the server locked.
+ */
static int
smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
struct qstr *name, struct smb_fattr *attr)
{
char *p;
int result;
-
+ __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;
char param[SMB_MAXPATHLEN + 20]; /* too big for the stack! */
- smb_lock_server(server);
-
retry:
WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
DSET(param, 2, 0);
@@ -1737,7 +1861,7 @@
printk("smb_proc_getattr_trans2: for %s: result=%d, rcls=%d, err=%d\n",
¶m[6], result, server->rcls, server->err);
#endif
- result = -smb_errno(server->rcls, server->err);
+ result = -smb_errno(server);
goto out;
}
result = -ENOENT;
@@ -1750,18 +1874,34 @@
goto out;
}
- attr->f_ctime = date_dos2unix(WVAL(resp_data, 2),
- WVAL(resp_data, 0));
- attr->f_atime = date_dos2unix(WVAL(resp_data, 6),
- WVAL(resp_data, 4));
- attr->f_mtime = date_dos2unix(WVAL(resp_data, 10),
- WVAL(resp_data, 8));
+ /*
+ * Kludge alert: Win 95 swaps the date and time field,
+ * contrary to the CIFS docs and Win NT practice.
+ */
+ if (server->mnt->version & SMB_FIX_WIN95) {
+ off_date = 2;
+ off_time = 0;
+ }
+ date = WVAL(resp_data, off_date);
+ time = WVAL(resp_data, off_time);
+ attr->f_ctime = date_dos2unix(date, time);
+
+ date = WVAL(resp_data, 4 + off_date);
+ time = WVAL(resp_data, 4 + off_time);
+ attr->f_atime = date_dos2unix(date, time);
+
+ date = WVAL(resp_data, 8 + off_date);
+ time = WVAL(resp_data, 8 + off_time);
+ attr->f_mtime = date_dos2unix(date, time);
+#ifdef SMBFS_DEBUG_TIMESTAMP
+printk("getattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n",
+dir->d_name.name, name->name, date, time, attr->f_mtime);
+#endif
attr->f_size = DVAL(resp_data, 12);
attr->attr = WVAL(resp_data, 20);
result = 0;
out:
- smb_unlock_server(server);
return result;
}
@@ -1769,28 +1909,33 @@
smb_proc_getattr(struct dentry *dir, struct qstr *name,
struct smb_fattr *fattr)
{
- struct smb_sb_info *server;
+ struct smb_sb_info *server = server_from_dentry(dir);
int result;
- server = server_from_dentry(dir);
+ smb_lock_server(server);
smb_init_dirent(server, fattr);
/*
- * Win 95 is painfully slow at returning trans2 getattr info ...
+ * Win 95 is painfully slow at returning trans2 getattr info,
+ * so we provide the SMB_FIX_OLDATTR option switch.
*/
if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 &&
- !(server->mnt->version & 1))
+ !(server->mnt->version & SMB_FIX_OLDATTR))
result = smb_proc_getattr_trans2(server, dir, name, fattr);
else
result = smb_proc_getattr_core(server, dir, name, fattr);
smb_finish_dirent(server, fattr);
+ smb_unlock_server(server);
return result;
}
-/* In core protocol, there is only 1 time to be set, we use
- entry->f_mtime, to make touch work. */
+/*
+ * In the core protocol there is only one time to be set,
+ * so we use fattr->f_mtime to make `touch' work.
+ * Note: called with the server locked.
+ */
static int
smb_proc_setattr_core(struct smb_sb_info *server,
struct dentry *dir, struct smb_fattr *fattr)
@@ -1799,19 +1944,25 @@
char *buf;
int result;
- smb_lock_server(server);
+#ifdef SMBFS_DEBUG_TIMESTAMP
+printk("setattr_core: %s/%s, mtime=%ld\n",
+dir->d_parent->d_name.name, dir->d_name.name, fattr->f_mtime);
+#endif
retry:
buf = server->packet;
p = smb_setup_header(server, SMBsetatr, 8, 0);
WSET(buf, smb_vwv0, fattr->attr);
DSET(buf, smb_vwv1, utc2local(fattr->f_mtime));
+ WSET(buf, smb_vwv3, 0); /* reserved values */
+ WSET(buf, smb_vwv4, 0);
+ WSET(buf, smb_vwv5, 0);
+ WSET(buf, smb_vwv6, 0);
+ WSET(buf, smb_vwv7, 0);
*p++ = 4;
p = smb_encode_path(server, p, dir, NULL);
- *p++ = 4;
- *p++ = 0;
-
smb_setup_bcc(server, p);
+
result = smb_request_ok(server, SMBsetatr, 0, 0);
if (result < 0)
{
@@ -1821,14 +1972,17 @@
}
result = 0;
out:
- smb_unlock_server(server);
return result;
}
+/*
+ * Note: called with the server locked.
+ */
static int
smb_proc_setattr_trans2(struct smb_sb_info *server,
struct dentry *dir, struct smb_fattr *fattr)
{
+ __u16 date, time;
char *p;
int result;
@@ -1839,20 +1993,28 @@
char param[SMB_MAXPATHLEN + 20]; /* too long for the stack! */
char data[26];
- smb_lock_server(server);
-
retry:
WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
DSET(param, 2, 0);
p = smb_encode_path(server, param + 6, dir, NULL);
- date_unix2dos(fattr->f_ctime, &(data[0]), &(data[2]));
- date_unix2dos(fattr->f_atime, &(data[4]), &(data[6]));
- date_unix2dos(fattr->f_mtime, &(data[8]), &(data[10]));
+ date_unix2dos(fattr->f_ctime, &date, &time);
+ WSET(data, 0, date);
+ WSET(data, 2, time);
+ date_unix2dos(fattr->f_atime, &date, &time);
+ WSET(data, 4, date);
+ WSET(data, 6, time);
+ date_unix2dos(fattr->f_mtime, &date, &time);
+ WSET(data, 8, date);
+ WSET(data, 10, time);
+#ifdef SMBFS_DEBUG_TIMESTAMP
+printk("setattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n",
+dir->d_parent->d_name.name, dir->d_name.name, date, time, fattr->f_mtime);
+#endif
DSET(data, 12, fattr->f_size);
DSET(data, 16, fattr->f_blksize);
WSET(data, 20, fattr->attr);
- WSET(data, 22, 0);
+ DSET(data, 22, 0); /* ULONG EA size */
result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
26, data, p - param, param,
@@ -1866,10 +2028,64 @@
}
result = 0;
if (server->rcls != 0)
- result = -smb_errno(server->rcls, server->err);
+ result = -smb_errno(server);
+
+out:
+ return result;
+}
+
+/*
+ * Set the attributes for an open file.
+ */
+static int
+smb_proc_setfile_trans2(struct smb_sb_info *server,
+ struct inode * inode, struct smb_fattr *fattr)
+{
+ __u16 date, time;
+ unsigned char *resp_data = NULL;
+ unsigned char *resp_parm = NULL;
+ int resp_data_len = 0;
+ int resp_parm_len = 0;
+ int result;
+ char parm[6], data[26];
+
+ retry:
+ WSET(parm, 0, inode->u.smbfs_i.fileid);
+ WSET(parm, 2, 1); /* Info level SMB_INFO_STANDARD */
+
+ date_unix2dos(fattr->f_ctime, &date, &time);
+ WSET(data, 0, date);
+ WSET(data, 2, time);
+ date_unix2dos(fattr->f_atime, &date, &time);
+ WSET(data, 4, date);
+ WSET(data, 6, time);
+#ifdef SMBFS_DEBUG_TIMESTAMP
+printk("smb_proc_setfile_trans2: date=%x, time=%x, atime=%ld\n",
+date, time, fattr->f_atime);
+#endif
+ date_unix2dos(fattr->f_mtime, &date, &time);
+ WSET(data, 8, date);
+ WSET(data, 10, time);
+ DSET(data, 12, fattr->f_size);
+ DSET(data, 16, fattr->f_blksize);
+ WSET(data, 20, fattr->attr);
+ DSET(data, 22, 0); /* ULONG EA size */
+
+ result = smb_trans2_request(server, TRANSACT2_SETFILEINFO,
+ 26, data, 6, parm,
+ &resp_data_len, &resp_data,
+ &resp_parm_len, &resp_parm);
+ if (result < 0)
+ {
+ if (smb_retry(server))
+ goto retry;
+ goto out;
+ }
+ result = 0;
+ if (server->rcls != 0)
+ result = -smb_errno(server);
out:
- smb_unlock_server(server);
return result;
}
@@ -1879,11 +2095,22 @@
{
int result;
- if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
- result = smb_proc_setattr_trans2(server, dir, fattr);
- else
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_setattr: setting %s/%s, open=%d\n",
+dir->d_parent->d_name.name, dir->d_name.name, smb_is_open(dir->d_inode));
+#endif
+ smb_lock_server(server);
+ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) {
+ struct inode *inode = dir->d_inode;
+
+ if (smb_is_open(inode))
+ result = smb_proc_setfile_trans2(server, inode, fattr);
+ else
+ result = smb_proc_setattr_trans2(server, dir, fattr);
+ } else
result = smb_proc_setattr_core(server, dir, fattr);
+ smb_unlock_server(server);
return result;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov