aboutsummaryrefslogtreecommitdiffstats
path: root/fs/smbfs/proc.c
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2010-10-04 16:55:57 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-10-05 12:08:21 -0400
commit2116b7a473bf1c8d26998b477c294e7fe294921f (patch)
tree5f06aca6b425916f763d83fa4516bca51c8f9a60 /fs/smbfs/proc.c
parent5af74aa5e97fcc0cc3955bc2a7ff6f3a13fa41cb (diff)
smbfs: move to drivers/staging
smbfs has been scheduled for removal in 2.6.27, so maybe we can now move it to drivers/staging on the way out. smbfs still uses the big kernel lock and nobody is going to fix that, so we should be getting rid of it soon. This removes the 32 bit compat mount and ioctl handling code, which is implemented in common fs code, and moves all smbfs related files into drivers/staging/smbfs. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/smbfs/proc.c')
-rw-r--r--fs/smbfs/proc.c3507
1 files changed, 0 insertions, 3507 deletions
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
deleted file mode 100644
index 71c29b6670b4..000000000000
--- a/fs/smbfs/proc.c
+++ /dev/null
@@ -1,3507 +0,0 @@
1/*
2 * proc.c
3 *
4 * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
5 * Copyright (C) 1997 by Volker Lendecke
6 *
7 * Please add a note about your changes to smbfs in the ChangeLog file.
8 */
9
10#include <linux/types.h>
11#include <linux/capability.h>
12#include <linux/errno.h>
13#include <linux/slab.h>
14#include <linux/fs.h>
15#include <linux/file.h>
16#include <linux/stat.h>
17#include <linux/fcntl.h>
18#include <linux/dcache.h>
19#include <linux/nls.h>
20#include <linux/smp_lock.h>
21#include <linux/net.h>
22#include <linux/vfs.h>
23#include <linux/smb_fs.h>
24#include <linux/smbno.h>
25#include <linux/smb_mount.h>
26
27#include <net/sock.h>
28
29#include <asm/string.h>
30#include <asm/div64.h>
31
32#include "smb_debug.h"
33#include "proto.h"
34#include "request.h"
35
36
37/* Features. Undefine if they cause problems, this should perhaps be a
38 config option. */
39#define SMBFS_POSIX_UNLINK 1
40
41/* Allow smb_retry to be interrupted. */
42#define SMB_RETRY_INTR
43
44#define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN)
45#define SMB_CMD(packet) (*(packet+8))
46#define SMB_WCT(packet) (*(packet+SMB_HEADER_LEN - 1))
47
48#define SMB_DIRINFO_SIZE 43
49#define SMB_STATUS_SIZE 21
50
51#define SMB_ST_BLKSIZE (PAGE_SIZE)
52#define SMB_ST_BLKSHIFT (PAGE_SHIFT)
53
54static struct smb_ops smb_ops_core;
55static struct smb_ops smb_ops_os2;
56static struct smb_ops smb_ops_win95;
57static struct smb_ops smb_ops_winNT;
58static struct smb_ops smb_ops_unix;
59static struct smb_ops smb_ops_null;
60
61static void
62smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);
63static void
64smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);
65static int
66smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,
67 struct smb_fattr *fattr);
68static int
69smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry,
70 struct smb_fattr *fattr);
71static int
72smb_proc_setattr_core(struct smb_sb_info *server, struct dentry *dentry,
73 u16 attr);
74static int
75smb_proc_setattr_ext(struct smb_sb_info *server,
76 struct inode *inode, struct smb_fattr *fattr);
77static int
78smb_proc_query_cifsunix(struct smb_sb_info *server);
79static void
80install_ops(struct smb_ops *dst, struct smb_ops *src);
81
82
83static void
84str_upper(char *name, int len)
85{
86 while (len--)
87 {
88 if (*name >= 'a' && *name <= 'z')
89 *name -= ('a' - 'A');
90 name++;
91 }
92}
93
94#if 0
95static void
96str_lower(char *name, int len)
97{
98 while (len--)
99 {
100 if (*name >= 'A' && *name <= 'Z')
101 *name += ('a' - 'A');
102 name++;
103 }
104}
105#endif
106
107/* reverse a string inline. This is used by the dircache walking routines */
108static void reverse_string(char *buf, int len)
109{
110 char c;
111 char *end = buf+len-1;
112
113 while(buf < end) {
114 c = *buf;
115 *(buf++) = *end;
116 *(end--) = c;
117 }
118}
119
120/* no conversion, just a wrapper for memcpy. */
121static int convert_memcpy(unsigned char *output, int olen,
122 const unsigned char *input, int ilen,
123 struct nls_table *nls_from,
124 struct nls_table *nls_to)
125{
126 if (olen < ilen)
127 return -ENAMETOOLONG;
128 memcpy(output, input, ilen);
129 return ilen;
130}
131
132static inline int write_char(unsigned char ch, char *output, int olen)
133{
134 if (olen < 4)
135 return -ENAMETOOLONG;
136 sprintf(output, ":x%02x", ch);
137 return 4;
138}
139
140static inline int write_unichar(wchar_t ch, char *output, int olen)
141{
142 if (olen < 5)
143 return -ENAMETOOLONG;
144 sprintf(output, ":%04x", ch);
145 return 5;
146}
147
148/* convert from one "codepage" to another (possibly being utf8). */
149static int convert_cp(unsigned char *output, int olen,
150 const unsigned char *input, int ilen,
151 struct nls_table *nls_from,
152 struct nls_table *nls_to)
153{
154 int len = 0;
155 int n;
156 wchar_t ch;
157
158 while (ilen > 0) {
159 /* convert by changing to unicode and back to the new cp */
160 n = nls_from->char2uni(input, ilen, &ch);
161 if (n == -EINVAL) {
162 ilen--;
163 n = write_char(*input++, output, olen);
164 if (n < 0)
165 goto fail;
166 output += n;
167 olen -= n;
168 len += n;
169 continue;
170 } else if (n < 0)
171 goto fail;
172 input += n;
173 ilen -= n;
174
175 n = nls_to->uni2char(ch, output, olen);
176 if (n == -EINVAL)
177 n = write_unichar(ch, output, olen);
178 if (n < 0)
179 goto fail;
180 output += n;
181 olen -= n;
182
183 len += n;
184 }
185 return len;
186fail:
187 return n;
188}
189
190/* ----------------------------------------------------------- */
191
192/*
193 * nls_unicode
194 *
195 * This encodes/decodes little endian unicode format
196 */
197
198static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
199{
200 if (boundlen < 2)
201 return -EINVAL;
202 *out++ = uni & 0xff;
203 *out++ = uni >> 8;
204 return 2;
205}
206
207static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni)
208{
209 if (boundlen < 2)
210 return -EINVAL;
211 *uni = (rawstring[1] << 8) | rawstring[0];
212 return 2;
213}
214
215static struct nls_table unicode_table = {
216 .charset = "unicode",
217 .uni2char = uni2char,
218 .char2uni = char2uni,
219};
220
221/* ----------------------------------------------------------- */
222
223static int setcodepage(struct nls_table **p, char *name)
224{
225 struct nls_table *nls;
226
227 if (!name || !*name) {
228 nls = NULL;
229 } else if ( (nls = load_nls(name)) == NULL) {
230 printk (KERN_ERR "smbfs: failed to load nls '%s'\n", name);
231 return -EINVAL;
232 }
233
234 /* if already set, unload the previous one. */
235 if (*p && *p != &unicode_table)
236 unload_nls(*p);
237 *p = nls;
238
239 return 0;
240}
241
242/* Handles all changes to codepage settings. */
243int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp)
244{
245 int n = 0;
246
247 smb_lock_server(server);
248
249 /* Don't load any nls_* at all, if no remote is requested */
250 if (!*cp->remote_name)
251 goto out;
252
253 /* local */
254 n = setcodepage(&server->local_nls, cp->local_name);
255 if (n != 0)
256 goto out;
257
258 /* remote */
259 if (!strcmp(cp->remote_name, "unicode")) {
260 server->remote_nls = &unicode_table;
261 } else {
262 n = setcodepage(&server->remote_nls, cp->remote_name);
263 if (n != 0)
264 setcodepage(&server->local_nls, NULL);
265 }
266
267out:
268 if (server->local_nls != NULL && server->remote_nls != NULL)
269 server->ops->convert = convert_cp;
270 else
271 server->ops->convert = convert_memcpy;
272
273 smb_unlock_server(server);
274 return n;
275}
276
277
278/*****************************************************************************/
279/* */
280/* Encoding/Decoding section */
281/* */
282/*****************************************************************************/
283
284static __u8 *
285smb_encode_smb_length(__u8 * p, __u32 len)
286{
287 *p = 0;
288 *(p+1) = 0;
289 *(p+2) = (len & 0xFF00) >> 8;
290 *(p+3) = (len & 0xFF);
291 if (len > 0xFFFF)
292 {
293 *(p+1) = 1;
294 }
295 return p + 4;
296}
297
298/*
299 * smb_build_path: build the path to entry and name storing it in buf.
300 * The path returned will have the trailing '\0'.
301 */
302static int smb_build_path(struct smb_sb_info *server, unsigned char *buf,
303 int maxlen,
304 struct dentry *entry, struct qstr *name)
305{
306 unsigned char *path = buf;
307 int len;
308 int unicode = (server->mnt->flags & SMB_MOUNT_UNICODE) != 0;
309
310 if (maxlen < (2<<unicode))
311 return -ENAMETOOLONG;
312
313 if (maxlen > SMB_MAXPATHLEN + 1)
314 maxlen = SMB_MAXPATHLEN + 1;
315
316 if (entry == NULL)
317 goto test_name_and_out;
318
319 /*
320 * If IS_ROOT, we have to do no walking at all.
321 */
322 if (IS_ROOT(entry) && !name) {
323 *path++ = '\\';
324 if (unicode) *path++ = '\0';
325 *path++ = '\0';
326 if (unicode) *path++ = '\0';
327 return path-buf;
328 }
329
330 /*
331 * Build the path string walking the tree backward from end to ROOT
332 * and store it in reversed order [see reverse_string()]
333 */
334 dget(entry);
335 spin_lock(&entry->d_lock);
336 while (!IS_ROOT(entry)) {
337 struct dentry *parent;
338
339 if (maxlen < (3<<unicode)) {
340 spin_unlock(&entry->d_lock);
341 dput(entry);
342 return -ENAMETOOLONG;
343 }
344
345 len = server->ops->convert(path, maxlen-2,
346 entry->d_name.name, entry->d_name.len,
347 server->local_nls, server->remote_nls);
348 if (len < 0) {
349 spin_unlock(&entry->d_lock);
350 dput(entry);
351 return len;
352 }
353 reverse_string(path, len);
354 path += len;
355 if (unicode) {
356 /* Note: reverse order */
357 *path++ = '\0';
358 maxlen--;
359 }
360 *path++ = '\\';
361 maxlen -= len+1;
362
363 parent = entry->d_parent;
364 dget(parent);
365 spin_unlock(&entry->d_lock);
366 dput(entry);
367 entry = parent;
368 spin_lock(&entry->d_lock);
369 }
370 spin_unlock(&entry->d_lock);
371 dput(entry);
372 reverse_string(buf, path-buf);
373
374 /* maxlen has space for at least one char */
375test_name_and_out:
376 if (name) {
377 if (maxlen < (3<<unicode))
378 return -ENAMETOOLONG;
379 *path++ = '\\';
380 if (unicode) {
381 *path++ = '\0';
382 maxlen--;
383 }
384 len = server->ops->convert(path, maxlen-2,
385 name->name, name->len,
386 server->local_nls, server->remote_nls);
387 if (len < 0)
388 return len;
389 path += len;
390 maxlen -= len+1;
391 }
392 /* maxlen has space for at least one char */
393 *path++ = '\0';
394 if (unicode) *path++ = '\0';
395 return path-buf;
396}
397
398static int smb_encode_path(struct smb_sb_info *server, char *buf, int maxlen,
399 struct dentry *dir, struct qstr *name)
400{
401 int result;
402
403 result = smb_build_path(server, buf, maxlen, dir, name);
404 if (result < 0)
405 goto out;
406 if (server->opt.protocol <= SMB_PROTOCOL_COREPLUS)
407 str_upper(buf, result);
408out:
409 return result;
410}
411
412/* encode_path for non-trans2 request SMBs */
413static int smb_simple_encode_path(struct smb_request *req, char **p,
414 struct dentry * entry, struct qstr * name)
415{
416 struct smb_sb_info *server = req->rq_server;
417 char *s = *p;
418 int res;
419 int maxlen = ((char *)req->rq_buffer + req->rq_bufsize) - s;
420 int unicode = (server->mnt->flags & SMB_MOUNT_UNICODE);
421
422 if (!maxlen)
423 return -ENAMETOOLONG;
424 *s++ = 4; /* ASCII data format */
425
426 /*
427 * SMB Unicode strings must be 16bit aligned relative the start of the
428 * packet. If they are not they must be padded with 0.
429 */
430 if (unicode) {
431 int align = s - (char *)req->rq_buffer;
432 if (!(align & 1)) {
433 *s++ = '\0';
434 maxlen--;
435 }
436 }
437
438 res = smb_encode_path(server, s, maxlen-1, entry, name);
439 if (res < 0)
440 return res;
441 *p = s + res;
442 return 0;
443}
444
445/* The following are taken directly from msdos-fs */
446
447/* Linear day numbers of the respective 1sts in non-leap years. */
448
449static int day_n[] =
450{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
451 /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
452
453
454static time_t
455utc2local(struct smb_sb_info *server, time_t time)
456{
457 return time - server->opt.serverzone*60;
458}
459
460static time_t
461local2utc(struct smb_sb_info *server, time_t time)
462{
463 return time + server->opt.serverzone*60;
464}
465
466/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
467
468static time_t
469date_dos2unix(struct smb_sb_info *server, __u16 date, __u16 time)
470{
471 int month, year;
472 time_t secs;
473
474 /* first subtract and mask after that... Otherwise, if
475 date == 0, bad things happen */
476 month = ((date >> 5) - 1) & 15;
477 year = date >> 9;
478 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 86400 *
479 ((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 - ((year & 3) == 0 &&
480 month < 2 ? 1 : 0) + 3653);
481 /* days since 1.1.70 plus 80's leap day */
482 return local2utc(server, secs);
483}
484
485
486/* Convert linear UNIX date to a MS-DOS time/date pair. */
487
488static void
489date_unix2dos(struct smb_sb_info *server,
490 int unix_date, __u16 *date, __u16 *time)
491{
492 int day, year, nl_day, month;
493
494 unix_date = utc2local(server, unix_date);
495 if (unix_date < 315532800)
496 unix_date = 315532800;
497
498 *time = (unix_date % 60) / 2 +
499 (((unix_date / 60) % 60) << 5) +
500 (((unix_date / 3600) % 24) << 11);
501
502 day = unix_date / 86400 - 3652;
503 year = day / 365;
504 if ((year + 3) / 4 + 365 * year > day)
505 year--;
506 day -= (year + 3) / 4 + 365 * year;
507 if (day == 59 && !(year & 3)) {
508 nl_day = day;
509 month = 2;
510 } else {
511 nl_day = (year & 3) || day <= 59 ? day : day - 1;
512 for (month = 1; month < 12; month++)
513 if (day_n[month] > nl_day)
514 break;
515 }
516 *date = nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9);
517}
518
519/* The following are taken from fs/ntfs/util.c */
520
521#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000)
522
523/*
524 * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units)
525 * into Unix UTC (based 1970-01-01, in seconds).
526 */
527static struct timespec
528smb_ntutc2unixutc(u64 ntutc)
529{
530 struct timespec ts;
531 /* FIXME: what about the timezone difference? */
532 /* Subtract the NTFS time offset, then convert to 1s intervals. */
533 u64 t = ntutc - NTFS_TIME_OFFSET;
534 ts.tv_nsec = do_div(t, 10000000) * 100;
535 ts.tv_sec = t;
536 return ts;
537}
538
539/* Convert the Unix UTC into NT time */
540static u64
541smb_unixutc2ntutc(struct timespec ts)
542{
543 /* Note: timezone conversion is probably wrong. */
544 /* return ((u64)utc2local(server, t)) * 10000000 + NTFS_TIME_OFFSET; */
545 return ((u64)ts.tv_sec) * 10000000 + ts.tv_nsec/100 + NTFS_TIME_OFFSET;
546}
547
548#define MAX_FILE_MODE 6
549static mode_t file_mode[] = {
550 S_IFREG, S_IFDIR, S_IFLNK, S_IFCHR, S_IFBLK, S_IFIFO, S_IFSOCK
551};
552
553static int smb_filetype_to_mode(u32 filetype)
554{
555 if (filetype > MAX_FILE_MODE) {
556 PARANOIA("Filetype out of range: %d\n", filetype);
557 return S_IFREG;
558 }
559 return file_mode[filetype];
560}
561
562static u32 smb_filetype_from_mode(int mode)
563{
564 if (S_ISREG(mode))
565 return UNIX_TYPE_FILE;
566 if (S_ISDIR(mode))
567 return UNIX_TYPE_DIR;
568 if (S_ISLNK(mode))
569 return UNIX_TYPE_SYMLINK;
570 if (S_ISCHR(mode))
571 return UNIX_TYPE_CHARDEV;
572 if (S_ISBLK(mode))
573 return UNIX_TYPE_BLKDEV;
574 if (S_ISFIFO(mode))
575 return UNIX_TYPE_FIFO;
576 if (S_ISSOCK(mode))
577 return UNIX_TYPE_SOCKET;
578 return UNIX_TYPE_UNKNOWN;
579}
580
581
582/*****************************************************************************/
583/* */
584/* Support section. */
585/* */
586/*****************************************************************************/
587
588__u32
589smb_len(__u8 * p)
590{
591 return ((*(p+1) & 0x1) << 16L) | (*(p+2) << 8L) | *(p+3);
592}
593
594static __u16
595smb_bcc(__u8 * packet)
596{
597 int pos = SMB_HEADER_LEN + SMB_WCT(packet) * sizeof(__u16);
598 return WVAL(packet, pos);
599}
600
601/* smb_valid_packet: We check if packet fulfills the basic
602 requirements of a smb packet */
603
604static int
605smb_valid_packet(__u8 * packet)
606{
607 return (packet[4] == 0xff
608 && packet[5] == 'S'
609 && packet[6] == 'M'
610 && packet[7] == 'B'
611 && (smb_len(packet) + 4 == SMB_HEADER_LEN
612 + SMB_WCT(packet) * 2 + smb_bcc(packet)));
613}
614
615/* smb_verify: We check if we got the answer we expected, and if we
616 got enough data. If bcc == -1, we don't care. */
617
618static int
619smb_verify(__u8 * packet, int command, int wct, int bcc)
620{
621 if (SMB_CMD(packet) != command)
622 goto bad_command;
623 if (SMB_WCT(packet) < wct)
624 goto bad_wct;
625 if (bcc != -1 && smb_bcc(packet) < bcc)
626 goto bad_bcc;
627 return 0;
628
629bad_command:
630 printk(KERN_ERR "smb_verify: command=%x, SMB_CMD=%x??\n",
631 command, SMB_CMD(packet));
632 goto fail;
633bad_wct:
634 printk(KERN_ERR "smb_verify: command=%x, wct=%d, SMB_WCT=%d??\n",
635 command, wct, SMB_WCT(packet));
636 goto fail;
637bad_bcc:
638 printk(KERN_ERR "smb_verify: command=%x, bcc=%d, SMB_BCC=%d??\n",
639 command, bcc, smb_bcc(packet));
640fail:
641 return -EIO;
642}
643
644/*
645 * Returns the maximum read or write size for the "payload". Making all of the
646 * packet fit within the negotiated max_xmit size.
647 *
648 * N.B. Since this value is usually computed before locking the server,
649 * the server's packet size must never be decreased!
650 */
651static inline int
652smb_get_xmitsize(struct smb_sb_info *server, int overhead)
653{
654 return server->opt.max_xmit - overhead;
655}
656
657/*
658 * Calculate the maximum read size
659 */
660int
661smb_get_rsize(struct smb_sb_info *server)
662{
663 /* readX has 12 parameters, read has 5 */
664 int overhead = SMB_HEADER_LEN + 12 * sizeof(__u16) + 2 + 1 + 2;
665 int size = smb_get_xmitsize(server, overhead);
666
667 VERBOSE("xmit=%d, size=%d\n", server->opt.max_xmit, size);
668
669 return size;
670}
671
672/*
673 * Calculate the maximum write size
674 */
675int
676smb_get_wsize(struct smb_sb_info *server)
677{
678 /* writeX has 14 parameters, write has 5 */
679 int overhead = SMB_HEADER_LEN + 14 * sizeof(__u16) + 2 + 1 + 2;
680 int size = smb_get_xmitsize(server, overhead);
681
682 VERBOSE("xmit=%d, size=%d\n", server->opt.max_xmit, size);
683
684 return size;
685}
686
687/*
688 * Convert SMB error codes to -E... errno values.
689 */
690int
691smb_errno(struct smb_request *req)
692{
693 int errcls = req->rq_rcls;
694 int error = req->rq_err;
695 char *class = "Unknown";
696
697 VERBOSE("errcls %d code %d from command 0x%x\n",
698 errcls, error, SMB_CMD(req->rq_header));
699
700 if (errcls == ERRDOS) {
701 switch (error) {
702 case ERRbadfunc:
703 return -EINVAL;
704 case ERRbadfile:
705 case ERRbadpath:
706 return -ENOENT;
707 case ERRnofids:
708 return -EMFILE;
709 case ERRnoaccess:
710 return -EACCES;
711 case ERRbadfid:
712 return -EBADF;
713 case ERRbadmcb:
714 return -EREMOTEIO;
715 case ERRnomem:
716 return -ENOMEM;
717 case ERRbadmem:
718 return -EFAULT;
719 case ERRbadenv:
720 case ERRbadformat:
721 return -EREMOTEIO;
722 case ERRbadaccess:
723 return -EACCES;
724 case ERRbaddata:
725 return -E2BIG;
726 case ERRbaddrive:
727 return -ENXIO;
728 case ERRremcd:
729 return -EREMOTEIO;
730 case ERRdiffdevice:
731 return -EXDEV;
732 case ERRnofiles:
733 return -ENOENT;
734 case ERRbadshare:
735 return -ETXTBSY;
736 case ERRlock:
737 return -EDEADLK;
738 case ERRfilexists:
739 return -EEXIST;
740 case ERROR_INVALID_PARAMETER:
741 return -EINVAL;
742 case ERROR_DISK_FULL:
743 return -ENOSPC;
744 case ERROR_INVALID_NAME:
745 return -ENOENT;
746 case ERROR_DIR_NOT_EMPTY:
747 return -ENOTEMPTY;
748 case ERROR_NOT_LOCKED:
749 return -ENOLCK;
750 case ERROR_ALREADY_EXISTS:
751 return -EEXIST;
752 default:
753 class = "ERRDOS";
754 goto err_unknown;
755 }
756 } else if (errcls == ERRSRV) {
757 switch (error) {
758 /* N.B. This is wrong ... EIO ? */
759 case ERRerror:
760 return -ENFILE;
761 case ERRbadpw:
762 return -EINVAL;
763 case ERRbadtype:
764 case ERRtimeout:
765 return -EIO;
766 case ERRaccess:
767 return -EACCES;
768 /*
769 * This is a fatal error, as it means the "tree ID"
770 * for this connection is no longer valid. We map
771 * to a special error code and get a new connection.
772 */
773 case ERRinvnid:
774 return -EBADSLT;
775 default:
776 class = "ERRSRV";
777 goto err_unknown;
778 }
779 } else if (errcls == ERRHRD) {
780 switch (error) {
781 case ERRnowrite:
782 return -EROFS;
783 case ERRbadunit:
784 return -ENODEV;
785 case ERRnotready:
786 return -EUCLEAN;
787 case ERRbadcmd:
788 case ERRdata:
789 return -EIO;
790 case ERRbadreq:
791 return -ERANGE;
792 case ERRbadshare:
793 return -ETXTBSY;
794 case ERRlock:
795 return -EDEADLK;
796 case ERRdiskfull:
797 return -ENOSPC;
798 default:
799 class = "ERRHRD";
800 goto err_unknown;
801 }
802 } else if (errcls == ERRCMD) {
803 class = "ERRCMD";
804 } else if (errcls == SUCCESS) {
805 return 0; /* This is the only valid 0 return */
806 }
807
808err_unknown:
809 printk(KERN_ERR "smb_errno: class %s, code %d from command 0x%x\n",
810 class, error, SMB_CMD(req->rq_header));
811 return -EIO;
812}
813
814/* smb_request_ok: We expect the server to be locked. Then we do the
815 request and check the answer completely. When smb_request_ok
816 returns 0, you can be quite sure that everything went well. When
817 the answer is <=0, the returned number is a valid unix errno. */
818
819static int
820smb_request_ok(struct smb_request *req, int command, int wct, int bcc)
821{
822 int result;
823
824 req->rq_resp_wct = wct;
825 req->rq_resp_bcc = bcc;
826
827 result = smb_add_request(req);
828 if (result != 0) {
829 DEBUG1("smb_request failed\n");
830 goto out;
831 }
832
833 if (smb_valid_packet(req->rq_header) != 0) {
834 PARANOIA("invalid packet!\n");
835 goto out;
836 }
837
838 result = smb_verify(req->rq_header, command, wct, bcc);
839
840out:
841 return result;
842}
843
844/*
845 * This implements the NEWCONN ioctl. It installs the server pid,
846 * sets server->state to CONN_VALID, and wakes up the waiting process.
847 */
848int
849smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
850{
851 struct file *filp;
852 struct sock *sk;
853 int error;
854
855 VERBOSE("fd=%d, pid=%d\n", opt->fd, current->pid);
856
857 smb_lock_server(server);
858
859 /*
860 * Make sure we don't already have a valid connection ...
861 */
862 error = -EINVAL;
863 if (server->state == CONN_VALID)
864 goto out;
865
866 error = -EACCES;
867 if (current_uid() != server->mnt->mounted_uid &&
868 !capable(CAP_SYS_ADMIN))
869 goto out;
870
871 error = -EBADF;
872 filp = fget(opt->fd);
873 if (!filp)
874 goto out;
875 if (!smb_valid_socket(filp->f_path.dentry->d_inode))
876 goto out_putf;
877
878 server->sock_file = filp;
879 server->conn_pid = get_pid(task_pid(current));
880 server->opt = *opt;
881 server->generation += 1;
882 server->state = CONN_VALID;
883 error = 0;
884
885 if (server->conn_error) {
886 /*
887 * conn_error is the returncode we originally decided to
888 * drop the old connection on. This message should be positive
889 * and not make people ask questions on why smbfs is printing
890 * error messages ...
891 */
892 printk(KERN_INFO "SMB connection re-established (%d)\n",
893 server->conn_error);
894 server->conn_error = 0;
895 }
896
897 /*
898 * Store the server in sock user_data (Only used by sunrpc)
899 */
900 sk = SOCKET_I(filp->f_path.dentry->d_inode)->sk;
901 sk->sk_user_data = server;
902
903 /* chain into the data_ready callback */
904 server->data_ready = xchg(&sk->sk_data_ready, smb_data_ready);
905
906 /* check if we have an old smbmount that uses seconds for the
907 serverzone */
908 if (server->opt.serverzone > 12*60 || server->opt.serverzone < -12*60)
909 server->opt.serverzone /= 60;
910
911 /* now that we have an established connection we can detect the server
912 type and enable bug workarounds */
913 if (server->opt.protocol < SMB_PROTOCOL_LANMAN2)
914 install_ops(server->ops, &smb_ops_core);
915 else if (server->opt.protocol == SMB_PROTOCOL_LANMAN2)
916 install_ops(server->ops, &smb_ops_os2);
917 else if (server->opt.protocol == SMB_PROTOCOL_NT1 &&
918 (server->opt.max_xmit < 0x1000) &&
919 !(server->opt.capabilities & SMB_CAP_NT_SMBS)) {
920 /* FIXME: can we kill the WIN95 flag now? */
921 server->mnt->flags |= SMB_MOUNT_WIN95;
922 VERBOSE("detected WIN95 server\n");
923 install_ops(server->ops, &smb_ops_win95);
924 } else {
925 /*
926 * Samba has max_xmit 65535
927 * NT4spX has max_xmit 4536 (or something like that)
928 * win2k has ...
929 */
930 VERBOSE("detected NT1 (Samba, NT4/5) server\n");
931 install_ops(server->ops, &smb_ops_winNT);
932 }
933
934 /* FIXME: the win9x code wants to modify these ... (seek/trunc bug) */
935 if (server->mnt->flags & SMB_MOUNT_OLDATTR) {
936 server->ops->getattr = smb_proc_getattr_core;
937 } else if (server->mnt->flags & SMB_MOUNT_DIRATTR) {
938 server->ops->getattr = smb_proc_getattr_ff;
939 }
940
941 /* Decode server capabilities */
942 if (server->opt.capabilities & SMB_CAP_LARGE_FILES) {
943 /* Should be ok to set this now, as no one can access the
944 mount until the connection has been established. */
945 SB_of(server)->s_maxbytes = ~0ULL >> 1;
946 VERBOSE("LFS enabled\n");
947 }
948 if (server->opt.capabilities & SMB_CAP_UNICODE) {
949 server->mnt->flags |= SMB_MOUNT_UNICODE;
950 VERBOSE("Unicode enabled\n");
951 } else {
952 server->mnt->flags &= ~SMB_MOUNT_UNICODE;
953 }
954#if 0
955 /* flags we may test for other patches ... */
956 if (server->opt.capabilities & SMB_CAP_LARGE_READX) {
957 VERBOSE("Large reads enabled\n");
958 }
959 if (server->opt.capabilities & SMB_CAP_LARGE_WRITEX) {
960 VERBOSE("Large writes enabled\n");
961 }
962#endif
963 if (server->opt.capabilities & SMB_CAP_UNIX) {
964 struct inode *inode;
965 VERBOSE("Using UNIX CIFS extensions\n");
966 install_ops(server->ops, &smb_ops_unix);
967 inode = SB_of(server)->s_root->d_inode;
968 if (inode)
969 inode->i_op = &smb_dir_inode_operations_unix;
970 }
971
972 VERBOSE("protocol=%d, max_xmit=%d, pid=%d capabilities=0x%x\n",
973 server->opt.protocol, server->opt.max_xmit,
974 pid_nr(server->conn_pid), server->opt.capabilities);
975
976 /* FIXME: this really should be done by smbmount. */
977 if (server->opt.max_xmit > SMB_MAX_PACKET_SIZE) {
978 server->opt.max_xmit = SMB_MAX_PACKET_SIZE;
979 }
980
981 smb_unlock_server(server);
982 smbiod_wake_up();
983 if (server->opt.capabilities & SMB_CAP_UNIX)
984 smb_proc_query_cifsunix(server);
985
986 server->conn_complete++;
987 wake_up_interruptible_all(&server->conn_wq);
988 return error;
989
990out:
991 smb_unlock_server(server);
992 smbiod_wake_up();
993 return error;
994
995out_putf:
996 fput(filp);
997 goto out;
998}
999
1000/* smb_setup_header: We completely set up the packet. You only have to
1001 insert the command-specific fields */
1002
1003__u8 *
1004smb_setup_header(struct smb_request *req, __u8 command, __u16 wct, __u16 bcc)
1005{
1006 __u32 xmit_len = SMB_HEADER_LEN + wct * sizeof(__u16) + bcc + 2;
1007 __u8 *p = req->rq_header;
1008 struct smb_sb_info *server = req->rq_server;
1009
1010 p = smb_encode_smb_length(p, xmit_len - 4);
1011
1012 *p++ = 0xff;
1013 *p++ = 'S';
1014 *p++ = 'M';
1015 *p++ = 'B';
1016 *p++ = command;
1017
1018 memset(p, '\0', 19);
1019 p += 19;
1020 p += 8;
1021
1022 if (server->opt.protocol > SMB_PROTOCOL_CORE) {
1023 int flags = SMB_FLAGS_CASELESS_PATHNAMES;
1024 int flags2 = SMB_FLAGS2_LONG_PATH_COMPONENTS |
1025 SMB_FLAGS2_EXTENDED_ATTRIBUTES; /* EA? not really ... */
1026
1027 *(req->rq_header + smb_flg) = flags;
1028 if (server->mnt->flags & SMB_MOUNT_UNICODE)
1029 flags2 |= SMB_FLAGS2_UNICODE_STRINGS;
1030 WSET(req->rq_header, smb_flg2, flags2);
1031 }
1032 *p++ = wct; /* wct */
1033 p += 2 * wct;
1034 WSET(p, 0, bcc);
1035
1036 /* Include the header in the data to send */
1037 req->rq_iovlen = 1;
1038 req->rq_iov[0].iov_base = req->rq_header;
1039 req->rq_iov[0].iov_len = xmit_len - bcc;
1040
1041 return req->rq_buffer;
1042}
1043
1044static void
1045smb_setup_bcc(struct smb_request *req, __u8 *p)
1046{
1047 u16 bcc = p - req->rq_buffer;
1048 u8 *pbcc = req->rq_header + SMB_HEADER_LEN + 2*SMB_WCT(req->rq_header);
1049
1050 WSET(pbcc, 0, bcc);
1051
1052 smb_encode_smb_length(req->rq_header, SMB_HEADER_LEN +
1053 2*SMB_WCT(req->rq_header) - 2 + bcc);
1054
1055 /* Include the "bytes" in the data to send */
1056 req->rq_iovlen = 2;
1057 req->rq_iov[1].iov_base = req->rq_buffer;
1058 req->rq_iov[1].iov_len = bcc;
1059}
1060
1061static int
1062smb_proc_seek(struct smb_sb_info *server, __u16 fileid,
1063 __u16 mode, off_t offset)
1064{
1065 int result;
1066 struct smb_request *req;
1067
1068 result = -ENOMEM;
1069 if (! (req = smb_alloc_request(server, 0)))
1070 goto out;
1071
1072 smb_setup_header(req, SMBlseek, 4, 0);
1073 WSET(req->rq_header, smb_vwv0, fileid);
1074 WSET(req->rq_header, smb_vwv1, mode);
1075 DSET(req->rq_header, smb_vwv2, offset);
1076 req->rq_flags |= SMB_REQ_NORETRY;
1077
1078 result = smb_request_ok(req, SMBlseek, 2, 0);
1079 if (result < 0) {
1080 result = 0;
1081 goto out_free;
1082 }
1083
1084 result = DVAL(req->rq_header, smb_vwv0);
1085out_free:
1086 smb_rput(req);
1087out:
1088 return result;
1089}
1090
1091static int
1092smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish)
1093{
1094 struct inode *ino = dentry->d_inode;
1095 struct smb_inode_info *ei = SMB_I(ino);
1096 int mode, read_write = 0x42, read_only = 0x40;
1097 int res;
1098 char *p;
1099 struct smb_request *req;
1100
1101 /*
1102 * Attempt to open r/w, unless there are no write privileges.
1103 */
1104 mode = read_write;
1105 if (!(ino->i_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
1106 mode = read_only;
1107#if 0
1108 /* FIXME: why is this code not in? below we fix it so that a caller
1109 wanting RO doesn't get RW. smb_revalidate_inode does some
1110 optimization based on access mode. tail -f needs it to be correct.
1111
1112 We must open rw since we don't do the open if called a second time
1113 with different 'wish'. Is that not supported by smb servers? */
1114 if (!(wish & (O_WRONLY | O_RDWR)))
1115 mode = read_only;
1116#endif
1117
1118 res = -ENOMEM;
1119 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
1120 goto out;
1121
1122 retry:
1123 p = smb_setup_header(req, SMBopen, 2, 0);
1124 WSET(req->rq_header, smb_vwv0, mode);
1125 WSET(req->rq_header, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);
1126 res = smb_simple_encode_path(req, &p, dentry, NULL);
1127 if (res < 0)
1128 goto out_free;
1129 smb_setup_bcc(req, p);
1130
1131 res = smb_request_ok(req, SMBopen, 7, 0);
1132 if (res != 0) {
1133 if (mode == read_write &&
1134 (res == -EACCES || res == -ETXTBSY || res == -EROFS))
1135 {
1136 VERBOSE("%s/%s R/W failed, error=%d, retrying R/O\n",
1137 DENTRY_PATH(dentry), res);
1138 mode = read_only;
1139 req->rq_flags = 0;
1140 goto retry;
1141 }
1142 goto out_free;
1143 }
1144 /* We should now have data in vwv[0..6]. */
1145
1146 ei->fileid = WVAL(req->rq_header, smb_vwv0);
1147 ei->attr = WVAL(req->rq_header, smb_vwv1);
1148 /* smb_vwv2 has mtime */
1149 /* smb_vwv4 has size */
1150 ei->access = (WVAL(req->rq_header, smb_vwv6) & SMB_ACCMASK);
1151 ei->open = server->generation;
1152
1153out_free:
1154 smb_rput(req);
1155out:
1156 return res;
1157}
1158
1159/*
1160 * Make sure the file is open, and check that the access
1161 * is compatible with the desired access.
1162 */
1163int
1164smb_open(struct dentry *dentry, int wish)
1165{
1166 struct inode *inode = dentry->d_inode;
1167 int result;
1168 __u16 access;
1169
1170 result = -ENOENT;
1171 if (!inode) {
1172 printk(KERN_ERR "smb_open: no inode for dentry %s/%s\n",
1173 DENTRY_PATH(dentry));
1174 goto out;
1175 }
1176
1177 if (!smb_is_open(inode)) {
1178 struct smb_sb_info *server = server_from_inode(inode);
1179 result = 0;
1180 if (!smb_is_open(inode))
1181 result = smb_proc_open(server, dentry, wish);
1182 if (result)
1183 goto out;
1184 /*
1185 * A successful open means the path is still valid ...
1186 */
1187 smb_renew_times(dentry);
1188 }
1189
1190 /*
1191 * Check whether the access is compatible with the desired mode.
1192 */
1193 result = 0;
1194 access = SMB_I(inode)->access;
1195 if (access != wish && access != SMB_O_RDWR) {
1196 PARANOIA("%s/%s access denied, access=%x, wish=%x\n",
1197 DENTRY_PATH(dentry), access, wish);
1198 result = -EACCES;
1199 }
1200out:
1201 return result;
1202}
1203
1204static int
1205smb_proc_close(struct smb_sb_info *server, __u16 fileid, __u32 mtime)
1206{
1207 struct smb_request *req;
1208 int result = -ENOMEM;
1209
1210 if (! (req = smb_alloc_request(server, 0)))
1211 goto out;
1212
1213 smb_setup_header(req, SMBclose, 3, 0);
1214 WSET(req->rq_header, smb_vwv0, fileid);
1215 DSET(req->rq_header, smb_vwv1, utc2local(server, mtime));
1216 req->rq_flags |= SMB_REQ_NORETRY;
1217 result = smb_request_ok(req, SMBclose, 0, 0);
1218
1219 smb_rput(req);
1220out:
1221 return result;
1222}
1223
1224/*
1225 * Win NT 4.0 has an apparent bug in that it fails to update the
1226 * modify time when writing to a file. As a workaround, we update
1227 * both modify and access time locally, and post the times to the
1228 * server when closing the file.
1229 */
1230static int
1231smb_proc_close_inode(struct smb_sb_info *server, struct inode * ino)
1232{
1233 struct smb_inode_info *ei = SMB_I(ino);
1234 int result = 0;
1235 if (smb_is_open(ino))
1236 {
1237 /*
1238 * We clear the open flag in advance, in case another
1239 * process observes the value while we block below.
1240 */
1241 ei->open = 0;
1242
1243 /*
1244 * Kludge alert: SMB timestamps are accurate only to
1245 * two seconds ... round the times to avoid needless
1246 * cache invalidations!
1247 */
1248 if (ino->i_mtime.tv_sec & 1) {
1249 ino->i_mtime.tv_sec--;
1250 ino->i_mtime.tv_nsec = 0;
1251 }
1252 if (ino->i_atime.tv_sec & 1) {
1253 ino->i_atime.tv_sec--;
1254 ino->i_atime.tv_nsec = 0;
1255 }
1256 /*
1257 * If the file is open with write permissions,
1258 * update the time stamps to sync mtime and atime.
1259 */
1260 if ((server->opt.capabilities & SMB_CAP_UNIX) == 0 &&
1261 (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) &&
1262 !(ei->access == SMB_O_RDONLY))
1263 {
1264 struct smb_fattr fattr;
1265 smb_get_inode_attr(ino, &fattr);
1266 smb_proc_setattr_ext(server, ino, &fattr);
1267 }
1268
1269 result = smb_proc_close(server, ei->fileid, ino->i_mtime.tv_sec);
1270 /*
1271 * Force a revalidation after closing ... some servers
1272 * don't post the size until the file has been closed.
1273 */
1274 if (server->opt.protocol < SMB_PROTOCOL_NT1)
1275 ei->oldmtime = 0;
1276 ei->closed = jiffies;
1277 }
1278 return result;
1279}
1280
1281int
1282smb_close(struct inode *ino)
1283{
1284 int result = 0;
1285
1286 if (smb_is_open(ino)) {
1287 struct smb_sb_info *server = server_from_inode(ino);
1288 result = smb_proc_close_inode(server, ino);
1289 }
1290 return result;
1291}
1292
1293/*
1294 * This is used to close a file following a failed instantiate.
1295 * Since we don't have an inode, we can't use any of the above.
1296 */
1297int
1298smb_close_fileid(struct dentry *dentry, __u16 fileid)
1299{
1300 struct smb_sb_info *server = server_from_dentry(dentry);
1301 int result;
1302
1303 result = smb_proc_close(server, fileid, get_seconds());
1304 return result;
1305}
1306
1307/* In smb_proc_read and smb_proc_write we do not retry, because the
1308 file-id would not be valid after a reconnection. */
1309
1310static void
1311smb_proc_read_data(struct smb_request *req)
1312{
1313 req->rq_iov[0].iov_base = req->rq_buffer;
1314 req->rq_iov[0].iov_len = 3;
1315
1316 req->rq_iov[1].iov_base = req->rq_page;
1317 req->rq_iov[1].iov_len = req->rq_rsize;
1318 req->rq_iovlen = 2;
1319
1320 req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd;
1321}
1322
1323static int
1324smb_proc_read(struct inode *inode, loff_t offset, int count, char *data)
1325{
1326 struct smb_sb_info *server = server_from_inode(inode);
1327 __u16 returned_count, data_len;
1328 unsigned char *buf;
1329 int result;
1330 struct smb_request *req;
1331 u8 rbuf[4];
1332
1333 result = -ENOMEM;
1334 if (! (req = smb_alloc_request(server, 0)))
1335 goto out;
1336
1337 smb_setup_header(req, SMBread, 5, 0);
1338 buf = req->rq_header;
1339 WSET(buf, smb_vwv0, SMB_I(inode)->fileid);
1340 WSET(buf, smb_vwv1, count);
1341 DSET(buf, smb_vwv2, offset);
1342 WSET(buf, smb_vwv4, 0);
1343
1344 req->rq_page = data;
1345 req->rq_rsize = count;
1346 req->rq_callback = smb_proc_read_data;
1347 req->rq_buffer = rbuf;
1348 req->rq_flags |= SMB_REQ_NORETRY | SMB_REQ_STATIC;
1349
1350 result = smb_request_ok(req, SMBread, 5, -1);
1351 if (result < 0)
1352 goto out_free;
1353 returned_count = WVAL(req->rq_header, smb_vwv0);
1354
1355 data_len = WVAL(rbuf, 1);
1356
1357 if (returned_count != data_len) {
1358 printk(KERN_NOTICE "smb_proc_read: returned != data_len\n");
1359 printk(KERN_NOTICE "smb_proc_read: ret_c=%d, data_len=%d\n",
1360 returned_count, data_len);
1361 }
1362 result = data_len;
1363
1364out_free:
1365 smb_rput(req);
1366out:
1367 VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",
1368 inode->i_ino, SMB_I(inode)->fileid, count, result);
1369 return result;
1370}
1371
1372static int
1373smb_proc_write(struct inode *inode, loff_t offset, int count, const char *data)
1374{
1375 struct smb_sb_info *server = server_from_inode(inode);
1376 int result;
1377 u16 fileid = SMB_I(inode)->fileid;
1378 u8 buf[4];
1379 struct smb_request *req;
1380
1381 result = -ENOMEM;
1382 if (! (req = smb_alloc_request(server, 0)))
1383 goto out;
1384
1385 VERBOSE("ino=%ld, fileid=%d, count=%d@%Ld\n",
1386 inode->i_ino, fileid, count, offset);
1387
1388 smb_setup_header(req, SMBwrite, 5, count + 3);
1389 WSET(req->rq_header, smb_vwv0, fileid);
1390 WSET(req->rq_header, smb_vwv1, count);
1391 DSET(req->rq_header, smb_vwv2, offset);
1392 WSET(req->rq_header, smb_vwv4, 0);
1393
1394 buf[0] = 1;
1395 WSET(buf, 1, count); /* yes, again ... */
1396 req->rq_iov[1].iov_base = buf;
1397 req->rq_iov[1].iov_len = 3;
1398 req->rq_iov[2].iov_base = (char *) data;
1399 req->rq_iov[2].iov_len = count;
1400 req->rq_iovlen = 3;
1401 req->rq_flags |= SMB_REQ_NORETRY;
1402
1403 result = smb_request_ok(req, SMBwrite, 1, 0);
1404 if (result >= 0)
1405 result = WVAL(req->rq_header, smb_vwv0);
1406
1407 smb_rput(req);
1408out:
1409 return result;
1410}
1411
1412/*
1413 * In smb_proc_readX and smb_proc_writeX we do not retry, because the
1414 * file-id would not be valid after a reconnection.
1415 */
1416
1417#define SMB_READX_MAX_PAD 64
1418static void
1419smb_proc_readX_data(struct smb_request *req)
1420{
1421 /* header length, excluding the netbios length (-4) */
1422 int hdrlen = SMB_HEADER_LEN + req->rq_resp_wct*2 - 2;
1423 int data_off = WVAL(req->rq_header, smb_vwv6);
1424
1425 /*
1426 * Some genius made the padding to the data bytes arbitrary.
1427 * So we must first calculate the amount of padding used by the server.
1428 */
1429 data_off -= hdrlen;
1430 if (data_off > SMB_READX_MAX_PAD || data_off < 0) {
1431 PARANOIA("offset is larger than SMB_READX_MAX_PAD or negative!\n");
1432 PARANOIA("%d > %d || %d < 0\n", data_off, SMB_READX_MAX_PAD, data_off);
1433 req->rq_rlen = req->rq_bufsize + 1;
1434 return;
1435 }
1436 req->rq_iov[0].iov_base = req->rq_buffer;
1437 req->rq_iov[0].iov_len = data_off;
1438
1439 req->rq_iov[1].iov_base = req->rq_page;
1440 req->rq_iov[1].iov_len = req->rq_rsize;
1441 req->rq_iovlen = 2;
1442
1443 req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd;
1444}
1445
1446static int
1447smb_proc_readX(struct inode *inode, loff_t offset, int count, char *data)
1448{
1449 struct smb_sb_info *server = server_from_inode(inode);
1450 unsigned char *buf;
1451 int result;
1452 struct smb_request *req;
1453 static char pad[SMB_READX_MAX_PAD];
1454
1455 result = -ENOMEM;
1456 if (! (req = smb_alloc_request(server, 0)))
1457 goto out;
1458
1459 smb_setup_header(req, SMBreadX, 12, 0);
1460 buf = req->rq_header;
1461 WSET(buf, smb_vwv0, 0x00ff);
1462 WSET(buf, smb_vwv1, 0);
1463 WSET(buf, smb_vwv2, SMB_I(inode)->fileid);
1464 DSET(buf, smb_vwv3, (u32)offset); /* low 32 bits */
1465 WSET(buf, smb_vwv5, count);
1466 WSET(buf, smb_vwv6, 0);
1467 DSET(buf, smb_vwv7, 0);
1468 WSET(buf, smb_vwv9, 0);
1469 DSET(buf, smb_vwv10, (u32)(offset >> 32)); /* high 32 bits */
1470 WSET(buf, smb_vwv11, 0);
1471
1472 req->rq_page = data;
1473 req->rq_rsize = count;
1474 req->rq_callback = smb_proc_readX_data;
1475 req->rq_buffer = pad;
1476 req->rq_bufsize = SMB_READX_MAX_PAD;
1477 req->rq_flags |= SMB_REQ_STATIC | SMB_REQ_NORETRY;
1478
1479 result = smb_request_ok(req, SMBreadX, 12, -1);
1480 if (result < 0)
1481 goto out_free;
1482 result = WVAL(req->rq_header, smb_vwv5);
1483
1484out_free:
1485 smb_rput(req);
1486out:
1487 VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",
1488 inode->i_ino, SMB_I(inode)->fileid, count, result);
1489 return result;
1490}
1491
1492static int
1493smb_proc_writeX(struct inode *inode, loff_t offset, int count, const char *data)
1494{
1495 struct smb_sb_info *server = server_from_inode(inode);
1496 int result;
1497 u8 *p;
1498 static u8 pad[4];
1499 struct smb_request *req;
1500
1501 result = -ENOMEM;
1502 if (! (req = smb_alloc_request(server, 0)))
1503 goto out;
1504
1505 VERBOSE("ino=%ld, fileid=%d, count=%d@%Ld\n",
1506 inode->i_ino, SMB_I(inode)->fileid, count, offset);
1507
1508 p = smb_setup_header(req, SMBwriteX, 14, count + 1);
1509 WSET(req->rq_header, smb_vwv0, 0x00ff);
1510 WSET(req->rq_header, smb_vwv1, 0);
1511 WSET(req->rq_header, smb_vwv2, SMB_I(inode)->fileid);
1512 DSET(req->rq_header, smb_vwv3, (u32)offset); /* low 32 bits */
1513 DSET(req->rq_header, smb_vwv5, 0);
1514 WSET(req->rq_header, smb_vwv7, 0); /* write mode */
1515 WSET(req->rq_header, smb_vwv8, 0);
1516 WSET(req->rq_header, smb_vwv9, 0);
1517 WSET(req->rq_header, smb_vwv10, count); /* data length */
1518 WSET(req->rq_header, smb_vwv11, smb_vwv12 + 2 + 1);
1519 DSET(req->rq_header, smb_vwv12, (u32)(offset >> 32));
1520
1521 req->rq_iov[1].iov_base = pad;
1522 req->rq_iov[1].iov_len = 1;
1523 req->rq_iov[2].iov_base = (char *) data;
1524 req->rq_iov[2].iov_len = count;
1525 req->rq_iovlen = 3;
1526 req->rq_flags |= SMB_REQ_NORETRY;
1527
1528 result = smb_request_ok(req, SMBwriteX, 6, 0);
1529 if (result >= 0)
1530 result = WVAL(req->rq_header, smb_vwv2);
1531
1532 smb_rput(req);
1533out:
1534 return result;
1535}
1536
1537int
1538smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid)
1539{
1540 struct smb_sb_info *server = server_from_dentry(dentry);
1541 char *p;
1542 int result;
1543 struct smb_request *req;
1544
1545 result = -ENOMEM;
1546 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
1547 goto out;
1548
1549 p = smb_setup_header(req, SMBcreate, 3, 0);
1550 WSET(req->rq_header, smb_vwv0, attr);
1551 DSET(req->rq_header, smb_vwv1, utc2local(server, ctime));
1552 result = smb_simple_encode_path(req, &p, dentry, NULL);
1553 if (result < 0)
1554 goto out_free;
1555 smb_setup_bcc(req, p);
1556
1557 result = smb_request_ok(req, SMBcreate, 1, 0);
1558 if (result < 0)
1559 goto out_free;
1560
1561 *fileid = WVAL(req->rq_header, smb_vwv0);
1562 result = 0;
1563
1564out_free:
1565 smb_rput(req);
1566out:
1567 return result;
1568}
1569
1570int
1571smb_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry)
1572{
1573 struct smb_sb_info *server = server_from_dentry(old_dentry);
1574 char *p;
1575 int result;
1576 struct smb_request *req;
1577
1578 result = -ENOMEM;
1579 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
1580 goto out;
1581
1582 p = smb_setup_header(req, SMBmv, 1, 0);
1583 WSET(req->rq_header, smb_vwv0, aSYSTEM | aHIDDEN | aDIR);
1584 result = smb_simple_encode_path(req, &p, old_dentry, NULL);
1585 if (result < 0)
1586 goto out_free;
1587 result = smb_simple_encode_path(req, &p, new_dentry, NULL);
1588 if (result < 0)
1589 goto out_free;
1590 smb_setup_bcc(req, p);
1591
1592 if ((result = smb_request_ok(req, SMBmv, 0, 0)) < 0)
1593 goto out_free;
1594 result = 0;
1595
1596out_free:
1597 smb_rput(req);
1598out:
1599 return result;
1600}
1601
1602/*
1603 * Code common to mkdir and rmdir.
1604 */
1605static int
1606smb_proc_generic_command(struct dentry *dentry, __u8 command)
1607{
1608 struct smb_sb_info *server = server_from_dentry(dentry);
1609 char *p;
1610 int result;
1611 struct smb_request *req;
1612
1613 result = -ENOMEM;
1614 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
1615 goto out;
1616
1617 p = smb_setup_header(req, command, 0, 0);
1618 result = smb_simple_encode_path(req, &p, dentry, NULL);
1619 if (result < 0)
1620 goto out_free;
1621 smb_setup_bcc(req, p);
1622
1623 result = smb_request_ok(req, command, 0, 0);
1624 if (result < 0)
1625 goto out_free;
1626 result = 0;
1627
1628out_free:
1629 smb_rput(req);
1630out:
1631 return result;
1632}
1633
1634int
1635smb_proc_mkdir(struct dentry *dentry)
1636{
1637 return smb_proc_generic_command(dentry, SMBmkdir);
1638}
1639
1640int
1641smb_proc_rmdir(struct dentry *dentry)
1642{
1643 return smb_proc_generic_command(dentry, SMBrmdir);
1644}
1645
1646#if SMBFS_POSIX_UNLINK
1647/*
1648 * Removes readonly attribute from a file. Used by unlink to give posix
1649 * semantics.
1650 */
1651static int
1652smb_set_rw(struct dentry *dentry,struct smb_sb_info *server)
1653{
1654 int result;
1655 struct smb_fattr fattr;
1656
1657 /* FIXME: cifsUE should allow removing a readonly file. */
1658
1659 /* first get current attribute */
1660 smb_init_dirent(server, &fattr);
1661 result = server->ops->getattr(server, dentry, &fattr);
1662 smb_finish_dirent(server, &fattr);
1663 if (result < 0)
1664 return result;
1665
1666 /* if RONLY attribute is set, remove it */
1667 if (fattr.attr & aRONLY) { /* read only attribute is set */
1668 fattr.attr &= ~aRONLY;
1669 result = smb_proc_setattr_core(server, dentry, fattr.attr);
1670 }
1671 return result;
1672}
1673#endif
1674
1675int
1676smb_proc_unlink(struct dentry *dentry)
1677{
1678 struct smb_sb_info *server = server_from_dentry(dentry);
1679 int flag = 0;
1680 char *p;
1681 int result;
1682 struct smb_request *req;
1683
1684 result = -ENOMEM;
1685 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
1686 goto out;
1687
1688 retry:
1689 p = smb_setup_header(req, SMBunlink, 1, 0);
1690 WSET(req->rq_header, smb_vwv0, aSYSTEM | aHIDDEN);
1691 result = smb_simple_encode_path(req, &p, dentry, NULL);
1692 if (result < 0)
1693 goto out_free;
1694 smb_setup_bcc(req, p);
1695
1696 if ((result = smb_request_ok(req, SMBunlink, 0, 0)) < 0) {
1697#if SMBFS_POSIX_UNLINK
1698 if (result == -EACCES && !flag) {
1699 /* Posix semantics is for the read-only state
1700 of a file to be ignored in unlink(). In the
1701 SMB world a unlink() is refused on a
1702 read-only file. To make things easier for
1703 unix users we try to override the files
1704 permission if the unlink fails with the
1705 right error.
1706 This introduces a race condition that could
1707 lead to a file being written by someone who
1708 shouldn't have access, but as far as I can
1709 tell that is unavoidable */
1710
1711 /* remove RONLY attribute and try again */
1712 result = smb_set_rw(dentry,server);
1713 if (result == 0) {
1714 flag = 1;
1715 req->rq_flags = 0;
1716 goto retry;
1717 }
1718 }
1719#endif
1720 goto out_free;
1721 }
1722 result = 0;
1723
1724out_free:
1725 smb_rput(req);
1726out:
1727 return result;
1728}
1729
1730int
1731smb_proc_flush(struct smb_sb_info *server, __u16 fileid)
1732{
1733 int result;
1734 struct smb_request *req;
1735
1736 result = -ENOMEM;
1737 if (! (req = smb_alloc_request(server, 0)))
1738 goto out;
1739
1740 smb_setup_header(req, SMBflush, 1, 0);
1741 WSET(req->rq_header, smb_vwv0, fileid);
1742 req->rq_flags |= SMB_REQ_NORETRY;
1743 result = smb_request_ok(req, SMBflush, 0, 0);
1744
1745 smb_rput(req);
1746out:
1747 return result;
1748}
1749
1750static int
1751smb_proc_trunc32(struct inode *inode, loff_t length)
1752{
1753 /*
1754 * Writing 0bytes is old-SMB magic for truncating files.
1755 * MAX_NON_LFS should prevent this from being called with a too
1756 * large offset.
1757 */
1758 return smb_proc_write(inode, length, 0, NULL);
1759}
1760
1761static int
1762smb_proc_trunc64(struct inode *inode, loff_t length)
1763{
1764 struct smb_sb_info *server = server_from_inode(inode);
1765 int result;
1766 char *param;
1767 char *data;
1768 struct smb_request *req;
1769
1770 result = -ENOMEM;
1771 if (! (req = smb_alloc_request(server, 14)))
1772 goto out;
1773
1774 param = req->rq_buffer;
1775 data = req->rq_buffer + 6;
1776
1777 /* FIXME: must we also set allocation size? winNT seems to do that */
1778 WSET(param, 0, SMB_I(inode)->fileid);
1779 WSET(param, 2, SMB_SET_FILE_END_OF_FILE_INFO);
1780 WSET(param, 4, 0);
1781 LSET(data, 0, length);
1782
1783 req->rq_trans2_command = TRANSACT2_SETFILEINFO;
1784 req->rq_ldata = 8;
1785 req->rq_data = data;
1786 req->rq_lparm = 6;
1787 req->rq_parm = param;
1788 req->rq_flags |= SMB_REQ_NORETRY;
1789 result = smb_add_request(req);
1790 if (result < 0)
1791 goto out_free;
1792
1793 result = 0;
1794 if (req->rq_rcls != 0)
1795 result = smb_errno(req);
1796
1797out_free:
1798 smb_rput(req);
1799out:
1800 return result;
1801}
1802
1803static int
1804smb_proc_trunc95(struct inode *inode, loff_t length)
1805{
1806 struct smb_sb_info *server = server_from_inode(inode);
1807 int result = smb_proc_trunc32(inode, length);
1808
1809 /*
1810 * win9x doesn't appear to update the size immediately.
1811 * It will return the old file size after the truncate,
1812 * confusing smbfs. So we force an update.
1813 *
1814 * FIXME: is this still necessary?
1815 */
1816 smb_proc_flush(server, SMB_I(inode)->fileid);
1817 return result;
1818}
1819
1820static void
1821smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
1822{
1823 memset(fattr, 0, sizeof(*fattr));
1824
1825 fattr->f_nlink = 1;
1826 fattr->f_uid = server->mnt->uid;
1827 fattr->f_gid = server->mnt->gid;
1828 fattr->f_unix = 0;
1829}
1830
1831static void
1832smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
1833{
1834 if (fattr->f_unix)
1835 return;
1836
1837 fattr->f_mode = server->mnt->file_mode;
1838 if (fattr->attr & aDIR) {
1839 fattr->f_mode = server->mnt->dir_mode;
1840 fattr->f_size = SMB_ST_BLKSIZE;
1841 }
1842 /* Check the read-only flag */
1843 if (fattr->attr & aRONLY)
1844 fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
1845
1846 /* How many 512 byte blocks do we need for this file? */
1847 fattr->f_blocks = 0;
1848 if (fattr->f_size != 0)
1849 fattr->f_blocks = 1 + ((fattr->f_size-1) >> 9);
1850 return;
1851}
1852
1853void
1854smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr,
1855 struct super_block *sb)
1856{
1857 smb_init_dirent(server, fattr);
1858 fattr->attr = aDIR;
1859 fattr->f_ino = 2; /* traditional root inode number */
1860 fattr->f_mtime = current_fs_time(sb);
1861 smb_finish_dirent(server, fattr);
1862}
1863
1864/*
1865 * Decode a dirent for old protocols
1866 *
1867 * qname is filled with the decoded, and possibly translated, name.
1868 * fattr receives decoded attributes
1869 *
1870 * Bugs Noted:
1871 * (1) Pathworks servers may pad the name with extra spaces.
1872 */
1873static char *
1874smb_decode_short_dirent(struct smb_sb_info *server, char *p,
1875 struct qstr *qname, struct smb_fattr *fattr,
1876 unsigned char *name_buf)
1877{
1878 int len;
1879
1880 /*
1881 * SMB doesn't have a concept of inode numbers ...
1882 */
1883 smb_init_dirent(server, fattr);
1884 fattr->f_ino = 0; /* FIXME: do we need this? */
1885
1886 p += SMB_STATUS_SIZE; /* reserved (search_status) */
1887 fattr->attr = *p;
1888 fattr->f_mtime.tv_sec = date_dos2unix(server, WVAL(p, 3), WVAL(p, 1));
1889 fattr->f_mtime.tv_nsec = 0;
1890 fattr->f_size = DVAL(p, 5);
1891 fattr->f_ctime = fattr->f_mtime;
1892 fattr->f_atime = fattr->f_mtime;
1893 qname->name = p + 9;
1894 len = strnlen(qname->name, 12);
1895
1896 /*
1897 * Trim trailing blanks for Pathworks servers
1898 */
1899 while (len > 2 && qname->name[len-1] == ' ')
1900 len--;
1901
1902 smb_finish_dirent(server, fattr);
1903
1904#if 0
1905 /* FIXME: These only work for ascii chars, and recent smbmount doesn't
1906 allow the flag to be set anyway. It kills const. Remove? */
1907 switch (server->opt.case_handling) {
1908 case SMB_CASE_UPPER:
1909 str_upper(entry->name, len);
1910 break;
1911 case SMB_CASE_LOWER:
1912 str_lower(entry->name, len);
1913 break;
1914 default:
1915 break;
1916 }
1917#endif
1918
1919 qname->len = 0;
1920 len = server->ops->convert(name_buf, SMB_MAXNAMELEN,
1921 qname->name, len,
1922 server->remote_nls, server->local_nls);
1923 if (len > 0) {
1924 qname->len = len;
1925 qname->name = name_buf;
1926 DEBUG1("len=%d, name=%.*s\n",qname->len,qname->len,qname->name);
1927 }
1928
1929 return p + 22;
1930}
1931
1932/*
1933 * This routine is used to read in directory entries from the network.
1934 * Note that it is for short directory name seeks, i.e.: protocol <
1935 * SMB_PROTOCOL_LANMAN2
1936 */
1937static int
1938smb_proc_readdir_short(struct file *filp, void *dirent, filldir_t filldir,
1939 struct smb_cache_control *ctl)
1940{
1941 struct dentry *dir = filp->f_path.dentry;
1942 struct smb_sb_info *server = server_from_dentry(dir);
1943 struct qstr qname;
1944 struct smb_fattr fattr;
1945 char *p;
1946 int result;
1947 int i, first, entries_seen, entries;
1948 int entries_asked = (server->opt.max_xmit - 100) / SMB_DIRINFO_SIZE;
1949 __u16 bcc;
1950 __u16 count;
1951 char status[SMB_STATUS_SIZE];
1952 static struct qstr mask = {
1953 .name = "*.*",
1954 .len = 3,
1955 };
1956 unsigned char *last_status;
1957 struct smb_request *req;
1958 unsigned char *name_buf;
1959
1960 VERBOSE("%s/%s\n", DENTRY_PATH(dir));
1961
1962 lock_kernel();
1963
1964 result = -ENOMEM;
1965 if (! (name_buf = kmalloc(SMB_MAXNAMELEN, GFP_KERNEL)))
1966 goto out;
1967
1968 first = 1;
1969 entries = 0;
1970 entries_seen = 2; /* implicit . and .. */
1971
1972 result = -ENOMEM;
1973 if (! (req = smb_alloc_request(server, server->opt.max_xmit)))
1974 goto out_name;
1975
1976 while (1) {
1977 p = smb_setup_header(req, SMBsearch, 2, 0);
1978 WSET(req->rq_header, smb_vwv0, entries_asked);
1979 WSET(req->rq_header, smb_vwv1, aDIR);
1980 if (first == 1) {
1981 result = smb_simple_encode_path(req, &p, dir, &mask);
1982 if (result < 0)
1983 goto out_free;
1984 if (p + 3 > (char *)req->rq_buffer + req->rq_bufsize) {
1985 result = -ENAMETOOLONG;
1986 goto out_free;
1987 }
1988 *p++ = 5;
1989 WSET(p, 0, 0);
1990 p += 2;
1991 first = 0;
1992 } else {
1993 if (p + 5 + SMB_STATUS_SIZE >
1994 (char *)req->rq_buffer + req->rq_bufsize) {
1995 result = -ENAMETOOLONG;
1996 goto out_free;
1997 }
1998
1999 *p++ = 4;
2000 *p++ = 0;
2001 *p++ = 5;
2002 WSET(p, 0, SMB_STATUS_SIZE);
2003 p += 2;
2004 memcpy(p, status, SMB_STATUS_SIZE);
2005 p += SMB_STATUS_SIZE;
2006 }
2007
2008 smb_setup_bcc(req, p);
2009
2010 result = smb_request_ok(req, SMBsearch, 1, -1);
2011 if (result < 0) {
2012 if ((req->rq_rcls == ERRDOS) &&
2013 (req->rq_err == ERRnofiles))
2014 break;
2015 goto out_free;
2016 }
2017 count = WVAL(req->rq_header, smb_vwv0);
2018 if (count <= 0)
2019 break;
2020
2021 result = -EIO;
2022 bcc = smb_bcc(req->rq_header);
2023 if (bcc != count * SMB_DIRINFO_SIZE + 3)
2024 goto out_free;
2025 p = req->rq_buffer + 3;
2026
2027
2028 /* Make sure the response fits in the buffer. Fixed sized
2029 entries means we don't have to check in the decode loop. */
2030
2031 last_status = req->rq_buffer + 3 + (count-1) * SMB_DIRINFO_SIZE;
2032
2033 if (last_status + SMB_DIRINFO_SIZE >=
2034 req->rq_buffer + req->rq_bufsize) {
2035 printk(KERN_ERR "smb_proc_readdir_short: "
2036 "last dir entry outside buffer! "
2037 "%d@%p %d@%p\n", SMB_DIRINFO_SIZE, last_status,
2038 req->rq_bufsize, req->rq_buffer);
2039 goto out_free;
2040 }
2041
2042 /* Read the last entry into the status field. */
2043 memcpy(status, last_status, SMB_STATUS_SIZE);
2044
2045
2046 /* Now we are ready to parse smb directory entries. */
2047
2048 for (i = 0; i < count; i++) {
2049 p = smb_decode_short_dirent(server, p,
2050 &qname, &fattr, name_buf);
2051 if (qname.len == 0)
2052 continue;
2053
2054 if (entries_seen == 2 && qname.name[0] == '.') {
2055 if (qname.len == 1)
2056 continue;
2057 if (qname.name[1] == '.' && qname.len == 2)
2058 continue;
2059 }
2060 if (!smb_fill_cache(filp, dirent, filldir, ctl,
2061 &qname, &fattr))
2062 ; /* stop reading? */
2063 entries_seen++;
2064 }
2065 }
2066 result = entries;
2067
2068out_free:
2069 smb_rput(req);
2070out_name:
2071 kfree(name_buf);
2072out:
2073 unlock_kernel();
2074 return result;
2075}
2076
2077static void smb_decode_unix_basic(struct smb_fattr *fattr, struct smb_sb_info *server, char *p)
2078{
2079 u64 size, disk_bytes;
2080
2081 /* FIXME: verify nls support. all is sent as utf8? */
2082
2083 fattr->f_unix = 1;
2084 fattr->f_mode = 0;
2085
2086 /* FIXME: use the uniqueID from the remote instead? */
2087 /* 0 L file size in bytes */
2088 /* 8 L file size on disk in bytes (block count) */
2089 /* 40 L uid */
2090 /* 48 L gid */
2091 /* 56 W file type */
2092 /* 60 L devmajor */
2093 /* 68 L devminor */
2094 /* 76 L unique ID (inode) */
2095 /* 84 L permissions */
2096 /* 92 L link count */
2097
2098 size = LVAL(p, 0);
2099 disk_bytes = LVAL(p, 8);
2100
2101 /*
2102 * Some samba versions round up on-disk byte usage
2103 * to 1MB boundaries, making it useless. When seeing
2104 * that, use the size instead.
2105 */
2106 if (!(disk_bytes & 0xfffff))
2107 disk_bytes = size+511;
2108
2109 fattr->f_size = size;
2110 fattr->f_blocks = disk_bytes >> 9;
2111 fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 16));
2112 fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 24));
2113 fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 32));
2114
2115 if (server->mnt->flags & SMB_MOUNT_UID)
2116 fattr->f_uid = server->mnt->uid;
2117 else
2118 fattr->f_uid = LVAL(p, 40);
2119
2120 if (server->mnt->flags & SMB_MOUNT_GID)
2121 fattr->f_gid = server->mnt->gid;
2122 else
2123 fattr->f_gid = LVAL(p, 48);
2124
2125 fattr->f_mode |= smb_filetype_to_mode(WVAL(p, 56));
2126
2127 if (S_ISBLK(fattr->f_mode) || S_ISCHR(fattr->f_mode)) {
2128 __u64 major = LVAL(p, 60);
2129 __u64 minor = LVAL(p, 68);
2130
2131 fattr->f_rdev = MKDEV(major & 0xffffffff, minor & 0xffffffff);
2132 if (MAJOR(fattr->f_rdev) != (major & 0xffffffff) ||
2133 MINOR(fattr->f_rdev) != (minor & 0xffffffff))
2134 fattr->f_rdev = 0;
2135 }
2136
2137 fattr->f_mode |= LVAL(p, 84);
2138
2139 if ( (server->mnt->flags & SMB_MOUNT_DMODE) &&
2140 (S_ISDIR(fattr->f_mode)) )
2141 fattr->f_mode = (server->mnt->dir_mode & S_IRWXUGO) | S_IFDIR;
2142 else if ( (server->mnt->flags & SMB_MOUNT_FMODE) &&
2143 !(S_ISDIR(fattr->f_mode)) )
2144 fattr->f_mode = (server->mnt->file_mode & S_IRWXUGO) |
2145 (fattr->f_mode & S_IFMT);
2146
2147}
2148
2149/*
2150 * Interpret a long filename structure using the specified info level:
2151 * level 1 for anything below NT1 protocol
2152 * level 260 for NT1 protocol
2153 *
2154 * qname is filled with the decoded, and possibly translated, name
2155 * fattr receives decoded attributes.
2156 *
2157 * Bugs Noted:
2158 * (1) Win NT 4.0 appends a null byte to names and counts it in the length!
2159 */
2160static char *
2161smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level,
2162 struct qstr *qname, struct smb_fattr *fattr,
2163 unsigned char *name_buf)
2164{
2165 char *result;
2166 unsigned int len = 0;
2167 int n;
2168 __u16 date, time;
2169 int unicode = (server->mnt->flags & SMB_MOUNT_UNICODE);
2170
2171 /*
2172 * SMB doesn't have a concept of inode numbers ...
2173 */
2174 smb_init_dirent(server, fattr);
2175 fattr->f_ino = 0; /* FIXME: do we need this? */
2176
2177 switch (level) {
2178 case 1:
2179 len = *((unsigned char *) p + 22);
2180 qname->name = p + 23;
2181 result = p + 24 + len;
2182
2183 date = WVAL(p, 0);
2184 time = WVAL(p, 2);
2185 fattr->f_ctime.tv_sec = date_dos2unix(server, date, time);
2186 fattr->f_ctime.tv_nsec = 0;
2187
2188 date = WVAL(p, 4);
2189 time = WVAL(p, 6);
2190 fattr->f_atime.tv_sec = date_dos2unix(server, date, time);
2191 fattr->f_atime.tv_nsec = 0;
2192
2193 date = WVAL(p, 8);
2194 time = WVAL(p, 10);
2195 fattr->f_mtime.tv_sec = date_dos2unix(server, date, time);
2196 fattr->f_mtime.tv_nsec = 0;
2197 fattr->f_size = DVAL(p, 12);
2198 /* ULONG allocation size */
2199 fattr->attr = WVAL(p, 20);
2200
2201 VERBOSE("info 1 at %p, len=%d, name=%.*s\n",
2202 p, len, len, qname->name);
2203 break;
2204 case 260:
2205 result = p + WVAL(p, 0);
2206 len = DVAL(p, 60);
2207 if (len > 255) len = 255;
2208 /* NT4 null terminates, unless we are using unicode ... */
2209 qname->name = p + 94;
2210 if (!unicode && len && qname->name[len-1] == '\0')
2211 len--;
2212
2213 fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 8));
2214 fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 16));
2215 fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 24));
2216 /* change time (32) */
2217 fattr->f_size = LVAL(p, 40);
2218 /* alloc size (48) */
2219 fattr->attr = DVAL(p, 56);
2220
2221 VERBOSE("info 260 at %p, len=%d, name=%.*s\n",
2222 p, len, len, qname->name);
2223 break;
2224 case SMB_FIND_FILE_UNIX:
2225 result = p + WVAL(p, 0);
2226 qname->name = p + 108;
2227
2228 len = strlen(qname->name);
2229 /* FIXME: should we check the length?? */
2230
2231 p += 8;
2232 smb_decode_unix_basic(fattr, server, p);
2233 VERBOSE("info SMB_FIND_FILE_UNIX at %p, len=%d, name=%.*s\n",
2234 p, len, len, qname->name);
2235 break;
2236 default:
2237 PARANOIA("Unknown info level %d\n", level);
2238 result = p + WVAL(p, 0);
2239 goto out;
2240 }
2241
2242 smb_finish_dirent(server, fattr);
2243
2244#if 0
2245 /* FIXME: These only work for ascii chars, and recent smbmount doesn't
2246 allow the flag to be set anyway. Remove? */
2247 switch (server->opt.case_handling) {
2248 case SMB_CASE_UPPER:
2249 str_upper(qname->name, len);
2250 break;
2251 case SMB_CASE_LOWER:
2252 str_lower(qname->name, len);
2253 break;
2254 default:
2255 break;
2256 }
2257#endif
2258
2259 qname->len = 0;
2260 n = server->ops->convert(name_buf, SMB_MAXNAMELEN,
2261 qname->name, len,
2262 server->remote_nls, server->local_nls);
2263 if (n > 0) {
2264 qname->len = n;
2265 qname->name = name_buf;
2266 }
2267
2268out:
2269 return result;
2270}
2271
2272/* findfirst/findnext flags */
2273#define SMB_CLOSE_AFTER_FIRST (1<<0)
2274#define SMB_CLOSE_IF_END (1<<1)
2275#define SMB_REQUIRE_RESUME_KEY (1<<2)
2276#define SMB_CONTINUE_BIT (1<<3)
2277
2278/*
2279 * Note: samba-2.0.7 (at least) has a very similar routine, cli_list, in
2280 * source/libsmb/clilist.c. When looking for smb bugs in the readdir code,
2281 * go there for advise.
2282 *
2283 * Bugs Noted:
2284 * (1) When using Info Level 1 Win NT 4.0 truncates directory listings
2285 * for certain patterns of names and/or lengths. The breakage pattern
2286 * is completely reproducible and can be toggled by the creation of a
2287 * single file. (E.g. echo hi >foo breaks, rm -f foo works.)
2288 */
2289static int
2290smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir,
2291 struct smb_cache_control *ctl)
2292{
2293 struct dentry *dir = filp->f_path.dentry;
2294 struct smb_sb_info *server = server_from_dentry(dir);
2295 struct qstr qname;
2296 struct smb_fattr fattr;
2297
2298 unsigned char *p, *lastname;
2299 char *mask, *param;
2300 __u16 command;
2301 int first, entries_seen;
2302
2303 /* Both NT and OS/2 accept info level 1 (but see note below). */
2304 int info_level = 260;
2305 const int max_matches = 512;
2306
2307 unsigned int ff_searchcount = 0;
2308 unsigned int ff_eos = 0;
2309 unsigned int ff_lastname = 0;
2310 unsigned int ff_dir_handle = 0;
2311 unsigned int loop_count = 0;
2312 unsigned int mask_len, i;
2313 int result;
2314 struct smb_request *req;
2315 unsigned char *name_buf;
2316 static struct qstr star = {
2317 .name = "*",
2318 .len = 1,
2319 };
2320
2321 lock_kernel();
2322
2323 /*
2324 * We always prefer unix style. Use info level 1 for older
2325 * servers that don't do 260.
2326 */
2327 if (server->opt.capabilities & SMB_CAP_UNIX)
2328 info_level = SMB_FIND_FILE_UNIX;
2329 else if (server->opt.protocol < SMB_PROTOCOL_NT1)
2330 info_level = 1;
2331
2332 result = -ENOMEM;
2333 if (! (name_buf = kmalloc(SMB_MAXNAMELEN+2, GFP_KERNEL)))
2334 goto out;
2335 if (! (req = smb_alloc_request(server, server->opt.max_xmit)))
2336 goto out_name;
2337 param = req->rq_buffer;
2338
2339 /*
2340 * Encode the initial path
2341 */
2342 mask = param + 12;
2343
2344 result = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dir, &star);
2345 if (result <= 0)
2346 goto out_free;
2347 mask_len = result - 1; /* mask_len is strlen, not #bytes */
2348 result = 0;
2349 first = 1;
2350 VERBOSE("starting mask_len=%d, mask=%s\n", mask_len, mask);
2351
2352 entries_seen = 2;
2353 ff_eos = 0;
2354
2355 while (ff_eos == 0) {
2356 loop_count += 1;
2357 if (loop_count > 10) {
2358 printk(KERN_WARNING "smb_proc_readdir_long: "
2359 "Looping in FIND_NEXT??\n");
2360 result = -EIO;
2361 break;
2362 }
2363
2364 if (first != 0) {
2365 command = TRANSACT2_FINDFIRST;
2366 WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
2367 WSET(param, 2, max_matches); /* max count */
2368 WSET(param, 4, SMB_CLOSE_IF_END);
2369 WSET(param, 6, info_level);
2370 DSET(param, 8, 0);
2371 } else {
2372 command = TRANSACT2_FINDNEXT;
2373
2374 VERBOSE("handle=0x%X, lastname=%d, mask=%.*s\n",
2375 ff_dir_handle, ff_lastname, mask_len, mask);
2376
2377 WSET(param, 0, ff_dir_handle); /* search handle */
2378 WSET(param, 2, max_matches); /* max count */
2379 WSET(param, 4, info_level);
2380 DSET(param, 6, 0);
2381 WSET(param, 10, SMB_CONTINUE_BIT|SMB_CLOSE_IF_END);
2382 }
2383
2384 req->rq_trans2_command = command;
2385 req->rq_ldata = 0;
2386 req->rq_data = NULL;
2387 req->rq_lparm = 12 + mask_len + 1;
2388 req->rq_parm = param;
2389 req->rq_flags = 0;
2390 result = smb_add_request(req);
2391 if (result < 0) {
2392 PARANOIA("error=%d, breaking\n", result);
2393 break;
2394 }
2395
2396 if (req->rq_rcls == ERRSRV && req->rq_err == ERRerror) {
2397 /* a damn Win95 bug - sometimes it clags if you
2398 ask it too fast */
2399 schedule_timeout_interruptible(msecs_to_jiffies(200));
2400 continue;
2401 }
2402
2403 if (req->rq_rcls != 0) {
2404 result = smb_errno(req);
2405 PARANOIA("name=%s, result=%d, rcls=%d, err=%d\n",
2406 mask, result, req->rq_rcls, req->rq_err);
2407 break;
2408 }
2409
2410 /* parse out some important return info */
2411 if (first != 0) {
2412 ff_dir_handle = WVAL(req->rq_parm, 0);
2413 ff_searchcount = WVAL(req->rq_parm, 2);
2414 ff_eos = WVAL(req->rq_parm, 4);
2415 ff_lastname = WVAL(req->rq_parm, 8);
2416 } else {
2417 ff_searchcount = WVAL(req->rq_parm, 0);
2418 ff_eos = WVAL(req->rq_parm, 2);
2419 ff_lastname = WVAL(req->rq_parm, 6);
2420 }
2421
2422 if (ff_searchcount == 0)
2423 break;
2424
2425 /* Now we are ready to parse smb directory entries. */
2426
2427 /* point to the data bytes */
2428 p = req->rq_data;
2429 for (i = 0; i < ff_searchcount; i++) {
2430 /* make sure we stay within the buffer */
2431 if (p >= req->rq_data + req->rq_ldata) {
2432 printk(KERN_ERR "smb_proc_readdir_long: "
2433 "dirent pointer outside buffer! "
2434 "%p %d@%p\n",
2435 p, req->rq_ldata, req->rq_data);
2436 result = -EIO; /* always a comm. error? */
2437 goto out_free;
2438 }
2439
2440 p = smb_decode_long_dirent(server, p, info_level,
2441 &qname, &fattr, name_buf);
2442
2443 /* ignore . and .. from the server */
2444 if (entries_seen == 2 && qname.name[0] == '.') {
2445 if (qname.len == 1)
2446 continue;
2447 if (qname.name[1] == '.' && qname.len == 2)
2448 continue;
2449 }
2450
2451 if (!smb_fill_cache(filp, dirent, filldir, ctl,
2452 &qname, &fattr))
2453 ; /* stop reading? */
2454 entries_seen++;
2455 }
2456
2457 VERBOSE("received %d entries, eos=%d\n", ff_searchcount,ff_eos);
2458
2459 /*
2460 * We might need the lastname for continuations.
2461 *
2462 * Note that some servers (win95?) point to the filename and
2463 * others (NT4, Samba using NT1) to the dir entry. We assume
2464 * here that those who do not point to a filename do not need
2465 * this info to continue the listing.
2466 *
2467 * OS/2 needs this and talks infolevel 1.
2468 * NetApps want lastname with infolevel 260.
2469 * win2k want lastname with infolevel 260, and points to
2470 * the record not to the name.
2471 * Samba+CifsUnixExt doesn't need lastname.
2472 *
2473 * Both are happy if we return the data they point to. So we do.
2474 * (FIXME: above is not true with win2k)
2475 */
2476 mask_len = 0;
2477 if (info_level != SMB_FIND_FILE_UNIX &&
2478 ff_lastname > 0 && ff_lastname < req->rq_ldata) {
2479 lastname = req->rq_data + ff_lastname;
2480
2481 switch (info_level) {
2482 case 260:
2483 mask_len = req->rq_ldata - ff_lastname;
2484 break;
2485 case 1:
2486 /* lastname points to a length byte */
2487 mask_len = *lastname++;
2488 if (ff_lastname + 1 + mask_len > req->rq_ldata)
2489 mask_len = req->rq_ldata - ff_lastname - 1;
2490 break;
2491 }
2492
2493 /*
2494 * Update the mask string for the next message.
2495 */
2496 if (mask_len > 255)
2497 mask_len = 255;
2498 if (mask_len)
2499 strncpy(mask, lastname, mask_len);
2500 }
2501 mask_len = strnlen(mask, mask_len);
2502 VERBOSE("new mask, len=%d@%d of %d, mask=%.*s\n",
2503 mask_len, ff_lastname, req->rq_ldata, mask_len, mask);
2504
2505 first = 0;
2506 loop_count = 0;
2507 }
2508
2509out_free:
2510 smb_rput(req);
2511out_name:
2512 kfree(name_buf);
2513out:
2514 unlock_kernel();
2515 return result;
2516}
2517
2518/*
2519 * This version uses the trans2 TRANSACT2_FINDFIRST message
2520 * to get the attribute data.
2521 *
2522 * Bugs Noted:
2523 */
2524static int
2525smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry,
2526 struct smb_fattr *fattr)
2527{
2528 char *param, *mask;
2529 __u16 date, time;
2530 int mask_len, result;
2531 struct smb_request *req;
2532
2533 result = -ENOMEM;
2534 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
2535 goto out;
2536 param = req->rq_buffer;
2537 mask = param + 12;
2538
2539 mask_len = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dentry,NULL);
2540 if (mask_len < 0) {
2541 result = mask_len;
2542 goto out_free;
2543 }
2544 VERBOSE("name=%s, len=%d\n", mask, mask_len);
2545 WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
2546 WSET(param, 2, 1); /* max count */
2547 WSET(param, 4, 1); /* close after this call */
2548 WSET(param, 6, 1); /* info_level */
2549 DSET(param, 8, 0);
2550
2551 req->rq_trans2_command = TRANSACT2_FINDFIRST;
2552 req->rq_ldata = 0;
2553 req->rq_data = NULL;
2554 req->rq_lparm = 12 + mask_len;
2555 req->rq_parm = param;
2556 req->rq_flags = 0;
2557 result = smb_add_request(req);
2558 if (result < 0)
2559 goto out_free;
2560 if (req->rq_rcls != 0) {
2561 result = smb_errno(req);
2562#ifdef SMBFS_PARANOIA
2563 if (result != -ENOENT)
2564 PARANOIA("error for %s, rcls=%d, err=%d\n",
2565 mask, req->rq_rcls, req->rq_err);
2566#endif
2567 goto out_free;
2568 }
2569 /* Make sure we got enough data ... */
2570 result = -EINVAL;
2571 if (req->rq_ldata < 22 || WVAL(req->rq_parm, 2) != 1) {
2572 PARANOIA("bad result for %s, len=%d, count=%d\n",
2573 mask, req->rq_ldata, WVAL(req->rq_parm, 2));
2574 goto out_free;
2575 }
2576
2577 /*
2578 * Decode the response into the fattr ...
2579 */
2580 date = WVAL(req->rq_data, 0);
2581 time = WVAL(req->rq_data, 2);
2582 fattr->f_ctime.tv_sec = date_dos2unix(server, date, time);
2583 fattr->f_ctime.tv_nsec = 0;
2584
2585 date = WVAL(req->rq_data, 4);
2586 time = WVAL(req->rq_data, 6);
2587 fattr->f_atime.tv_sec = date_dos2unix(server, date, time);
2588 fattr->f_atime.tv_nsec = 0;
2589
2590 date = WVAL(req->rq_data, 8);
2591 time = WVAL(req->rq_data, 10);
2592 fattr->f_mtime.tv_sec = date_dos2unix(server, date, time);
2593 fattr->f_mtime.tv_nsec = 0;
2594 VERBOSE("name=%s, date=%x, time=%x, mtime=%ld\n",
2595 mask, date, time, fattr->f_mtime.tv_sec);
2596 fattr->f_size = DVAL(req->rq_data, 12);
2597 /* ULONG allocation size */
2598 fattr->attr = WVAL(req->rq_data, 20);
2599 result = 0;
2600
2601out_free:
2602 smb_rput(req);
2603out:
2604 return result;
2605}
2606
2607static int
2608smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,
2609 struct smb_fattr *fattr)
2610{
2611 int result;
2612 char *p;
2613 struct smb_request *req;
2614
2615 result = -ENOMEM;
2616 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
2617 goto out;
2618
2619 p = smb_setup_header(req, SMBgetatr, 0, 0);
2620 result = smb_simple_encode_path(req, &p, dir, NULL);
2621 if (result < 0)
2622 goto out_free;
2623 smb_setup_bcc(req, p);
2624
2625 if ((result = smb_request_ok(req, SMBgetatr, 10, 0)) < 0)
2626 goto out_free;
2627 fattr->attr = WVAL(req->rq_header, smb_vwv0);
2628 fattr->f_mtime.tv_sec = local2utc(server, DVAL(req->rq_header, smb_vwv1));
2629 fattr->f_mtime.tv_nsec = 0;
2630 fattr->f_size = DVAL(req->rq_header, smb_vwv3);
2631 fattr->f_ctime = fattr->f_mtime;
2632 fattr->f_atime = fattr->f_mtime;
2633#ifdef SMBFS_DEBUG_TIMESTAMP
2634 printk("getattr_core: %s/%s, mtime=%ld\n",
2635 DENTRY_PATH(dir), fattr->f_mtime);
2636#endif
2637 result = 0;
2638
2639out_free:
2640 smb_rput(req);
2641out:
2642 return result;
2643}
2644
2645/*
2646 * Bugs Noted:
2647 * (1) Win 95 swaps the date and time fields in the standard info level.
2648 */
2649static int
2650smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
2651 struct smb_request *req, int infolevel)
2652{
2653 char *p, *param;
2654 int result;
2655
2656 param = req->rq_buffer;
2657 WSET(param, 0, infolevel);
2658 DSET(param, 2, 0);
2659 result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);
2660 if (result < 0)
2661 goto out;
2662 p = param + 6 + result;
2663
2664 req->rq_trans2_command = TRANSACT2_QPATHINFO;
2665 req->rq_ldata = 0;
2666 req->rq_data = NULL;
2667 req->rq_lparm = p - param;
2668 req->rq_parm = param;
2669 req->rq_flags = 0;
2670 result = smb_add_request(req);
2671 if (result < 0)
2672 goto out;
2673 if (req->rq_rcls != 0) {
2674 VERBOSE("for %s: result=%d, rcls=%d, err=%d\n",
2675 &param[6], result, req->rq_rcls, req->rq_err);
2676 result = smb_errno(req);
2677 goto out;
2678 }
2679 result = -ENOENT;
2680 if (req->rq_ldata < 22) {
2681 PARANOIA("not enough data for %s, len=%d\n",
2682 &param[6], req->rq_ldata);
2683 goto out;
2684 }
2685
2686 result = 0;
2687out:
2688 return result;
2689}
2690
2691static int
2692smb_proc_getattr_trans2_std(struct smb_sb_info *server, struct dentry *dir,
2693 struct smb_fattr *attr)
2694{
2695 u16 date, time;
2696 int off_date = 0, off_time = 2;
2697 int result;
2698 struct smb_request *req;
2699
2700 result = -ENOMEM;
2701 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
2702 goto out;
2703
2704 result = smb_proc_getattr_trans2(server, dir, req, SMB_INFO_STANDARD);
2705 if (result < 0)
2706 goto out_free;
2707
2708 /*
2709 * Kludge alert: Win 95 swaps the date and time field,
2710 * contrary to the CIFS docs and Win NT practice.
2711 */
2712 if (server->mnt->flags & SMB_MOUNT_WIN95) {
2713 off_date = 2;
2714 off_time = 0;
2715 }
2716 date = WVAL(req->rq_data, off_date);
2717 time = WVAL(req->rq_data, off_time);
2718 attr->f_ctime.tv_sec = date_dos2unix(server, date, time);
2719 attr->f_ctime.tv_nsec = 0;
2720
2721 date = WVAL(req->rq_data, 4 + off_date);
2722 time = WVAL(req->rq_data, 4 + off_time);
2723 attr->f_atime.tv_sec = date_dos2unix(server, date, time);
2724 attr->f_atime.tv_nsec = 0;
2725
2726 date = WVAL(req->rq_data, 8 + off_date);
2727 time = WVAL(req->rq_data, 8 + off_time);
2728 attr->f_mtime.tv_sec = date_dos2unix(server, date, time);
2729 attr->f_mtime.tv_nsec = 0;
2730#ifdef SMBFS_DEBUG_TIMESTAMP
2731 printk(KERN_DEBUG "getattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n",
2732 DENTRY_PATH(dir), date, time, attr->f_mtime);
2733#endif
2734 attr->f_size = DVAL(req->rq_data, 12);
2735 attr->attr = WVAL(req->rq_data, 20);
2736
2737out_free:
2738 smb_rput(req);
2739out:
2740 return result;
2741}
2742
2743static int
2744smb_proc_getattr_trans2_all(struct smb_sb_info *server, struct dentry *dir,
2745 struct smb_fattr *attr)
2746{
2747 struct smb_request *req;
2748 int result;
2749
2750 result = -ENOMEM;
2751 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
2752 goto out;
2753
2754 result = smb_proc_getattr_trans2(server, dir, req,
2755 SMB_QUERY_FILE_ALL_INFO);
2756 if (result < 0)
2757 goto out_free;
2758
2759 attr->f_ctime = smb_ntutc2unixutc(LVAL(req->rq_data, 0));
2760 attr->f_atime = smb_ntutc2unixutc(LVAL(req->rq_data, 8));
2761 attr->f_mtime = smb_ntutc2unixutc(LVAL(req->rq_data, 16));
2762 /* change (24) */
2763 attr->attr = WVAL(req->rq_data, 32);
2764 /* pad? (34) */
2765 /* allocated size (40) */
2766 attr->f_size = LVAL(req->rq_data, 48);
2767
2768out_free:
2769 smb_rput(req);
2770out:
2771 return result;
2772}
2773
2774static int
2775smb_proc_getattr_unix(struct smb_sb_info *server, struct dentry *dir,
2776 struct smb_fattr *attr)
2777{
2778 struct smb_request *req;
2779 int result;
2780
2781 result = -ENOMEM;
2782 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
2783 goto out;
2784
2785 result = smb_proc_getattr_trans2(server, dir, req,
2786 SMB_QUERY_FILE_UNIX_BASIC);
2787 if (result < 0)
2788 goto out_free;
2789
2790 smb_decode_unix_basic(attr, server, req->rq_data);
2791
2792out_free:
2793 smb_rput(req);
2794out:
2795 return result;
2796}
2797
2798static int
2799smb_proc_getattr_95(struct smb_sb_info *server, struct dentry *dir,
2800 struct smb_fattr *attr)
2801{
2802 struct inode *inode = dir->d_inode;
2803 int result;
2804
2805 /* FIXME: why not use the "all" version? */
2806 result = smb_proc_getattr_trans2_std(server, dir, attr);
2807 if (result < 0)
2808 goto out;
2809
2810 /*
2811 * None of the getattr versions here can make win9x return the right
2812 * filesize if there are changes made to an open file.
2813 * A seek-to-end does return the right size, but we only need to do
2814 * that on files we have written.
2815 */
2816 if (inode && SMB_I(inode)->flags & SMB_F_LOCALWRITE &&
2817 smb_is_open(inode))
2818 {
2819 __u16 fileid = SMB_I(inode)->fileid;
2820 attr->f_size = smb_proc_seek(server, fileid, 2, 0);
2821 }
2822
2823out:
2824 return result;
2825}
2826
2827static int
2828smb_proc_ops_wait(struct smb_sb_info *server)
2829{
2830 int result;
2831
2832 result = wait_event_interruptible_timeout(server->conn_wq,
2833 server->conn_complete, 30*HZ);
2834
2835 if (!result || signal_pending(current))
2836 return -EIO;
2837
2838 return 0;
2839}
2840
2841static int
2842smb_proc_getattr_null(struct smb_sb_info *server, struct dentry *dir,
2843 struct smb_fattr *fattr)
2844{
2845 int result;
2846
2847 if (smb_proc_ops_wait(server) < 0)
2848 return -EIO;
2849
2850 smb_init_dirent(server, fattr);
2851 result = server->ops->getattr(server, dir, fattr);
2852 smb_finish_dirent(server, fattr);
2853
2854 return result;
2855}
2856
2857static int
2858smb_proc_readdir_null(struct file *filp, void *dirent, filldir_t filldir,
2859 struct smb_cache_control *ctl)
2860{
2861 struct smb_sb_info *server = server_from_dentry(filp->f_path.dentry);
2862
2863 if (smb_proc_ops_wait(server) < 0)
2864 return -EIO;
2865
2866 return server->ops->readdir(filp, dirent, filldir, ctl);
2867}
2868
2869int
2870smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr)
2871{
2872 struct smb_sb_info *server = server_from_dentry(dir);
2873 int result;
2874
2875 smb_init_dirent(server, fattr);
2876 result = server->ops->getattr(server, dir, fattr);
2877 smb_finish_dirent(server, fattr);
2878
2879 return result;
2880}
2881
2882
2883/*
2884 * Because of bugs in the core protocol, we use this only to set
2885 * attributes. See smb_proc_settime() below for timestamp handling.
2886 *
2887 * Bugs Noted:
2888 * (1) If mtime is non-zero, both Win 3.1 and Win 95 fail
2889 * with an undocumented error (ERRDOS code 50). Setting
2890 * mtime to 0 allows the attributes to be set.
2891 * (2) The extra parameters following the name string aren't
2892 * in the CIFS docs, but seem to be necessary for operation.
2893 */
2894static int
2895smb_proc_setattr_core(struct smb_sb_info *server, struct dentry *dentry,
2896 __u16 attr)
2897{
2898 char *p;
2899 int result;
2900 struct smb_request *req;
2901
2902 result = -ENOMEM;
2903 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
2904 goto out;
2905
2906 p = smb_setup_header(req, SMBsetatr, 8, 0);
2907 WSET(req->rq_header, smb_vwv0, attr);
2908 DSET(req->rq_header, smb_vwv1, 0); /* mtime */
2909 WSET(req->rq_header, smb_vwv3, 0); /* reserved values */
2910 WSET(req->rq_header, smb_vwv4, 0);
2911 WSET(req->rq_header, smb_vwv5, 0);
2912 WSET(req->rq_header, smb_vwv6, 0);
2913 WSET(req->rq_header, smb_vwv7, 0);
2914 result = smb_simple_encode_path(req, &p, dentry, NULL);
2915 if (result < 0)
2916 goto out_free;
2917 if (p + 2 > (char *)req->rq_buffer + req->rq_bufsize) {
2918 result = -ENAMETOOLONG;
2919 goto out_free;
2920 }
2921 *p++ = 4;
2922 *p++ = 0;
2923 smb_setup_bcc(req, p);
2924
2925 result = smb_request_ok(req, SMBsetatr, 0, 0);
2926 if (result < 0)
2927 goto out_free;
2928 result = 0;
2929
2930out_free:
2931 smb_rput(req);
2932out:
2933 return result;
2934}
2935
2936/*
2937 * Because of bugs in the trans2 setattr messages, we must set
2938 * attributes and timestamps separately. The core SMBsetatr
2939 * message seems to be the only reliable way to set attributes.
2940 */
2941int
2942smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr)
2943{
2944 struct smb_sb_info *server = server_from_dentry(dir);
2945 int result;
2946
2947 VERBOSE("setting %s/%s, open=%d\n",
2948 DENTRY_PATH(dir), smb_is_open(dir->d_inode));
2949 result = smb_proc_setattr_core(server, dir, fattr->attr);
2950 return result;
2951}
2952
2953/*
2954 * Sets the timestamps for an file open with write permissions.
2955 */
2956static int
2957smb_proc_setattr_ext(struct smb_sb_info *server,
2958 struct inode *inode, struct smb_fattr *fattr)
2959{
2960 __u16 date, time;
2961 int result;
2962 struct smb_request *req;
2963
2964 result = -ENOMEM;
2965 if (! (req = smb_alloc_request(server, 0)))
2966 goto out;
2967
2968 smb_setup_header(req, SMBsetattrE, 7, 0);
2969 WSET(req->rq_header, smb_vwv0, SMB_I(inode)->fileid);
2970 /* We don't change the creation time */
2971 WSET(req->rq_header, smb_vwv1, 0);
2972 WSET(req->rq_header, smb_vwv2, 0);
2973 date_unix2dos(server, fattr->f_atime.tv_sec, &date, &time);
2974 WSET(req->rq_header, smb_vwv3, date);
2975 WSET(req->rq_header, smb_vwv4, time);
2976 date_unix2dos(server, fattr->f_mtime.tv_sec, &date, &time);
2977 WSET(req->rq_header, smb_vwv5, date);
2978 WSET(req->rq_header, smb_vwv6, time);
2979#ifdef SMBFS_DEBUG_TIMESTAMP
2980 printk(KERN_DEBUG "smb_proc_setattr_ext: date=%d, time=%d, mtime=%ld\n",
2981 date, time, fattr->f_mtime);
2982#endif
2983
2984 req->rq_flags |= SMB_REQ_NORETRY;
2985 result = smb_request_ok(req, SMBsetattrE, 0, 0);
2986 if (result < 0)
2987 goto out_free;
2988 result = 0;
2989out_free:
2990 smb_rput(req);
2991out:
2992 return result;
2993}
2994
2995/*
2996 * Bugs Noted:
2997 * (1) The TRANSACT2_SETPATHINFO message under Win NT 4.0 doesn't
2998 * set the file's attribute flags.
2999 */
3000static int
3001smb_proc_setattr_trans2(struct smb_sb_info *server,
3002 struct dentry *dir, struct smb_fattr *fattr)
3003{
3004 __u16 date, time;
3005 char *p, *param;
3006 int result;
3007 char data[26];
3008 struct smb_request *req;
3009
3010 result = -ENOMEM;
3011 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
3012 goto out;
3013 param = req->rq_buffer;
3014
3015 WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
3016 DSET(param, 2, 0);
3017 result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);
3018 if (result < 0)
3019 goto out_free;
3020 p = param + 6 + result;
3021
3022 WSET(data, 0, 0); /* creation time */
3023 WSET(data, 2, 0);
3024 date_unix2dos(server, fattr->f_atime.tv_sec, &date, &time);
3025 WSET(data, 4, date);
3026 WSET(data, 6, time);
3027 date_unix2dos(server, fattr->f_mtime.tv_sec, &date, &time);
3028 WSET(data, 8, date);
3029 WSET(data, 10, time);
3030#ifdef SMBFS_DEBUG_TIMESTAMP
3031 printk(KERN_DEBUG "setattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n",
3032 DENTRY_PATH(dir), date, time, fattr->f_mtime);
3033#endif
3034 DSET(data, 12, 0); /* size */
3035 DSET(data, 16, 0); /* blksize */
3036 WSET(data, 20, 0); /* attr */
3037 DSET(data, 22, 0); /* ULONG EA size */
3038
3039 req->rq_trans2_command = TRANSACT2_SETPATHINFO;
3040 req->rq_ldata = 26;
3041 req->rq_data = data;
3042 req->rq_lparm = p - param;
3043 req->rq_parm = param;
3044 req->rq_flags = 0;
3045 result = smb_add_request(req);
3046 if (result < 0)
3047 goto out_free;
3048 result = 0;
3049 if (req->rq_rcls != 0)
3050 result = smb_errno(req);
3051
3052out_free:
3053 smb_rput(req);
3054out:
3055 return result;
3056}
3057
3058/*
3059 * ATTR_MODE 0x001
3060 * ATTR_UID 0x002
3061 * ATTR_GID 0x004
3062 * ATTR_SIZE 0x008
3063 * ATTR_ATIME 0x010
3064 * ATTR_MTIME 0x020
3065 * ATTR_CTIME 0x040
3066 * ATTR_ATIME_SET 0x080
3067 * ATTR_MTIME_SET 0x100
3068 * ATTR_FORCE 0x200
3069 * ATTR_ATTR_FLAG 0x400
3070 *
3071 * major/minor should only be set by mknod.
3072 */
3073int
3074smb_proc_setattr_unix(struct dentry *d, struct iattr *attr,
3075 unsigned int major, unsigned int minor)
3076{
3077 struct smb_sb_info *server = server_from_dentry(d);
3078 u64 nttime;
3079 char *p, *param;
3080 int result;
3081 char data[100];
3082 struct smb_request *req;
3083
3084 result = -ENOMEM;
3085 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
3086 goto out;
3087 param = req->rq_buffer;
3088
3089 DEBUG1("valid flags = 0x%04x\n", attr->ia_valid);
3090
3091 WSET(param, 0, SMB_SET_FILE_UNIX_BASIC);
3092 DSET(param, 2, 0);
3093 result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, d, NULL);
3094 if (result < 0)
3095 goto out_free;
3096 p = param + 6 + result;
3097
3098 /* 0 L file size in bytes */
3099 /* 8 L file size on disk in bytes (block count) */
3100 /* 40 L uid */
3101 /* 48 L gid */
3102 /* 56 W file type enum */
3103 /* 60 L devmajor */
3104 /* 68 L devminor */
3105 /* 76 L unique ID (inode) */
3106 /* 84 L permissions */
3107 /* 92 L link count */
3108 LSET(data, 0, SMB_SIZE_NO_CHANGE);
3109 LSET(data, 8, SMB_SIZE_NO_CHANGE);
3110 LSET(data, 16, SMB_TIME_NO_CHANGE);
3111 LSET(data, 24, SMB_TIME_NO_CHANGE);
3112 LSET(data, 32, SMB_TIME_NO_CHANGE);
3113 LSET(data, 40, SMB_UID_NO_CHANGE);
3114 LSET(data, 48, SMB_GID_NO_CHANGE);
3115 DSET(data, 56, smb_filetype_from_mode(attr->ia_mode));
3116 LSET(data, 60, major);
3117 LSET(data, 68, minor);
3118 LSET(data, 76, 0);
3119 LSET(data, 84, SMB_MODE_NO_CHANGE);
3120 LSET(data, 92, 0);
3121
3122 if (attr->ia_valid & ATTR_SIZE) {
3123 LSET(data, 0, attr->ia_size);
3124 LSET(data, 8, 0); /* can't set anyway */
3125 }
3126
3127 /*
3128 * FIXME: check the conversion function it the correct one
3129 *
3130 * we can't set ctime but we might as well pass this to the server
3131 * and let it ignore it.
3132 */
3133 if (attr->ia_valid & ATTR_CTIME) {
3134 nttime = smb_unixutc2ntutc(attr->ia_ctime);
3135 LSET(data, 16, nttime);
3136 }
3137 if (attr->ia_valid & ATTR_ATIME) {
3138 nttime = smb_unixutc2ntutc(attr->ia_atime);
3139 LSET(data, 24, nttime);
3140 }
3141 if (attr->ia_valid & ATTR_MTIME) {
3142 nttime = smb_unixutc2ntutc(attr->ia_mtime);
3143 LSET(data, 32, nttime);
3144 }
3145
3146 if (attr->ia_valid & ATTR_UID) {
3147 LSET(data, 40, attr->ia_uid);
3148 }
3149 if (attr->ia_valid & ATTR_GID) {
3150 LSET(data, 48, attr->ia_gid);
3151 }
3152
3153 if (attr->ia_valid & ATTR_MODE) {
3154 LSET(data, 84, attr->ia_mode);
3155 }
3156
3157 req->rq_trans2_command = TRANSACT2_SETPATHINFO;
3158 req->rq_ldata = 100;
3159 req->rq_data = data;
3160 req->rq_lparm = p - param;
3161 req->rq_parm = param;
3162 req->rq_flags = 0;
3163 result = smb_add_request(req);
3164
3165out_free:
3166 smb_rput(req);
3167out:
3168 return result;
3169}
3170
3171
3172/*
3173 * Set the modify and access timestamps for a file.
3174 *
3175 * Incredibly enough, in all of SMB there is no message to allow
3176 * setting both attributes and timestamps at once.
3177 *
3178 * Bugs Noted:
3179 * (1) Win 95 doesn't support the TRANSACT2_SETFILEINFO message
3180 * with info level 1 (INFO_STANDARD).
3181 * (2) Win 95 seems not to support setting directory timestamps.
3182 * (3) Under the core protocol apparently the only way to set the
3183 * timestamp is to open and close the file.
3184 */
3185int
3186smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr)
3187{
3188 struct smb_sb_info *server = server_from_dentry(dentry);
3189 struct inode *inode = dentry->d_inode;
3190 int result;
3191
3192 VERBOSE("setting %s/%s, open=%d\n",
3193 DENTRY_PATH(dentry), smb_is_open(inode));
3194
3195 /* setting the time on a Win95 server fails (tridge) */
3196 if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 &&
3197 !(server->mnt->flags & SMB_MOUNT_WIN95)) {
3198 if (smb_is_open(inode) && SMB_I(inode)->access != SMB_O_RDONLY)
3199 result = smb_proc_setattr_ext(server, inode, fattr);
3200 else
3201 result = smb_proc_setattr_trans2(server, dentry, fattr);
3202 } else {
3203 /*
3204 * Fail silently on directories ... timestamp can't be set?
3205 */
3206 result = 0;
3207 if (S_ISREG(inode->i_mode)) {
3208 /*
3209 * Set the mtime by opening and closing the file.
3210 * Note that the file is opened read-only, but this
3211 * still allows us to set the date (tridge)
3212 */
3213 result = -EACCES;
3214 if (!smb_is_open(inode))
3215 smb_proc_open(server, dentry, SMB_O_RDONLY);
3216 if (smb_is_open(inode)) {
3217 inode->i_mtime = fattr->f_mtime;
3218 result = smb_proc_close_inode(server, inode);
3219 }
3220 }
3221 }
3222
3223 return result;
3224}
3225
3226int
3227smb_proc_dskattr(struct dentry *dentry, struct kstatfs *attr)
3228{
3229 struct smb_sb_info *server = SMB_SB(dentry->d_sb);
3230 int result;
3231 char *p;
3232 long unit;
3233 struct smb_request *req;
3234
3235 result = -ENOMEM;
3236 if (! (req = smb_alloc_request(server, 0)))
3237 goto out;
3238
3239 smb_setup_header(req, SMBdskattr, 0, 0);
3240 if ((result = smb_request_ok(req, SMBdskattr, 5, 0)) < 0)
3241 goto out_free;
3242 p = SMB_VWV(req->rq_header);
3243 unit = (WVAL(p, 2) * WVAL(p, 4)) >> SMB_ST_BLKSHIFT;
3244 attr->f_blocks = WVAL(p, 0) * unit;
3245 attr->f_bsize = SMB_ST_BLKSIZE;
3246 attr->f_bavail = attr->f_bfree = WVAL(p, 6) * unit;
3247 result = 0;
3248
3249out_free:
3250 smb_rput(req);
3251out:
3252 return result;
3253}
3254
3255int
3256smb_proc_read_link(struct smb_sb_info *server, struct dentry *d,
3257 char *buffer, int len)
3258{
3259 char *p, *param;
3260 int result;
3261 struct smb_request *req;
3262
3263 DEBUG1("readlink of %s/%s\n", DENTRY_PATH(d));
3264
3265 result = -ENOMEM;
3266 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
3267 goto out;
3268 param = req->rq_buffer;
3269
3270 WSET(param, 0, SMB_QUERY_FILE_UNIX_LINK);
3271 DSET(param, 2, 0);
3272 result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, d, NULL);
3273 if (result < 0)
3274 goto out_free;
3275 p = param + 6 + result;
3276
3277 req->rq_trans2_command = TRANSACT2_QPATHINFO;
3278 req->rq_ldata = 0;
3279 req->rq_data = NULL;
3280 req->rq_lparm = p - param;
3281 req->rq_parm = param;
3282 req->rq_flags = 0;
3283 result = smb_add_request(req);
3284 if (result < 0)
3285 goto out_free;
3286 DEBUG1("for %s: result=%d, rcls=%d, err=%d\n",
3287 &param[6], result, req->rq_rcls, req->rq_err);
3288
3289 /* copy data up to the \0 or buffer length */
3290 result = len;
3291 if (req->rq_ldata < len)
3292 result = req->rq_ldata;
3293 strncpy(buffer, req->rq_data, result);
3294
3295out_free:
3296 smb_rput(req);
3297out:
3298 return result;
3299}
3300
3301
3302/*
3303 * Create a symlink object called dentry which points to oldpath.
3304 * Samba does not permit dangling links but returns a suitable error message.
3305 */
3306int
3307smb_proc_symlink(struct smb_sb_info *server, struct dentry *d,
3308 const char *oldpath)
3309{
3310 char *p, *param;
3311 int result;
3312 struct smb_request *req;
3313
3314 result = -ENOMEM;
3315 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
3316 goto out;
3317 param = req->rq_buffer;
3318
3319 WSET(param, 0, SMB_SET_FILE_UNIX_LINK);
3320 DSET(param, 2, 0);
3321 result = smb_encode_path(server, param + 6, SMB_MAXPATHLEN+1, d, NULL);
3322 if (result < 0)
3323 goto out_free;
3324 p = param + 6 + result;
3325
3326 req->rq_trans2_command = TRANSACT2_SETPATHINFO;
3327 req->rq_ldata = strlen(oldpath) + 1;
3328 req->rq_data = (char *) oldpath;
3329 req->rq_lparm = p - param;
3330 req->rq_parm = param;
3331 req->rq_flags = 0;
3332 result = smb_add_request(req);
3333 if (result < 0)
3334 goto out_free;
3335
3336 DEBUG1("for %s: result=%d, rcls=%d, err=%d\n",
3337 &param[6], result, req->rq_rcls, req->rq_err);
3338 result = 0;
3339
3340out_free:
3341 smb_rput(req);
3342out:
3343 return result;
3344}
3345
3346/*
3347 * Create a hard link object called new_dentry which points to dentry.
3348 */
3349int
3350smb_proc_link(struct smb_sb_info *server, struct dentry *dentry,
3351 struct dentry *new_dentry)
3352{
3353 char *p, *param;
3354 int result;
3355 struct smb_request *req;
3356
3357 result = -ENOMEM;
3358 if (! (req = smb_alloc_request(server, PAGE_SIZE)))
3359 goto out;
3360 param = req->rq_buffer;
3361
3362 WSET(param, 0, SMB_SET_FILE_UNIX_HLINK);
3363 DSET(param, 2, 0);
3364 result = smb_encode_path(server, param + 6, SMB_MAXPATHLEN+1,
3365 new_dentry, NULL);
3366 if (result < 0)
3367 goto out_free;
3368 p = param + 6 + result;
3369
3370 /* Grr, pointless separation of parameters and data ... */
3371 req->rq_data = p;
3372 req->rq_ldata = smb_encode_path(server, p, SMB_MAXPATHLEN+1,
3373 dentry, NULL);
3374
3375 req->rq_trans2_command = TRANSACT2_SETPATHINFO;
3376 req->rq_lparm = p - param;
3377 req->rq_parm = param;
3378 req->rq_flags = 0;
3379 result = smb_add_request(req);
3380 if (result < 0)
3381 goto out_free;
3382
3383 DEBUG1("for %s: result=%d, rcls=%d, err=%d\n",
3384 &param[6], result, req->rq_rcls, req->rq_err);
3385 result = 0;
3386
3387out_free:
3388 smb_rput(req);
3389out:
3390 return result;
3391}
3392
3393static int
3394smb_proc_query_cifsunix(struct smb_sb_info *server)
3395{
3396 int result;
3397 int major, minor;
3398 u64 caps;
3399 char param[2];
3400 struct smb_request *req;
3401
3402 result = -ENOMEM;
3403 if (! (req = smb_alloc_request(server, 100)))
3404 goto out;
3405
3406 WSET(param, 0, SMB_QUERY_CIFS_UNIX_INFO);
3407
3408 req->rq_trans2_command = TRANSACT2_QFSINFO;
3409 req->rq_ldata = 0;
3410 req->rq_data = NULL;
3411 req->rq_lparm = 2;
3412 req->rq_parm = param;
3413 req->rq_flags = 0;
3414 result = smb_add_request(req);
3415 if (result < 0)
3416 goto out_free;
3417
3418 if (req->rq_ldata < 12) {
3419 PARANOIA("Not enough data\n");
3420 goto out_free;
3421 }
3422 major = WVAL(req->rq_data, 0);
3423 minor = WVAL(req->rq_data, 2);
3424
3425 DEBUG1("Server implements CIFS Extensions for UNIX systems v%d.%d\n",
3426 major, minor);
3427 /* FIXME: verify that we are ok with this major/minor? */
3428
3429 caps = LVAL(req->rq_data, 4);
3430 DEBUG1("Server capabilities 0x%016llx\n", caps);
3431
3432out_free:
3433 smb_rput(req);
3434out:
3435 return result;
3436}
3437
3438
3439static void
3440install_ops(struct smb_ops *dst, struct smb_ops *src)
3441{
3442 memcpy(dst, src, sizeof(void *) * SMB_OPS_NUM_STATIC);
3443}
3444
3445/* < LANMAN2 */
3446static struct smb_ops smb_ops_core =
3447{
3448 .read = smb_proc_read,
3449 .write = smb_proc_write,
3450 .readdir = smb_proc_readdir_short,
3451 .getattr = smb_proc_getattr_core,
3452 .truncate = smb_proc_trunc32,
3453};
3454
3455/* LANMAN2, OS/2, others? */
3456static struct smb_ops smb_ops_os2 =
3457{
3458 .read = smb_proc_read,
3459 .write = smb_proc_write,
3460 .readdir = smb_proc_readdir_long,
3461 .getattr = smb_proc_getattr_trans2_std,
3462 .truncate = smb_proc_trunc32,
3463};
3464
3465/* Win95, and possibly some NetApp versions too */
3466static struct smb_ops smb_ops_win95 =
3467{
3468 .read = smb_proc_read, /* does not support 12word readX */
3469 .write = smb_proc_write,
3470 .readdir = smb_proc_readdir_long,
3471 .getattr = smb_proc_getattr_95,
3472 .truncate = smb_proc_trunc95,
3473};
3474
3475/* Samba, NT4 and NT5 */
3476static struct smb_ops smb_ops_winNT =
3477{
3478 .read = smb_proc_readX,
3479 .write = smb_proc_writeX,
3480 .readdir = smb_proc_readdir_long,
3481 .getattr = smb_proc_getattr_trans2_all,
3482 .truncate = smb_proc_trunc64,
3483};
3484
3485/* Samba w/ unix extensions. Others? */
3486static struct smb_ops smb_ops_unix =
3487{
3488 .read = smb_proc_readX,
3489 .write = smb_proc_writeX,
3490 .readdir = smb_proc_readdir_long,
3491 .getattr = smb_proc_getattr_unix,
3492 /* FIXME: core/ext/time setattr needs to be cleaned up! */
3493 /* .setattr = smb_proc_setattr_unix, */
3494 .truncate = smb_proc_trunc64,
3495};
3496
3497/* Place holder until real ops are in place */
3498static struct smb_ops smb_ops_null =
3499{
3500 .readdir = smb_proc_readdir_null,
3501 .getattr = smb_proc_getattr_null,
3502};
3503
3504void smb_install_null_ops(struct smb_ops *ops)
3505{
3506 install_ops(ops, &smb_ops_null);
3507}