Showing error 1922

User: Jiri Slaby
Error type: Invalid Pointer Dereference
Error type description: A pointer which is invalid is being dereferenced
File location: fs/smbfs/proc.c
Line in file: 3293
Project: Linux Kernel
Project version: 2.6.28
Tools: Cppcheck (1.59)
Entered: 2013-10-17 18:38:34 UTC


Source:

   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 = 0; 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}