patch-2.2.16 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: 919
- Date:
Wed Jun 7 14:26:44 2000
- Orig file:
v2.2.15/linux/fs/smbfs/proc.c
- Orig date:
Tue Jan 4 10:12:23 2000
diff -urN v2.2.15/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
@@ -12,6 +12,11 @@
* - don't sleep every time with win95 on a FINDNEXT
* - fixed loop_count bug
* - got rid of resume_key
+ * Jan 2000, cpg@aladdin.de
+ * - added posix semantics for unlink
+ * March 2000, tridge
+ * - removed support for old protocol levels. It didn't work anyway and
+ * was cluttering things up a lot.
*/
#include <linux/types.h>
@@ -34,6 +39,7 @@
/* #define SMBFS_DEBUG_TIMESTAMP 1 */
/* #define SMBFS_DEBUG_VERBOSE 1 */
/* #define pr_debug printk */
+#define SMBFS_POSIX_UNLINK 1
#define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN)
#define SMB_CMD(packet) (*(packet+8))
@@ -49,39 +55,19 @@
static int smb_proc_setattr_ext(struct smb_sb_info *, struct inode *,
struct smb_fattr *);
-static inline int
-min(int a, int b)
-{
- return a < b ? a : b;
-}
-
-static void
-str_upper(char *name, int len)
-{
- while (len--)
- {
- if (*name >= 'a' && *name <= 'z')
- *name -= ('a' - 'A');
- name++;
- }
-}
+static int
+smb_proc_setattr_core(struct smb_sb_info *server, struct dentry *dentry,
+ __u16 attr);
-static void
-str_lower(char *name, int len)
-{
- while (len--)
- {
- if (*name >= 'A' && *name <= 'Z')
- *name += ('a' - 'A');
- name++;
- }
-}
+static int
+smb_proc_do_getattr(struct dentry *dir, struct smb_fattr *fattr,struct smb_sb_info *server);
+/* reverse a string inline. This is used by the dircache walking routines */
static void reverse_string(char *buf, int len) {
char c;
char *end = buf+len-1;
- while(buf < end) {
+ while (buf < end) {
c = *buf;
*(buf++) = *end;
*(end--) = c;
@@ -163,13 +149,8 @@
static char *smb_encode_path(struct smb_sb_info *server, char *buf,
struct dentry *dir, struct qstr *name)
{
- char *start = buf;
-
buf += smb_build_path(dir, name, buf);
- if (server->opt.protocol <= SMB_PROTOCOL_COREPLUS)
- str_upper(start, buf - start);
-
return buf;
}
@@ -542,7 +523,7 @@
if (server->state == CONN_VALID)
{
#ifdef SMBFS_PARANOIA
-printk("smb_retry: new pid=%d, generation=%d\n",
+printk(KERN_DEBUG "smb_retry: new pid=%d, generation=%d\n",
server->conn_pid, server->generation);
#endif
result = 1;
@@ -587,7 +568,7 @@
if (smb_valid_packet(s->packet) != 0)
{
#ifdef SMBFS_PARANOIA
-printk("smb_request_ok: invalid packet!\n");
+printk(KERN_DEBUG "smb_request_ok: invalid packet!\n");
#endif
goto out;
}
@@ -601,7 +582,7 @@
{
result = -smb_errno(s);
if (!result)
- printk("smb_request_ok: rcls=%d, err=%d mapped to 0\n",
+ printk(KERN_DEBUG "smb_request_ok: rcls=%d, err=%d mapped to 0\n",
s->rcls, s->err);
/*
* Exit now even if the error was squashed ...
@@ -630,7 +611,7 @@
int error;
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_newconn: fd=%d, pid=%d\n", opt->fd, current->pid);
+printk(KERN_DEBUG "smb_newconn: fd=%d, pid=%d\n", opt->fd, current->pid);
#endif
/*
* Make sure we don't already have a pid ...
@@ -644,6 +625,11 @@
!capable(CAP_SYS_ADMIN))
goto out;
+ if (opt->protocol < SMB_PROTOCOL_NT1) {
+ printk(KERN_NOTICE " smbfs: protocols older than NT1 are not suppported\n");
+ goto out;
+ }
+
error = -EBADF;
filp = fget(opt->fd);
if (!filp)
@@ -666,17 +652,16 @@
/* now that we have an established connection we can detect the server
type and enable bug workarounds */
- if (server->opt.protocol == SMB_PROTOCOL_NT1 &&
- (server->opt.max_xmit < 0x1000) &&
+ if ((server->opt.max_xmit < 0x1000) &&
!(server->opt.capabilities & SMB_CAP_NT_SMBS)) {
server->mnt->version |= SMB_FIX_WIN95;
#ifdef SMBFS_DEBUG_VERBOSE
- printk("smb_newconn: detected WIN95 server\n");
+ printk(KERN_NOTICE "smb_newconn: detected WIN95 server\n");
#endif
}
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_newconn: protocol=%d, max_xmit=%d, pid=%d capabilities=0x%x\n",
+printk(KERN_DEBUG "smb_newconn: protocol=%d, max_xmit=%d, pid=%d capabilities=0x%x\n",
server->opt.protocol, server->opt.max_xmit, server->conn_pid,
server->opt.capabilities);
#endif
@@ -701,7 +686,7 @@
__u8 *buf = server->packet;
if (xmit_len > server->packet_size)
-printk("smb_setup_header: Aieee, xmit len > packet! len=%d, size=%d\n",
+printk(KERN_DEBUG "smb_setup_header: Aieee, xmit len > packet! len=%d, size=%d\n",
xmit_len, server->packet_size);
p = smb_encode_smb_length(p, xmit_len - 4);
@@ -721,11 +706,8 @@
WSET(buf, smb_uid, server->opt.server_uid);
WSET(buf, smb_mid, 1);
- if (server->opt.protocol > SMB_PROTOCOL_CORE)
- {
- *(buf+smb_flg) = 0x8;
- WSET(buf, smb_flg2, 0x3);
- }
+ *(buf+smb_flg) = 0x8;
+ WSET(buf, smb_flg2, 0x3);
*p++ = wct; /* wct */
p += 2 * wct;
WSET(p, 0, bcc);
@@ -784,7 +766,7 @@
(error == -EACCES || error == -ETXTBSY || error == -EROFS))
{
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_open: %s/%s R/W failed, error=%d, retrying R/O\n",
+printk(KERN_DEBUG "smb_proc_open: %s/%s R/W failed, error=%d, retrying R/O\n",
DENTRY_PATH(dentry), error);
#endif
mode = read_only;
@@ -818,7 +800,7 @@
result = -ENOENT;
if (!inode)
{
- printk("smb_open: no inode for dentry %s/%s\n",
+ printk(KERN_DEBUG "smb_open: no inode for dentry %s/%s\n",
DENTRY_PATH(dentry));
goto out;
}
@@ -839,7 +821,7 @@
if (result)
{
#ifdef SMBFS_PARANOIA
-printk("smb_open: %s/%s open failed, result=%d\n",
+printk(KERN_DEBUG "smb_open: %s/%s open failed, result=%d\n",
DENTRY_PATH(dentry), result);
#endif
goto out;
@@ -858,7 +840,7 @@
inode->u.smbfs_i.access != SMB_O_RDWR)
{
#ifdef SMBFS_PARANOIA
-printk("smb_open: %s/%s access denied, access=%x, wish=%x\n",
+printk(KERN_DEBUG "smb_open: %s/%s access denied, access=%x, wish=%x\n",
DENTRY_PATH(dentry), inode->u.smbfs_i.access, wish);
#endif
result = -EACCES;
@@ -911,9 +893,7 @@
* 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))
- {
+ if (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);
@@ -923,11 +903,8 @@
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.
+ * Force a revalidation after closing
*/
- if (server->opt.protocol < SMB_PROTOCOL_NT1)
- ino->u.smbfs_i.oldmtime = 0;
ino->u.smbfs_i.closed = jiffies;
}
return result;
@@ -974,7 +951,7 @@
if (dentry->d_count <= 1)
{
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_close_dentry: closing %s/%s, count=%d\n",
+printk(KERN_DEBUG "smb_close_dentry: closing %s/%s, count=%d\n",
DENTRY_PATH(dentry), dentry->d_count);
#endif
smb_proc_close_inode(server, ino);
@@ -982,7 +959,7 @@
smb_unlock_server(server);
}
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_close_dentry: closed %s/%s, count=%d\n",
+printk(KERN_DEBUG "smb_close_dentry: closed %s/%s, count=%d\n",
DENTRY_PATH(dentry), dentry->d_count);
#endif
}
@@ -1042,7 +1019,7 @@
out:
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_read: file %s/%s, count=%d, result=%d\n",
+printk(KERN_DEBUG "smb_proc_read: file %s/%s, count=%d, result=%d\n",
DENTRY_PATH(dentry), count, result);
#endif
smb_unlock_server(server);
@@ -1057,7 +1034,7 @@
__u8 *p;
#if SMBFS_DEBUG_VERBOSE
-printk("smb_proc_write: file %s/%s, count=%d@%ld, packet_size=%d\n",
+printk(KERN_DEBUG "smb_proc_write: file %s/%s, count=%d@%ld, packet_size=%d\n",
DENTRY_PATH(dentry), count, offset, server->packet_size);
#endif
smb_lock_server(server);
@@ -1184,11 +1161,36 @@
return smb_proc_generic_command(dentry, SMBrmdir);
}
+
+/*
+ * Note: called with the server locked.
+ * removes readonly attribute from a file. Used by unlink to give posix semantics
+ */
+static int
+smb_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(dentry, &fattr, server);
+ 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;
+}
+
int
smb_proc_unlink(struct dentry *dentry)
{
struct smb_sb_info *server = server_from_dentry(dentry);
char *p;
+ int flag = 0;
int result;
smb_lock_server(server);
@@ -1202,6 +1204,27 @@
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 */
+ result = smb_set_rw(dentry,server); /* remove RONLY attribute */
+ if (result == 0) {
+ flag = 1;
+ goto retry; /* and try again */
+ }
+ }
+#endif
if (smb_retry(server))
goto retry;
goto out;
@@ -1285,178 +1308,10 @@
smb_finish_dirent(server, fattr);
}
-/*
- * Note that we are now returning the name as a reference to avoid
- * an extra copy, and that the upper/lower casing is done in place.
- *
- * Bugs Noted:
- * (1) Pathworks servers may pad the name with extra spaces.
- */
-static __u8 *
-smb_decode_dirent(struct smb_sb_info *server, __u8 *p,
- struct cache_dirent *entry)
-{
- int len;
-
- /*
- * SMB doesn't have a concept of inode numbers ...
- */
- entry->ino = 0;
-
- p += SMB_STATUS_SIZE; /* reserved (search_status) */
- entry->name = p + 9;
- len = strlen(entry->name);
- if (len > 12)
- {
- len = 12;
- }
- /*
- * Trim trailing blanks for Pathworks servers
- */
- while (len > 2 && entry->name[len-1] == ' ')
- len--;
- entry->len = len;
-
- switch (server->opt.case_handling)
- {
- case SMB_CASE_UPPER:
- str_upper(entry->name, len);
- break;
- case SMB_CASE_LOWER:
- str_lower(entry->name, len);
- break;
- default:
- break;
- }
- pr_debug("smb_decode_dirent: len=%d, name=%s\n", len, entry->name);
- return p + 22;
-}
-
-/* This routine is used to read in directory entries from the network.
- Note that it is for short directory name seeks, i.e.: protocol <
- SMB_PROTOCOL_LANMAN2 */
-
-static int
-smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
- void *cachep)
-{
- char *p;
- int result;
- int i, first, entries_seen, entries;
- int entries_asked = (server->opt.max_xmit - 100) / SMB_DIRINFO_SIZE;
- __u16 bcc;
- __u16 count;
- char status[SMB_STATUS_SIZE];
- static struct qstr mask = { "*.*", 3, 0 };
-
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_readdir_short: %s/%s, pos=%d\n",
- DENTRY_PATH(dir), fpos);
-#endif
-
- smb_lock_server(server);
-
- /* N.B. We need to reinitialize the cache to restart */
- retry:
- smb_init_dircache(cachep);
- first = 1;
- entries = 0;
- entries_seen = 2; /* implicit . and .. */
-
- while (1)
- {
- p = smb_setup_header(server, SMBsearch, 2, 0);
- WSET(server->packet, smb_vwv0, entries_asked);
- WSET(server->packet, smb_vwv1, aDIR);
- *p++ = 4;
- if (first == 1)
- {
- p = smb_encode_path(server, p, dir, &mask);
- *p++ = 5;
- WSET(p, 0, 0);
- p += 2;
- first = 0;
- } else
- {
- *p++ = 0;
- *p++ = 5;
- WSET(p, 0, SMB_STATUS_SIZE);
- p += 2;
- memcpy(p, status, SMB_STATUS_SIZE);
- p += SMB_STATUS_SIZE;
- }
-
- smb_setup_bcc(server, p);
-
- result = smb_request_ok(server, SMBsearch, 1, -1);
- if (result < 0)
- {
- if ((server->rcls == ERRDOS) &&
- (server->err == ERRnofiles))
- break;
- if (smb_retry(server))
- goto retry;
- goto unlock_return;
- }
- p = SMB_VWV(server->packet);
- count = WVAL(p, 0);
- if (count <= 0)
- break;
-
- result = -EIO;
- bcc = WVAL(p, 2);
- if (bcc != count * SMB_DIRINFO_SIZE + 3)
- goto unlock_return;
- p += 7;
-
- /* Read the last entry into the status field. */
- memcpy(status,
- SMB_BUF(server->packet) + 3 +
- (count - 1) * SMB_DIRINFO_SIZE,
- SMB_STATUS_SIZE);
-
- /* Now we are ready to parse smb directory entries. */
-
- for (i = 0; i < count; i++)
- {
- struct cache_dirent this_ent, *entry = &this_ent;
-
- p = smb_decode_dirent(server, p, entry);
- if (entries_seen == 2 && entry->name[0] == '.')
- {
- if (entry->len == 1)
- continue;
- if (entry->name[1] == '.' && entry->len == 2)
- continue;
- }
- if (entries_seen >= fpos)
- {
- pr_debug("smb_proc_readdir: fpos=%u\n",
- entries_seen);
- smb_add_to_cache(cachep, entry, entries_seen);
- entries++;
- } else
- {
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_readdir: skipped, seen=%d, i=%d, fpos=%d\n",
-entries_seen, i, fpos);
-#endif
- }
- entries_seen++;
- }
- }
- result = entries;
-
- unlock_return:
- smb_unlock_server(server);
- return result;
-}
/*
- * Interpret a long filename structure using the specified info level:
- * level 1 for anything below NT1 protocol
- * level 260 for NT1 protocol
- *
+ * Interpret a long filename structure using info level 260
+
* We return a reference to the name string to avoid copying, and perform
* any needed upper/lower casing in place.
@@ -1465,7 +1320,7 @@
*/
static char *
smb_decode_long_dirent(struct smb_sb_info *server, char *p,
- struct cache_dirent *entry, int level)
+ struct cache_dirent *entry)
{
char *result;
unsigned int len = 0;
@@ -1475,46 +1330,18 @@
*/
entry->ino = 0;
- switch (level)
- {
- case 1:
- len = *((unsigned char *) p + 22);
- entry->len = len;
- entry->name = p + 23;
- result = p + 24 + len;
- break;
-
- case 260: /* SMB_FIND_FILE_BOTH_DIRECTORY_INFO = 0x104 */
- result = p + WVAL(p, 0);
- len = DVAL(p, 60);
- if (len > 255) len = 255;
- /* NT4 null terminates */
- entry->name = p + 94;
- if (len && entry->name[len-1] == '\0')
- len--;
- entry->len = len;
+ result = p + WVAL(p, 0);
+ len = DVAL(p, 60);
+ if (len > 255) len = 255;
+ /* NT4 null terminates */
+ entry->name = p + 94;
+ if (len && entry->name[len-1] == '\0')
+ len--;
+ entry->len = len;
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_decode_long_dirent: info 260 at %p, len=%d, name=%s\n",
- p, entry->len, entry->name);
+ printk(KERN_DEBUG "smb_decode_long_dirent: info 260 at %p, len=%d, name=%s\n",
+ p, entry->len, entry->name);
#endif
- break;
-
- default:
- printk("smb_decode_long_dirent: Unknown level %d\n", level);
- result = p + WVAL(p, 0);
- }
-
- switch (server->opt.case_handling)
- {
- case SMB_CASE_UPPER:
- str_upper(entry->name, len);
- break;
- case SMB_CASE_LOWER:
- str_lower(entry->name, len);
- break;
- default:
- break;
- }
return result;
}
@@ -1539,8 +1366,6 @@
char *p, *mask, *param = server->temp_buf;
__u16 command;
int first, entries, entries_seen;
-
- /* Both NT and OS/2 accept info level 1 (but see note below). */
int info_level = 260;
const int max_matches = 512;
@@ -1555,12 +1380,6 @@
int mask_len, i, result;
static struct qstr star = { "*", 1, 0 };
- /*
- * use info level 1 for older servers that don't do 260
- */
- if (server->opt.protocol < SMB_PROTOCOL_NT1)
- info_level = 1;
-
smb_lock_server(server);
retry:
@@ -1571,7 +1390,7 @@
mask_len = smb_encode_path(server, mask, dir, &star) - mask;
first = 1;
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_readdir_long: starting fpos=%d, mask=%s\n", fpos, mask);
+printk(KERN_DEBUG "smb_proc_readdir_long: starting fpos=%d, mask=%s\n", fpos, mask);
#endif
/*
* We must reinitialize the dircache when retrying.
@@ -1609,7 +1428,7 @@
command = TRANSACT2_FINDNEXT;
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_readdir_long: handle=0x%X, mask=%s\n",
+printk(KERN_DEBUG "smb_proc_readdir_long: handle=0x%X, mask=%s\n",
ff_dir_handle, mask);
#endif
WSET(param, 0, ff_dir_handle); /* search handle */
@@ -1630,12 +1449,12 @@
if (smb_retry(server))
{
#ifdef SMBFS_PARANOIA
-printk("smb_proc_readdir_long: error=%d, retrying\n", result);
+printk(KERN_DEBUG "smb_proc_readdir_long: error=%d, retrying\n", result);
#endif
goto retry;
}
#ifdef SMBFS_PARANOIA
-printk("smb_proc_readdir_long: error=%d, breaking\n", result);
+printk(KERN_DEBUG "smb_proc_readdir_long: error=%d, breaking\n", result);
#endif
entries = result;
break;
@@ -1653,7 +1472,7 @@
if (server->rcls != 0)
{
#ifdef SMBFS_PARANOIA
-printk("smb_proc_readdir_long: name=%s, entries=%d, rcls=%d, err=%d\n",
+printk(KERN_DEBUG "smb_proc_readdir_long: name=%s, entries=%d, rcls=%d, err=%d\n",
mask, entries, server->rcls, server->err);
#endif
entries = -smb_errno(server);
@@ -1685,8 +1504,7 @@
{
struct cache_dirent this_ent, *entry = &this_ent;
- p = smb_decode_long_dirent(server, p, entry,
- info_level);
+ p = smb_decode_long_dirent(server, p, entry);
/* ignore . and .. from the server */
if (entries_seen == 2 && entry->name[0] == '.')
@@ -1705,7 +1523,7 @@
}
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_readdir_long: received %d entries, eos=%d\n",
+printk(KERN_DEBUG "smb_proc_readdir_long: received %d entries, eos=%d\n",
ff_searchcount, ff_eos);
#endif
first = 0;
@@ -1722,98 +1540,7 @@
struct smb_sb_info *server;
server = server_from_dentry(dir);
- if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
- return smb_proc_readdir_long(server, dir, fpos, cachep);
- else
- return smb_proc_readdir_short(server, dir, fpos, cachep);
-}
-
-/*
- * This version uses the trans2 TRANSACT2_FINDFIRST message
- * to get the attribute data.
- * Note: called with the server locked.
- *
- * Bugs Noted:
- */
-static int
-smb_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, dentry, NULL) - mask;
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_getattr_ff: name=%s, len=%d\n", mask, mask_len);
-#endif
- 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 + 1, 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)
-printk("smb_proc_getattr_ff: 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)
- {
-#ifdef SMBFS_PARANOIA
-printk("smb_proc_getattr_ff: bad result for %s, len=%d, count=%d\n",
-mask, resp_data_len, WVAL(resp_param, 2));
-#endif
- 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);
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_getattr_ff: name=%s, date=%x, time=%x, mtime=%ld\n",
-mask, date, time, fattr->f_mtime);
-#endif
- fattr->f_size = DVAL(resp_data, 12);
- /* ULONG allocation size */
- fattr->attr = WVAL(resp_data, 20);
- result = 0;
-
-out:
- return result;
+ return smb_proc_readdir_long(server, dir, fpos, cachep);
}
/*
@@ -1839,12 +1566,21 @@
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_ctime = local2utc(server, DVAL(server->packet, smb_vwv1));
+
+ /* uggh. If its a directory then its a ctime, otherwise its a
+ mtime. In order for the dircache to work with Win9X we
+ have to set the mtime to the current time for directories */
+ if (fattr->attr & aDIR) {
+ fattr->f_mtime = CURRENT_TIME;
+ } else {
+ fattr->f_mtime = fattr->f_ctime;
+ }
+
fattr->f_atime = fattr->f_mtime;
+ fattr->f_size = DVAL(server->packet, smb_vwv3);
#ifdef SMBFS_DEBUG_TIMESTAMP
-printk("getattr_core: %s/%s, mtime=%ld\n",
+printk(KERN_DEBUG "getattr_core: %s/%s, mtime=%ld\n",
DENTRY_PATH(dir), fattr->f_mtime);
#endif
result = 0;
@@ -1890,7 +1626,7 @@
if (server->rcls != 0)
{
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_getattr_trans2: for %s: result=%d, rcls=%d, err=%d\n",
+printk(KERN_DEBUG "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);
@@ -1900,7 +1636,7 @@
if (resp_data_len < 22)
{
#ifdef SMBFS_PARANOIA
-printk("smb_proc_getattr_trans2: not enough data for %s, len=%d\n",
+printk(KERN_DEBUG "smb_proc_getattr_trans2: not enough data for %s, len=%d\n",
¶m[6], resp_data_len);
#endif
goto out;
@@ -1926,7 +1662,7 @@
time = WVAL(resp_data, 8 + off_time);
attr->f_mtime = date_dos2unix(server, date, time);
#ifdef SMBFS_DEBUG_TIMESTAMP
-printk("getattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n",
+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);
@@ -1937,35 +1673,41 @@
return result;
}
-int
-smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr)
+/*
+ * Note: called with the server locked.
+ *
+ * get the file attribute
+ */
+static int
+smb_proc_do_getattr(struct dentry *dir, struct smb_fattr *fattr,struct smb_sb_info *server)
{
- struct smb_sb_info *server = server_from_dentry(dir);
int result;
- smb_lock_server(server);
smb_init_dirent(server, fattr);
/*
* Select whether to use core or trans2 getattr.
- */
- if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) {
- /*
- * Win 95 appears to break with the trans2 getattr.
- */
- if (server->mnt->version & (SMB_FIX_OLDATTR|SMB_FIX_WIN95))
- goto core_attr;
- if (server->mnt->version & SMB_FIX_DIRATTR)
- result = smb_proc_getattr_ff(server, dir, fattr);
- else
- result = smb_proc_getattr_trans2(server, dir, fattr);
- } else {
- core_attr:
+ * Win 95 appears to break with the trans2 getattr.
+ */
+ if (server->mnt->version & SMB_FIX_WIN95) {
result = smb_proc_getattr_core(server, dir, fattr);
+ } else {
+ result = smb_proc_getattr_trans2(server, dir, fattr);
}
smb_finish_dirent(server, fattr);
+ return result;
+}
+
+
+int
+smb_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(dir, fattr, server);
smb_unlock_server(server);
return result;
}
@@ -2029,7 +1771,7 @@
int result;
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_setattr: setting %s/%s, open=%d\n",
+printk(KERN_DEBUG "smb_proc_setattr: setting %s/%s, open=%d\n",
DENTRY_PATH(dir), smb_is_open(dir->d_inode));
#endif
smb_lock_server(server);
@@ -2062,7 +1804,7 @@
WSET(server->packet, smb_vwv5, date);
WSET(server->packet, smb_vwv6, time);
#ifdef SMBFS_DEBUG_TIMESTAMP
-printk("smb_proc_setattr_ext: date=%d, time=%d, mtime=%ld\n",
+printk(KERN_DEBUG "smb_proc_setattr_ext: date=%d, time=%d, mtime=%ld\n",
date, time, fattr->f_mtime);
#endif
@@ -2112,7 +1854,7 @@
WSET(data, 8, date);
WSET(data, 10, time);
#ifdef SMBFS_DEBUG_TIMESTAMP
-printk("setattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n",
+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 */
@@ -2159,13 +1901,12 @@
int result;
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_settime: setting %s/%s, open=%d\n",
+printk(KERN_DEBUG "smb_proc_settime: setting %s/%s, open=%d\n",
DENTRY_PATH(dentry), smb_is_open(inode));
#endif
smb_lock_server(server);
/* setting the time on a Win95 server fails (tridge) */
- if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 &&
- !(server->mnt->version & SMB_FIX_WIN95))
+ if (!(server->mnt->version & SMB_FIX_WIN95))
{
if (smb_is_open(inode) &&
inode->u.smbfs_i.access != SMB_O_RDONLY)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)