The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/smbfs/smbfs_smb.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2000-2001 Boris Popov
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *    This product includes software developed by Boris Popov.
   16  * 4. Neither the name of the author nor the names of any co-contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  * $FreeBSD$
   33  */
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/malloc.h>
   38 #include <sys/proc.h>
   39 #include <sys/lock.h>
   40 #include <sys/vnode.h>
   41 #include <sys/mbuf.h>
   42 #include <sys/mount.h>
   43 
   44 #ifdef USE_MD5_HASH
   45 #include <sys/md5.h>
   46 #endif
   47 
   48 #include <netsmb/smb.h>
   49 #include <netsmb/smb_subr.h>
   50 #include <netsmb/smb_rq.h>
   51 #include <netsmb/smb_conn.h>
   52 
   53 #include <fs/smbfs/smbfs.h>
   54 #include <fs/smbfs/smbfs_node.h>
   55 #include <fs/smbfs/smbfs_subr.h>
   56 
   57 /*
   58  * Lack of inode numbers leads us to the problem of generating them.
   59  * Partially this problem can be solved by having a dir/file cache
   60  * with inode numbers generated from the incremented by one counter.
   61  * However this way will require too much kernel memory, gives all
   62  * sorts of locking and consistency problems, not to mentinon counter overflows.
   63  * So, I'm decided to use a hash function to generate pseudo random (and unique)
   64  * inode numbers.
   65  */
   66 static long
   67 smbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
   68 {
   69 #ifdef USE_MD5_HASH
   70         MD5_CTX md5;
   71         u_int32_t state[4];
   72         long ino;
   73         int i;
   74 
   75         MD5Init(&md5);
   76         MD5Update(&md5, name, nmlen);
   77         MD5Final((u_char *)state, &md5);
   78         for (i = 0, ino = 0; i < 4; i++)
   79                 ino += state[i];
   80         return dnp->n_ino + ino;
   81 #endif
   82         u_int32_t ino;
   83 
   84         ino = dnp->n_ino + smbfs_hash(name, nmlen);
   85         if (ino <= 2)
   86                 ino += 3;
   87         return ino;
   88 }
   89 
   90 static int
   91 smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end,
   92         struct smb_cred *scred)
   93 {
   94         struct smb_share *ssp = np->n_mount->sm_share;
   95         struct smb_rq rq, *rqp = &rq;
   96         struct mbchain *mbp;
   97         u_char ltype = 0;
   98         int error;
   99 
  100         if (op == SMB_LOCK_SHARED)
  101                 ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
  102         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred);
  103         if (error)
  104                 return error;
  105         smb_rq_getrequest(rqp, &mbp);
  106         smb_rq_wstart(rqp);
  107         mb_put_uint8(mbp, 0xff);        /* secondary command */
  108         mb_put_uint8(mbp, 0);           /* MBZ */
  109         mb_put_uint16le(mbp, 0);
  110         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  111         mb_put_uint8(mbp, ltype);       /* locktype */
  112         mb_put_uint8(mbp, 0);           /* oplocklevel - 0 seems is NO_OPLOCK */
  113         mb_put_uint32le(mbp, 0);        /* timeout - break immediately */
  114         mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
  115         mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
  116         smb_rq_wend(rqp);
  117         smb_rq_bstart(rqp);
  118         mb_put_uint16le(mbp, pid);
  119         mb_put_uint32le(mbp, start);
  120         mb_put_uint32le(mbp, end - start);
  121         smb_rq_bend(rqp);
  122         error = smb_rq_simple(rqp);
  123         smb_rq_done(rqp);
  124         return error;
  125 }
  126 
  127 int
  128 smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
  129         off_t start, off_t end, struct smb_cred *scred)
  130 {
  131         struct smb_share *ssp = np->n_mount->sm_share;
  132 
  133         if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
  134                 /*
  135                  * TODO: use LOCK_BYTE_RANGE here.
  136                  */
  137                 return EINVAL;
  138         else
  139                 return smbfs_smb_lockandx(np, op, (uintptr_t)id, start, end, scred);
  140 }
  141 
  142 static int
  143 smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap,
  144                     struct smb_cred *scred, short infolevel)
  145 {
  146         struct smb_share *ssp = np->n_mount->sm_share;
  147         struct smb_vc *vcp = SSTOVC(ssp);
  148         struct smb_t2rq *t2p;
  149         int error, svtz, timesok = 1;
  150         struct mbchain *mbp;
  151         struct mdchain *mdp;
  152         u_int16_t date, time, wattr;
  153         int64_t lint;
  154         u_int32_t size, dattr;
  155 
  156         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION,
  157                              scred, &t2p);
  158         if (error)
  159                 return error;
  160         mbp = &t2p->t2_tparam;
  161         mb_init(mbp);
  162         if (!infolevel) {
  163                 if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
  164                         infolevel = SMB_QUERY_FILE_STANDARD;
  165                 else
  166                         infolevel = SMB_QUERY_FILE_BASIC_INFO;
  167         }
  168         mb_put_uint16le(mbp, infolevel);
  169         mb_put_uint32le(mbp, 0);
  170         /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
  171         error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
  172         if (error) {
  173                 smb_t2_done(t2p);
  174                 return error;
  175         }
  176         t2p->t2_maxpcount = 2;
  177         t2p->t2_maxdcount = vcp->vc_txmax;
  178         error = smb_t2_request(t2p);
  179         if (error) {
  180                 smb_t2_done(t2p);
  181                 if (infolevel == SMB_QUERY_FILE_STANDARD || error != EINVAL)
  182                         return error;
  183                 return smbfs_smb_qpathinfo(np, fap, scred,
  184                                            SMB_QUERY_FILE_STANDARD);
  185         }
  186         mdp = &t2p->t2_rdata;
  187         svtz = vcp->vc_sopt.sv_tz;
  188         switch (infolevel) {
  189             case SMB_QUERY_FILE_STANDARD:
  190                 timesok = 0;
  191                 md_get_uint16le(mdp, NULL);
  192                 md_get_uint16le(mdp, NULL);     /* creation time */
  193                 md_get_uint16le(mdp, &date);
  194                 md_get_uint16le(mdp, &time);    /* access time */
  195                 if (date || time) {
  196                         timesok++;
  197                         smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
  198                 }
  199                 md_get_uint16le(mdp, &date);
  200                 md_get_uint16le(mdp, &time);    /* modify time */
  201                 if (date || time) {
  202                         timesok++;
  203                         smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
  204                 }
  205                 md_get_uint32le(mdp, &size);
  206                 fap->fa_size = size;
  207                 md_get_uint32(mdp, NULL);       /* allocation size */
  208                 md_get_uint16le(mdp, &wattr);
  209                 fap->fa_attr = wattr;
  210                 break;
  211             case SMB_QUERY_FILE_BASIC_INFO:
  212                 timesok = 0;
  213                 md_get_int64(mdp, NULL);        /* creation time */
  214                 md_get_int64le(mdp, &lint);
  215                 if (lint) {
  216                         timesok++;
  217                         smb_time_NT2local(lint, svtz, &fap->fa_atime);
  218                 }
  219                 md_get_int64le(mdp, &lint);
  220                 if (lint) {
  221                         timesok++;
  222                         smb_time_NT2local(lint, svtz, &fap->fa_mtime);
  223                 }
  224                 md_get_int64le(mdp, &lint);
  225                 if (lint) {
  226                         timesok++;
  227                         smb_time_NT2local(lint, svtz, &fap->fa_ctime);
  228                 }
  229                 md_get_uint32le(mdp, &dattr);
  230                 fap->fa_attr = dattr;
  231                 md_get_uint32(mdp, NULL);
  232                 /* XXX could use ALL_INFO to get size */
  233                 break;
  234             default:
  235                 SMBERROR("unexpected info level %d\n", infolevel);
  236                 error = EINVAL;
  237         }
  238         smb_t2_done(t2p);
  239         /*
  240          * if all times are zero (observed with FAT on NT4SP6)
  241          * then fall back to older info level
  242          */
  243         if (!timesok) {
  244                 if (infolevel != SMB_QUERY_FILE_STANDARD)
  245                         return smbfs_smb_qpathinfo(np, fap, scred,
  246                                                    SMB_QUERY_FILE_STANDARD);
  247                 error = EINVAL;
  248         }
  249         return error;
  250 }
  251 
  252 int
  253 smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp,
  254         struct smb_cred *scred)
  255 {
  256         struct smb_t2rq *t2p;
  257         struct mbchain *mbp;
  258         struct mdchain *mdp;
  259         u_int16_t bsize;
  260         u_int32_t units, bpu, funits;
  261         int error;
  262 
  263         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
  264             scred, &t2p);
  265         if (error)
  266                 return error;
  267         mbp = &t2p->t2_tparam;
  268         mb_init(mbp);
  269         mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
  270         t2p->t2_maxpcount = 4;
  271         t2p->t2_maxdcount = 4 * 4 + 2;
  272         error = smb_t2_request(t2p);
  273         if (error) {
  274                 smb_t2_done(t2p);
  275                 return error;
  276         }
  277         mdp = &t2p->t2_rdata;
  278         md_get_uint32(mdp, NULL);       /* fs id */
  279         md_get_uint32le(mdp, &bpu);
  280         md_get_uint32le(mdp, &units);
  281         md_get_uint32le(mdp, &funits);
  282         md_get_uint16le(mdp, &bsize);
  283         sbp->f_bsize = bpu * bsize;     /* fundamental filesystem block size */
  284         sbp->f_blocks= units;           /* total data blocks in filesystem */
  285         sbp->f_bfree = funits;          /* free blocks in fs */
  286         sbp->f_bavail= funits;          /* free blocks avail to non-superuser */
  287         sbp->f_files = 0xffff;          /* total file nodes in filesystem */
  288         sbp->f_ffree = 0xffff;          /* free file nodes in fs */
  289         smb_t2_done(t2p);
  290         return 0;
  291 }
  292 
  293 int
  294 smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
  295         struct smb_cred *scred)
  296 {
  297         struct smb_rq rq, *rqp = &rq;
  298         struct mdchain *mdp;
  299         u_int16_t units, bpu, bsize, funits;
  300         int error;
  301 
  302         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, scred);
  303         if (error)
  304                 return error;
  305         smb_rq_wstart(rqp);
  306         smb_rq_wend(rqp);
  307         smb_rq_bstart(rqp);
  308         smb_rq_bend(rqp);
  309         error = smb_rq_simple(rqp);
  310         if (error) {
  311                 smb_rq_done(rqp);
  312                 return error;
  313         }
  314         smb_rq_getreply(rqp, &mdp);
  315         md_get_uint16le(mdp, &units);
  316         md_get_uint16le(mdp, &bpu);
  317         md_get_uint16le(mdp, &bsize);
  318         md_get_uint16le(mdp, &funits);
  319         sbp->f_bsize = bpu * bsize;     /* fundamental filesystem block size */
  320         sbp->f_blocks= units;           /* total data blocks in filesystem */
  321         sbp->f_bfree = funits;          /* free blocks in fs */
  322         sbp->f_bavail= funits;          /* free blocks avail to non-superuser */
  323         sbp->f_files = 0xffff;          /* total file nodes in filesystem */
  324         sbp->f_ffree = 0xffff;          /* free file nodes in fs */
  325         smb_rq_done(rqp);
  326         return 0;
  327 }
  328 
  329 static int
  330 smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
  331 {
  332         struct smb_t2rq *t2p;
  333         struct smb_share *ssp = np->n_mount->sm_share;
  334         struct mbchain *mbp;
  335         int error;
  336 
  337         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
  338             scred, &t2p);
  339         if (error)
  340                 return error;
  341         mbp = &t2p->t2_tparam;
  342         mb_init(mbp);
  343         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  344         mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO);
  345         mb_put_uint32le(mbp, 0);
  346         mbp = &t2p->t2_tdata;
  347         mb_init(mbp);
  348         mb_put_int64le(mbp, newsize);
  349         mb_put_uint32le(mbp, 0);                        /* padding */
  350         mb_put_uint16le(mbp, 0);
  351         t2p->t2_maxpcount = 2;
  352         t2p->t2_maxdcount = 0;
  353         error = smb_t2_request(t2p);
  354         smb_t2_done(t2p);
  355         return error;
  356 }
  357 
  358 static int
  359 smb_smb_flush(struct smbnode *np, struct smb_cred *scred)
  360 {
  361         struct smb_share *ssp = np->n_mount->sm_share;
  362         struct smb_rq rq, *rqp = &rq;
  363         struct mbchain *mbp;
  364         int error;
  365 
  366         if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) ||
  367             SMBTOV(np)->v_type != VREG)
  368                 return 0; /* not a regular open file */
  369         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scred);
  370         if (error)
  371                 return (error);
  372         smb_rq_getrequest(rqp, &mbp);
  373         smb_rq_wstart(rqp);
  374         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  375         smb_rq_wend(rqp);
  376         smb_rq_bstart(rqp);
  377         smb_rq_bend(rqp);
  378         error = smb_rq_simple(rqp);
  379         smb_rq_done(rqp);
  380         if (!error)
  381                 np->n_flag &= ~NFLUSHWIRE;
  382         return (error);
  383 }
  384 
  385 int
  386 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred)
  387 {
  388         if (np->n_flag & NFLUSHWIRE)
  389                 return (smb_smb_flush(np, scred));
  390         return (0);
  391 }
  392 
  393 int
  394 smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred)
  395 {
  396         struct smb_share *ssp = np->n_mount->sm_share;
  397         struct smb_rq rq, *rqp = &rq;
  398         struct mbchain *mbp;
  399         int error;
  400 
  401         if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) {
  402                 np->n_flag |= NFLUSHWIRE;
  403                 return (0);
  404         }
  405 
  406         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred);
  407         if (error)
  408                 return error;
  409         smb_rq_getrequest(rqp, &mbp);
  410         smb_rq_wstart(rqp);
  411         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  412         mb_put_uint16le(mbp, 0);
  413         mb_put_uint32le(mbp, newsize);
  414         mb_put_uint16le(mbp, 0);
  415         smb_rq_wend(rqp);
  416         smb_rq_bstart(rqp);
  417         mb_put_uint8(mbp, SMB_DT_DATA);
  418         mb_put_uint16le(mbp, 0);
  419         smb_rq_bend(rqp);
  420         error = smb_rq_simple(rqp);
  421         smb_rq_done(rqp);
  422         return error;
  423 }
  424 
  425 int
  426 smbfs_smb_query_info(struct smbnode *np, const char *name, int len,
  427                      struct smbfattr *fap, struct smb_cred *scred)
  428 {
  429         struct smb_rq rq, *rqp = &rq;
  430         struct smb_share *ssp = np->n_mount->sm_share;
  431         struct mbchain *mbp;
  432         struct mdchain *mdp;
  433         u_int8_t wc;
  434         int error;
  435         u_int16_t wattr;
  436         u_int32_t lint;
  437 
  438         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred);
  439         if (error)
  440                 return error;
  441         smb_rq_getrequest(rqp, &mbp);
  442         smb_rq_wstart(rqp);
  443         smb_rq_wend(rqp);
  444         smb_rq_bstart(rqp);
  445         mb_put_uint8(mbp, SMB_DT_ASCII);
  446         do {
  447                 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len);
  448                 if (error)
  449                         break;
  450                 smb_rq_bend(rqp);
  451                 error = smb_rq_simple(rqp);
  452                 if (error)
  453                         break;
  454                 smb_rq_getreply(rqp, &mdp);
  455                 if (md_get_uint8(mdp, &wc) != 0 || wc != 10) {
  456                         error = EBADRPC;
  457                         break;
  458                 }
  459                 md_get_uint16le(mdp, &wattr);
  460                 fap->fa_attr = wattr;
  461                 /*
  462                  * Be careful using the time returned here, as
  463                  * with FAT on NT4SP6, at least, the time returned is low
  464                  * 32 bits of 100s of nanoseconds (since 1601) so it rolls
  465                  * over about every seven minutes!
  466                  */
  467                 md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */
  468                 if (lint)       /* avoid bogus zero returns */
  469                         smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz,
  470                                               &fap->fa_mtime);
  471                 md_get_uint32le(mdp, &lint);
  472                 fap->fa_size = lint;
  473         } while(0);
  474         smb_rq_done(rqp);
  475         return error;
  476 }
  477 
  478 /*
  479  * Set DOS file attributes. mtime should be NULL for dialects above lm10
  480  */
  481 int
  482 smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
  483         struct smb_cred *scred)
  484 {
  485         struct smb_rq rq, *rqp = &rq;
  486         struct smb_share *ssp = np->n_mount->sm_share;
  487         struct mbchain *mbp;
  488         u_long time;
  489         int error, svtz;
  490 
  491         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred);
  492         if (error)
  493                 return error;
  494         svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
  495         smb_rq_getrequest(rqp, &mbp);
  496         smb_rq_wstart(rqp);
  497         mb_put_uint16le(mbp, attr);
  498         if (mtime) {
  499                 smb_time_local2server(mtime, svtz, &time);
  500         } else
  501                 time = 0;
  502         mb_put_uint32le(mbp, time);             /* mtime */
  503         mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
  504         smb_rq_wend(rqp);
  505         smb_rq_bstart(rqp);
  506         mb_put_uint8(mbp, SMB_DT_ASCII);
  507         do {
  508                 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
  509                 if (error)
  510                         break;
  511                 mb_put_uint8(mbp, SMB_DT_ASCII);
  512                 mb_put_uint8(mbp, 0);
  513                 smb_rq_bend(rqp);
  514                 error = smb_rq_simple(rqp);
  515                 if (error) {
  516                         SMBERROR("smb_rq_simple(rqp) => error %d\n", error);
  517                         break;
  518                 }
  519         } while(0);
  520         smb_rq_done(rqp);
  521         return error;
  522 }
  523 
  524 /*
  525  * Note, win95 doesn't support this call.
  526  */
  527 int
  528 smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
  529         struct timespec *atime, int attr, struct smb_cred *scred)
  530 {
  531         struct smb_t2rq *t2p;
  532         struct smb_share *ssp = np->n_mount->sm_share;
  533         struct smb_vc *vcp = SSTOVC(ssp);
  534         struct mbchain *mbp;
  535         u_int16_t date, time;
  536         int error, tzoff;
  537 
  538         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
  539             scred, &t2p);
  540         if (error)
  541                 return error;
  542         mbp = &t2p->t2_tparam;
  543         mb_init(mbp);
  544         mb_put_uint16le(mbp, SMB_INFO_STANDARD);
  545         mb_put_uint32le(mbp, 0);                /* MBZ */
  546         /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
  547         error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
  548         if (error) {
  549                 smb_t2_done(t2p);
  550                 return error;
  551         }
  552         tzoff = vcp->vc_sopt.sv_tz;
  553         mbp = &t2p->t2_tdata;
  554         mb_init(mbp);
  555         mb_put_uint32le(mbp, 0);                /* creation time */
  556         if (atime)
  557                 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
  558         else
  559                 time = date = 0;
  560         mb_put_uint16le(mbp, date);
  561         mb_put_uint16le(mbp, time);
  562         if (mtime)
  563                 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
  564         else
  565                 time = date = 0;
  566         mb_put_uint16le(mbp, date);
  567         mb_put_uint16le(mbp, time);
  568         mb_put_uint32le(mbp, 0);                /* file size */
  569         mb_put_uint32le(mbp, 0);                /* allocation unit size */
  570         mb_put_uint16le(mbp, attr);     /* DOS attr */
  571         mb_put_uint32le(mbp, 0);                /* EA size */
  572         t2p->t2_maxpcount = 5 * 2;
  573         t2p->t2_maxdcount = vcp->vc_txmax;
  574         error = smb_t2_request(t2p);
  575         smb_t2_done(t2p);
  576         return error;
  577 }
  578 
  579 /*
  580  * NT level. Specially for win9x
  581  */
  582 int
  583 smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
  584         struct timespec *atime, struct smb_cred *scred)
  585 {
  586         struct smb_t2rq *t2p;
  587         struct smb_share *ssp = np->n_mount->sm_share;
  588         struct smb_vc *vcp = SSTOVC(ssp);
  589         struct mbchain *mbp;
  590         int64_t tm;
  591         int error, tzoff;
  592 
  593         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
  594             scred, &t2p);
  595         if (error)
  596                 return error;
  597         mbp = &t2p->t2_tparam;
  598         mb_init(mbp);
  599         mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
  600         mb_put_uint32le(mbp, 0);                /* MBZ */
  601         /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
  602         error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
  603         if (error) {
  604                 smb_t2_done(t2p);
  605                 return error;
  606         }
  607         tzoff = vcp->vc_sopt.sv_tz;
  608         mbp = &t2p->t2_tdata;
  609         mb_init(mbp);
  610         mb_put_int64le(mbp, 0);         /* creation time */
  611         if (atime) {
  612                 smb_time_local2NT(atime, tzoff, &tm);
  613         } else
  614                 tm = 0;
  615         mb_put_int64le(mbp, tm);
  616         if (mtime) {
  617                 smb_time_local2NT(mtime, tzoff, &tm);
  618         } else
  619                 tm = 0;
  620         mb_put_int64le(mbp, tm);
  621         mb_put_int64le(mbp, tm);                /* change time */
  622         mb_put_uint32le(mbp, attr);             /* attr */
  623         t2p->t2_maxpcount = 24;
  624         t2p->t2_maxdcount = 56;
  625         error = smb_t2_request(t2p);
  626         smb_t2_done(t2p);
  627         return error;
  628 }
  629 
  630 /*
  631  * Set file atime and mtime. Doesn't supported by core dialect.
  632  */
  633 int
  634 smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
  635         struct timespec *atime, struct smb_cred *scred)
  636 {
  637         struct smb_rq rq, *rqp = &rq;
  638         struct smb_share *ssp = np->n_mount->sm_share;
  639         struct mbchain *mbp;
  640         u_int16_t date, time;
  641         int error, tzoff;
  642 
  643         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred);
  644         if (error)
  645                 return error;
  646         tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
  647         smb_rq_getrequest(rqp, &mbp);
  648         smb_rq_wstart(rqp);
  649         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  650         mb_put_uint32le(mbp, 0);                /* creation time */
  651 
  652         if (atime)
  653                 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
  654         else
  655                 time = date = 0;
  656         mb_put_uint16le(mbp, date);
  657         mb_put_uint16le(mbp, time);
  658         if (mtime)
  659                 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
  660         else
  661                 time = date = 0;
  662         mb_put_uint16le(mbp, date);
  663         mb_put_uint16le(mbp, time);
  664         smb_rq_wend(rqp);
  665         smb_rq_bstart(rqp);
  666         smb_rq_bend(rqp);
  667         error = smb_rq_simple(rqp);
  668         SMBSDEBUG("%d\n", error);
  669         smb_rq_done(rqp);
  670         return error;
  671 }
  672 
  673 /*
  674  * Set DOS file attributes.
  675  * Looks like this call can be used only if CAP_NT_SMBS bit is on.
  676  */
  677 int
  678 smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
  679         struct timespec *atime, struct smb_cred *scred)
  680 {
  681         struct smb_t2rq *t2p;
  682         struct smb_share *ssp = np->n_mount->sm_share;
  683         struct mbchain *mbp;
  684         int64_t tm;
  685         int error, svtz;
  686 
  687         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
  688             scred, &t2p);
  689         if (error)
  690                 return error;
  691         svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
  692         mbp = &t2p->t2_tparam;
  693         mb_init(mbp);
  694         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  695         mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
  696         mb_put_uint32le(mbp, 0);
  697         mbp = &t2p->t2_tdata;
  698         mb_init(mbp);
  699         mb_put_int64le(mbp, 0);         /* creation time */
  700         if (atime) {
  701                 smb_time_local2NT(atime, svtz, &tm);
  702         } else
  703                 tm = 0;
  704         mb_put_int64le(mbp, tm);
  705         if (mtime) {
  706                 smb_time_local2NT(mtime, svtz, &tm);
  707         } else
  708                 tm = 0;
  709         mb_put_int64le(mbp, tm);
  710         mb_put_int64le(mbp, tm);                /* change time */
  711         mb_put_uint16le(mbp, attr);
  712         mb_put_uint32le(mbp, 0);                        /* padding */
  713         mb_put_uint16le(mbp, 0);
  714         t2p->t2_maxpcount = 2;
  715         t2p->t2_maxdcount = 0;
  716         error = smb_t2_request(t2p);
  717         smb_t2_done(t2p);
  718         return error;
  719 }
  720 
  721 
  722 int
  723 smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
  724 {
  725         struct smb_rq rq, *rqp = &rq;
  726         struct smb_share *ssp = np->n_mount->sm_share;
  727         struct mbchain *mbp;
  728         struct mdchain *mdp;
  729         u_int8_t wc;
  730         u_int16_t fid, wattr, grantedmode;
  731         int error;
  732 
  733         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred);
  734         if (error)
  735                 return error;
  736         smb_rq_getrequest(rqp, &mbp);
  737         smb_rq_wstart(rqp);
  738         mb_put_uint16le(mbp, accmode);
  739         mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
  740         smb_rq_wend(rqp);
  741         smb_rq_bstart(rqp);
  742         mb_put_uint8(mbp, SMB_DT_ASCII);
  743         do {
  744                 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
  745                 if (error)
  746                         break;
  747                 smb_rq_bend(rqp);
  748                 error = smb_rq_simple(rqp);
  749                 if (error)
  750                         break;
  751                 smb_rq_getreply(rqp, &mdp);
  752                 if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
  753                         error = EBADRPC;
  754                         break;
  755                 }
  756                 md_get_uint16(mdp, &fid);
  757                 md_get_uint16le(mdp, &wattr);
  758                 md_get_uint32(mdp, NULL);       /* mtime */
  759                 md_get_uint32(mdp, NULL);       /* fsize */
  760                 md_get_uint16le(mdp, &grantedmode);
  761                 /*
  762                  * TODO: refresh attributes from this reply
  763                  */
  764         } while(0);
  765         smb_rq_done(rqp);
  766         if (error)
  767                 return error;
  768         np->n_fid = fid;
  769         np->n_rwstate = grantedmode;
  770         return 0;
  771 }
  772 
  773 
  774 int
  775 smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
  776         struct smb_cred *scred)
  777 {
  778         struct smb_rq rq, *rqp = &rq;
  779         struct mbchain *mbp;
  780         u_long time;
  781         int error;
  782 
  783         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred);
  784         if (error)
  785                 return error;
  786         smb_rq_getrequest(rqp, &mbp);
  787         smb_rq_wstart(rqp);
  788         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  789         if (mtime) {
  790                 smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
  791         } else
  792                 time = 0;
  793         mb_put_uint32le(mbp, time);
  794         smb_rq_wend(rqp);
  795         smb_rq_bstart(rqp);
  796         smb_rq_bend(rqp);
  797         error = smb_rq_simple(rqp);
  798         smb_rq_done(rqp);
  799         return error;
  800 }
  801 
  802 int
  803 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
  804         struct smb_cred *scred)
  805 {
  806         struct smb_rq rq, *rqp = &rq;
  807         struct smb_share *ssp = dnp->n_mount->sm_share;
  808         struct mbchain *mbp;
  809         struct mdchain *mdp;
  810         struct timespec ctime;
  811         u_int8_t wc;
  812         u_int16_t fid;
  813         u_long tm;
  814         int error;
  815 
  816         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred);
  817         if (error)
  818                 return error;
  819         smb_rq_getrequest(rqp, &mbp);
  820         smb_rq_wstart(rqp);
  821         mb_put_uint16le(mbp, SMB_FA_ARCHIVE);           /* attributes  */
  822         nanotime(&ctime);
  823         smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
  824         mb_put_uint32le(mbp, tm);
  825         smb_rq_wend(rqp);
  826         smb_rq_bstart(rqp);
  827         mb_put_uint8(mbp, SMB_DT_ASCII);
  828         error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen);
  829         if (!error) {
  830                 smb_rq_bend(rqp);
  831                 error = smb_rq_simple(rqp);
  832                 if (!error) {
  833                         smb_rq_getreply(rqp, &mdp);
  834                         md_get_uint8(mdp, &wc);
  835                         if (wc == 1)
  836                                 md_get_uint16(mdp, &fid);
  837                         else
  838                                 error = EBADRPC;
  839                 }
  840         }
  841         smb_rq_done(rqp);
  842         if (error)
  843                 return error;
  844         smbfs_smb_close(ssp, fid, &ctime, scred);
  845         return error;
  846 }
  847 
  848 int
  849 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
  850 {
  851         struct smb_rq rq, *rqp = &rq;
  852         struct smb_share *ssp = np->n_mount->sm_share;
  853         struct mbchain *mbp;
  854         int error;
  855 
  856         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred);
  857         if (error)
  858                 return error;
  859         smb_rq_getrequest(rqp, &mbp);
  860         smb_rq_wstart(rqp);
  861         mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
  862         smb_rq_wend(rqp);
  863         smb_rq_bstart(rqp);
  864         mb_put_uint8(mbp, SMB_DT_ASCII);
  865         error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
  866         if (!error) {
  867                 smb_rq_bend(rqp);
  868                 error = smb_rq_simple(rqp);
  869         }
  870         smb_rq_done(rqp);
  871         return error;
  872 }
  873 
  874 int
  875 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
  876         const char *tname, int tnmlen, struct smb_cred *scred)
  877 {
  878         struct smb_rq rq, *rqp = &rq;
  879         struct smb_share *ssp = src->n_mount->sm_share;
  880         struct mbchain *mbp;
  881         int error;
  882 
  883         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred);
  884         if (error)
  885                 return error;
  886         smb_rq_getrequest(rqp, &mbp);
  887         smb_rq_wstart(rqp);
  888         mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
  889         smb_rq_wend(rqp);
  890         smb_rq_bstart(rqp);
  891         mb_put_uint8(mbp, SMB_DT_ASCII);
  892         do {
  893                 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
  894                 if (error)
  895                         break;
  896                 mb_put_uint8(mbp, SMB_DT_ASCII);
  897                 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
  898                 if (error)
  899                         break;
  900                 smb_rq_bend(rqp);
  901                 error = smb_rq_simple(rqp);
  902         } while(0);
  903         smb_rq_done(rqp);
  904         return error;
  905 }
  906 
  907 int
  908 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
  909         const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
  910 {
  911         struct smb_rq rq, *rqp = &rq;
  912         struct smb_share *ssp = src->n_mount->sm_share;
  913         struct mbchain *mbp;
  914         int error;
  915 
  916         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred);
  917         if (error)
  918                 return error;
  919         smb_rq_getrequest(rqp, &mbp);
  920         smb_rq_wstart(rqp);
  921         mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
  922         mb_put_uint16le(mbp, 0x20);     /* delete target file */
  923         mb_put_uint16le(mbp, flags);
  924         smb_rq_wend(rqp);
  925         smb_rq_bstart(rqp);
  926         mb_put_uint8(mbp, SMB_DT_ASCII);
  927         do {
  928                 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
  929                 if (error)
  930                         break;
  931                 mb_put_uint8(mbp, SMB_DT_ASCII);
  932                 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
  933                 if (error)
  934                         break;
  935                 smb_rq_bend(rqp);
  936                 error = smb_rq_simple(rqp);
  937         } while(0);
  938         smb_rq_done(rqp);
  939         return error;
  940 }
  941 
  942 int
  943 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
  944         struct smb_cred *scred)
  945 {
  946         struct smb_rq rq, *rqp = &rq;
  947         struct smb_share *ssp = dnp->n_mount->sm_share;
  948         struct mbchain *mbp;
  949         int error;
  950 
  951         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred);
  952         if (error)
  953                 return error;
  954         smb_rq_getrequest(rqp, &mbp);
  955         smb_rq_wstart(rqp);
  956         smb_rq_wend(rqp);
  957         smb_rq_bstart(rqp);
  958         mb_put_uint8(mbp, SMB_DT_ASCII);
  959         error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len);
  960         if (!error) {
  961                 smb_rq_bend(rqp);
  962                 error = smb_rq_simple(rqp);
  963         }
  964         smb_rq_done(rqp);
  965         return error;
  966 }
  967 
  968 int
  969 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred)
  970 {
  971         struct smb_rq rq, *rqp = &rq;
  972         struct smb_share *ssp = np->n_mount->sm_share;
  973         struct mbchain *mbp;
  974         int error;
  975 
  976         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred);
  977         if (error)
  978                 return error;
  979         smb_rq_getrequest(rqp, &mbp);
  980         smb_rq_wstart(rqp);
  981         smb_rq_wend(rqp);
  982         smb_rq_bstart(rqp);
  983         mb_put_uint8(mbp, SMB_DT_ASCII);
  984         error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
  985         if (!error) {
  986                 smb_rq_bend(rqp);
  987                 error = smb_rq_simple(rqp);
  988         }
  989         smb_rq_done(rqp);
  990         return error;
  991 }
  992 
  993 static int
  994 smbfs_smb_search(struct smbfs_fctx *ctx)
  995 {
  996         struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
  997         struct smb_rq *rqp;
  998         struct mbchain *mbp;
  999         struct mdchain *mdp;
 1000         u_int8_t wc, bt;
 1001         u_int16_t ec, dlen, bc;
 1002         int maxent, error, iseof = 0;
 1003 
 1004         maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
 1005         if (ctx->f_rq) {
 1006                 smb_rq_done(ctx->f_rq);
 1007                 ctx->f_rq = NULL;
 1008         }
 1009         error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
 1010         if (error)
 1011                 return error;
 1012         ctx->f_rq = rqp;
 1013         smb_rq_getrequest(rqp, &mbp);
 1014         smb_rq_wstart(rqp);
 1015         mb_put_uint16le(mbp, maxent);   /* max entries to return */
 1016         mb_put_uint16le(mbp, ctx->f_attrmask);
 1017         smb_rq_wend(rqp);
 1018         smb_rq_bstart(rqp);
 1019         mb_put_uint8(mbp, SMB_DT_ASCII);        /* buffer format */
 1020         if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
 1021                 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
 1022                 if (error)
 1023                         return error;
 1024                 mb_put_uint8(mbp, SMB_DT_VARIABLE);
 1025                 mb_put_uint16le(mbp, 0);        /* context length */
 1026                 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
 1027         } else {
 1028                 mb_put_uint8(mbp, 0);   /* file name length */
 1029                 mb_put_uint8(mbp, SMB_DT_VARIABLE);
 1030                 mb_put_uint16le(mbp, SMB_SKEYLEN);
 1031                 mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
 1032         }
 1033         smb_rq_bend(rqp);
 1034         error = smb_rq_simple(rqp);
 1035         if (error) {
 1036                 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
 1037                         error = 0;
 1038                         iseof = 1;
 1039                         ctx->f_flags |= SMBFS_RDD_EOF;
 1040                 } else
 1041                         return error;
 1042         }
 1043         smb_rq_getreply(rqp, &mdp);
 1044         md_get_uint8(mdp, &wc);
 1045         if (wc != 1) 
 1046                 return iseof ? ENOENT : EBADRPC;
 1047         md_get_uint16le(mdp, &ec);
 1048         if (ec == 0)
 1049                 return ENOENT;
 1050         ctx->f_ecnt = ec;
 1051         md_get_uint16le(mdp, &bc);
 1052         if (bc < 3)
 1053                 return EBADRPC;
 1054         bc -= 3;
 1055         md_get_uint8(mdp, &bt);
 1056         if (bt != SMB_DT_VARIABLE)
 1057                 return EBADRPC;
 1058         md_get_uint16le(mdp, &dlen);
 1059         if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
 1060                 return EBADRPC;
 1061         return 0;
 1062 }
 1063 
 1064 static int
 1065 smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
 1066         const char *wildcard, int wclen, int attr, struct smb_cred *scred)
 1067 {
 1068         ctx->f_attrmask = attr;
 1069         if (wildcard) {
 1070                 if (wclen == 1 && wildcard[0] == '*') {
 1071                         ctx->f_wildcard = "*.*";
 1072                         ctx->f_wclen = 3;
 1073                 } else {
 1074                         ctx->f_wildcard = wildcard;
 1075                         ctx->f_wclen = wclen;
 1076                 }
 1077         } else {
 1078                 ctx->f_wildcard = NULL;
 1079                 ctx->f_wclen = 0;
 1080         }
 1081         ctx->f_name = ctx->f_fname;
 1082         return 0;
 1083 }
 1084 
 1085 static int
 1086 smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
 1087 {
 1088         struct mdchain *mbp;
 1089         struct smb_rq *rqp;
 1090         char *cp;
 1091         u_int8_t battr;
 1092         u_int16_t date, time;
 1093         u_int32_t size;
 1094         int error;
 1095 
 1096         if (ctx->f_ecnt == 0) {
 1097                 if (ctx->f_flags & SMBFS_RDD_EOF)
 1098                         return ENOENT;
 1099                 ctx->f_left = ctx->f_limit = limit;
 1100                 error = smbfs_smb_search(ctx);
 1101                 if (error)
 1102                         return error;
 1103         }
 1104         rqp = ctx->f_rq;
 1105         smb_rq_getreply(rqp, &mbp);
 1106         md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
 1107         md_get_uint8(mbp, &battr);
 1108         md_get_uint16le(mbp, &time);
 1109         md_get_uint16le(mbp, &date);
 1110         md_get_uint32le(mbp, &size);
 1111         cp = ctx->f_name;
 1112         md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM);
 1113         cp[sizeof(ctx->f_fname) - 1] = 0;
 1114         cp += strlen(cp) - 1;
 1115         while (*cp == ' ' && cp >= ctx->f_name)
 1116                 *cp-- = 0;
 1117         ctx->f_attr.fa_attr = battr;
 1118         smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
 1119             &ctx->f_attr.fa_mtime);
 1120         ctx->f_attr.fa_size = size;
 1121         ctx->f_nmlen = strlen(ctx->f_name);
 1122         ctx->f_ecnt--;
 1123         ctx->f_left--;
 1124         return 0;
 1125 }
 1126 
 1127 static int
 1128 smbfs_findcloseLM1(struct smbfs_fctx *ctx)
 1129 {
 1130         if (ctx->f_rq)
 1131                 smb_rq_done(ctx->f_rq);
 1132         return 0;
 1133 }
 1134 
 1135 /*
 1136  * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
 1137  */
 1138 static int
 1139 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
 1140 {
 1141         struct smb_t2rq *t2p;
 1142         struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
 1143         struct mbchain *mbp;
 1144         struct mdchain *mdp;
 1145         u_int16_t tw, flags;
 1146         int error;
 1147 
 1148         if (ctx->f_t2) {
 1149                 smb_t2_done(ctx->f_t2);
 1150                 ctx->f_t2 = NULL;
 1151         }
 1152         ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
 1153         flags = 8 | 2;                  /* <resume> | <close if EOS> */
 1154         if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
 1155                 flags |= 1;             /* close search after this request */
 1156                 ctx->f_flags |= SMBFS_RDD_NOCLOSE;
 1157         }
 1158         if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
 1159                 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
 1160                     ctx->f_scred, &t2p);
 1161                 if (error)
 1162                         return error;
 1163                 ctx->f_t2 = t2p;
 1164                 mbp = &t2p->t2_tparam;
 1165                 mb_init(mbp);
 1166                 mb_put_uint16le(mbp, ctx->f_attrmask);
 1167                 mb_put_uint16le(mbp, ctx->f_limit);
 1168                 mb_put_uint16le(mbp, flags);
 1169                 mb_put_uint16le(mbp, ctx->f_infolevel);
 1170                 mb_put_uint32le(mbp, 0);
 1171                 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
 1172                 if (error)
 1173                         return error;
 1174         } else  {
 1175                 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
 1176                     ctx->f_scred, &t2p);
 1177                 if (error)
 1178                         return error;
 1179                 ctx->f_t2 = t2p;
 1180                 mbp = &t2p->t2_tparam;
 1181                 mb_init(mbp);
 1182                 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
 1183                 mb_put_uint16le(mbp, ctx->f_limit);
 1184                 mb_put_uint16le(mbp, ctx->f_infolevel);
 1185                 mb_put_uint32le(mbp, 0);                /* resume key */
 1186                 mb_put_uint16le(mbp, flags);
 1187                 if (ctx->f_rname)
 1188                         mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM);
 1189                 else
 1190                         mb_put_uint8(mbp, 0);   /* resume file name */
 1191 #if 0
 1192         struct timeval tv;
 1193         tv.tv_sec = 0;
 1194         tv.tv_usec = 200 * 1000;        /* 200ms */
 1195                 if (vcp->vc_flags & SMBC_WIN95) {
 1196                         /*
 1197                          * some implementations suggests to sleep here
 1198                          * for 200ms, due to the bug in the Win95.
 1199                          * I've didn't notice any problem, but put code
 1200                          * for it.
 1201                          */
 1202                          pause("fix95", tvtohz(&tv));
 1203                 }
 1204 #endif
 1205         }
 1206         t2p->t2_maxpcount = 5 * 2;
 1207         t2p->t2_maxdcount = vcp->vc_txmax;
 1208         error = smb_t2_request(t2p);
 1209         if (error)
 1210                 return error;
 1211         mdp = &t2p->t2_rparam;
 1212         if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
 1213                 if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
 1214                         return error;
 1215                 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
 1216         }
 1217         if ((error = md_get_uint16le(mdp, &tw)) != 0)
 1218                 return error;
 1219         ctx->f_ecnt = tw;
 1220         if ((error = md_get_uint16le(mdp, &tw)) != 0)
 1221                 return error;
 1222         if (tw)
 1223                 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
 1224         if ((error = md_get_uint16le(mdp, &tw)) != 0)
 1225                 return error;
 1226         if ((error = md_get_uint16le(mdp, &tw)) != 0)
 1227                 return error;
 1228         if (ctx->f_ecnt == 0) {
 1229                 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
 1230                 return ENOENT;
 1231         }
 1232         ctx->f_rnameofs = tw;
 1233         mdp = &t2p->t2_rdata;
 1234         if (mdp->md_top == NULL) {
 1235                 printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt);
 1236                 return ENOENT;
 1237         }
 1238         if (mdp->md_top->m_len == 0) {
 1239                 printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next);
 1240                 return ENOENT;
 1241         }
 1242         ctx->f_eofs = 0;
 1243         return 0;
 1244 }
 1245 
 1246 static int
 1247 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
 1248 {
 1249         struct smb_rq rq, *rqp = &rq;
 1250         struct mbchain *mbp;
 1251         int error;
 1252 
 1253         error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred);
 1254         if (error)
 1255                 return error;
 1256         smb_rq_getrequest(rqp, &mbp);
 1257         smb_rq_wstart(rqp);
 1258         mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
 1259         smb_rq_wend(rqp);
 1260         smb_rq_bstart(rqp);
 1261         smb_rq_bend(rqp);
 1262         error = smb_rq_simple(rqp);
 1263         smb_rq_done(rqp);
 1264         return error;
 1265 }
 1266 
 1267 static int
 1268 smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
 1269         const char *wildcard, int wclen, int attr, struct smb_cred *scred)
 1270 {
 1271         ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
 1272         if (ctx->f_name == NULL)
 1273                 return ENOMEM;
 1274         ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
 1275             SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
 1276         ctx->f_attrmask = attr;
 1277         ctx->f_wildcard = wildcard;
 1278         ctx->f_wclen = wclen;
 1279         return 0;
 1280 }
 1281 
 1282 static int
 1283 smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
 1284 {
 1285         struct mdchain *mbp;
 1286         struct smb_t2rq *t2p;
 1287         char *cp;
 1288         u_int8_t tb;
 1289         u_int16_t date, time, wattr;
 1290         u_int32_t size, next, dattr;
 1291         int64_t lint;
 1292         int error, svtz, cnt, fxsz, nmlen, recsz;
 1293 
 1294         if (ctx->f_ecnt == 0) {
 1295                 if (ctx->f_flags & SMBFS_RDD_EOF)
 1296                         return ENOENT;
 1297                 ctx->f_left = ctx->f_limit = limit;
 1298                 error = smbfs_smb_trans2find2(ctx);
 1299                 if (error)
 1300                         return error;
 1301         }
 1302         t2p = ctx->f_t2;
 1303         mbp = &t2p->t2_rdata;
 1304         svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
 1305         switch (ctx->f_infolevel) {
 1306             case SMB_INFO_STANDARD:
 1307                 next = 0;
 1308                 fxsz = 0;
 1309                 md_get_uint16le(mbp, &date);
 1310                 md_get_uint16le(mbp, &time);    /* creation time */
 1311                 md_get_uint16le(mbp, &date);
 1312                 md_get_uint16le(mbp, &time);    /* access time */
 1313                 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
 1314                 md_get_uint16le(mbp, &date);
 1315                 md_get_uint16le(mbp, &time);    /* access time */
 1316                 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
 1317                 md_get_uint32le(mbp, &size);
 1318                 ctx->f_attr.fa_size = size;
 1319                 md_get_uint32(mbp, NULL);       /* allocation size */
 1320                 md_get_uint16le(mbp, &wattr);
 1321                 ctx->f_attr.fa_attr = wattr;
 1322                 md_get_uint8(mbp, &tb);
 1323                 size = nmlen = tb;
 1324                 fxsz = 23;
 1325                 recsz = next = 24 + nmlen;      /* docs misses zero byte at end */
 1326                 break;
 1327             case SMB_FIND_FILE_DIRECTORY_INFO:
 1328                 md_get_uint32le(mbp, &next);
 1329                 md_get_uint32(mbp, NULL);       /* file index */
 1330                 md_get_int64(mbp, NULL);        /* creation time */
 1331                 md_get_int64le(mbp, &lint);
 1332                 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime);
 1333                 md_get_int64le(mbp, &lint);
 1334                 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime);
 1335                 md_get_int64le(mbp, &lint);
 1336                 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime);
 1337                 md_get_int64le(mbp, &lint);     /* file size */
 1338                 ctx->f_attr.fa_size = lint;
 1339                 md_get_int64(mbp, NULL);        /* real size (should use) */
 1340                 md_get_uint32le(mbp, &dattr);   /* EA */
 1341                 ctx->f_attr.fa_attr = dattr;
 1342                 md_get_uint32le(mbp, &size);    /* name len */
 1343                 fxsz = 64;
 1344                 recsz = next ? next : fxsz + size;
 1345                 break;
 1346             default:
 1347                 SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
 1348                 return EINVAL;
 1349         }
 1350         nmlen = min(size, SMB_MAXFNAMELEN);
 1351         cp = ctx->f_name;
 1352         error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
 1353         if (error)
 1354                 return error;
 1355         if (next) {
 1356                 cnt = next - nmlen - fxsz;
 1357                 if (cnt > 0)
 1358                         md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
 1359                 else if (cnt < 0) {
 1360                         SMBERROR("out of sync\n");
 1361                         return EBADRPC;
 1362                 }
 1363         }
 1364         if (nmlen && cp[nmlen - 1] == 0)
 1365                 nmlen--;
 1366         if (nmlen == 0)
 1367                 return EBADRPC;
 1368 
 1369         next = ctx->f_eofs + recsz;
 1370         if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
 1371             (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
 1372                 /*
 1373                  * Server needs a resume filename.
 1374                  */
 1375                 if (ctx->f_rnamelen <= nmlen) {
 1376                         if (ctx->f_rname)
 1377                                 free(ctx->f_rname, M_SMBFSDATA);
 1378                         ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
 1379                         ctx->f_rnamelen = nmlen;
 1380                 }
 1381                 bcopy(ctx->f_name, ctx->f_rname, nmlen);
 1382                 ctx->f_rname[nmlen] = 0;
 1383                 ctx->f_flags |= SMBFS_RDD_GOTRNAME;
 1384         }
 1385         ctx->f_nmlen = nmlen;
 1386         ctx->f_eofs = next;
 1387         ctx->f_ecnt--;
 1388         ctx->f_left--;
 1389         return 0;
 1390 }
 1391 
 1392 static int
 1393 smbfs_findcloseLM2(struct smbfs_fctx *ctx)
 1394 {
 1395         if (ctx->f_name)
 1396                 free(ctx->f_name, M_SMBFSDATA);
 1397         if (ctx->f_t2)
 1398                 smb_t2_done(ctx->f_t2);
 1399         if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
 1400                 smbfs_smb_findclose2(ctx);
 1401         return 0;
 1402 }
 1403 
 1404 int
 1405 smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
 1406         struct smb_cred *scred, struct smbfs_fctx **ctxpp)
 1407 {
 1408         struct smbfs_fctx *ctx;
 1409         int error;
 1410 
 1411         ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK);
 1412         if (ctx == NULL)
 1413                 return ENOMEM;
 1414         bzero(ctx, sizeof(*ctx));
 1415         ctx->f_ssp = dnp->n_mount->sm_share;
 1416         ctx->f_dnp = dnp;
 1417         ctx->f_flags = SMBFS_RDD_FINDFIRST;
 1418         ctx->f_scred = scred;
 1419         if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
 1420             (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) {
 1421                 ctx->f_flags |= SMBFS_RDD_USESEARCH;
 1422                 error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
 1423         } else
 1424                 error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
 1425         if (error)
 1426                 smbfs_findclose(ctx, scred);
 1427         else
 1428                 *ctxpp = ctx;
 1429         return error;
 1430 }
 1431 
 1432 int
 1433 smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
 1434 {
 1435         int error;
 1436 
 1437         if (limit == 0)
 1438                 limit = 1000000;
 1439         else if (limit > 1)
 1440                 limit *= 4;     /* imperical */
 1441         ctx->f_scred = scred;
 1442         for (;;) {
 1443                 if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
 1444                         error = smbfs_findnextLM1(ctx, limit);
 1445                 } else
 1446                         error = smbfs_findnextLM2(ctx, limit);
 1447                 if (error)
 1448                         return error;
 1449                 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
 1450                     (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
 1451                      ctx->f_name[1] == '.'))
 1452                         continue;
 1453                 break;
 1454         }
 1455         smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen,
 1456                             ctx->f_dnp->n_mount->sm_caseopt);
 1457         ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
 1458         return 0;
 1459 }
 1460 
 1461 int
 1462 smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
 1463 {
 1464         ctx->f_scred = scred;
 1465         if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
 1466                 smbfs_findcloseLM1(ctx);
 1467         } else
 1468                 smbfs_findcloseLM2(ctx);
 1469         if (ctx->f_rname)
 1470                 free(ctx->f_rname, M_SMBFSDATA);
 1471         free(ctx, M_SMBFSDATA);
 1472         return 0;
 1473 }
 1474 
 1475 int
 1476 smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
 1477         struct smbfattr *fap, struct smb_cred *scred)
 1478 {
 1479         struct smbfs_fctx *ctx;
 1480         int error;
 1481 
 1482         if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
 1483                 bzero(fap, sizeof(*fap));
 1484                 fap->fa_attr = SMB_FA_DIR;
 1485                 fap->fa_ino = 2;
 1486                 return 0;
 1487         }
 1488         if (nmlen == 1 && name[0] == '.') {
 1489                 error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred);
 1490                 return error;
 1491         } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
 1492                 error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap,
 1493                     scred);
 1494                 printf("%s: knows NOTHING about '..'\n", __func__);
 1495                 return error;
 1496         }
 1497         error = smbfs_findopen(dnp, name, nmlen,
 1498             SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
 1499         if (error)
 1500                 return error;
 1501         ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
 1502         error = smbfs_findnext(ctx, 1, scred);
 1503         if (error == 0) {
 1504                 *fap = ctx->f_attr;
 1505                 if (name == NULL)
 1506                         fap->fa_ino = dnp->n_ino;
 1507         }
 1508         smbfs_findclose(ctx, scred);
 1509         return error;
 1510 }

Cache object: fea8c86fff40849c6fd88ddf9ac40a6b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.