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: releng/5.0/sys/fs/smbfs/smbfs_smb.c 106595 2002-11-07 22:35:45Z jhb $
   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_opencount <= 0 || !SMBTOV(np) || SMBTOV(np)->v_type != VREG)
  367                 return 0; /* not an regular open file */
  368         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scred);
  369         if (error)
  370                 return (error);
  371         smb_rq_getrequest(rqp, &mbp);
  372         smb_rq_wstart(rqp);
  373         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  374         smb_rq_wend(rqp);
  375         smb_rq_bstart(rqp);
  376         smb_rq_bend(rqp);
  377         error = smb_rq_simple(rqp);
  378         smb_rq_done(rqp);
  379         if (!error)
  380                 np->n_flag &= ~NFLUSHWIRE;
  381         return (error);
  382 }
  383 
  384 int
  385 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred)
  386 {
  387         if (np->n_flag & NFLUSHWIRE)
  388                 return (smb_smb_flush(np, scred));
  389         return (0);
  390 }
  391 
  392 int
  393 smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred)
  394 {
  395         struct smb_share *ssp = np->n_mount->sm_share;
  396         struct smb_rq rq, *rqp = &rq;
  397         struct mbchain *mbp;
  398         int error;
  399 
  400         if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) {
  401                 np->n_flag |= NFLUSHWIRE;
  402                 return (0);
  403         }
  404 
  405         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred);
  406         if (error)
  407                 return error;
  408         smb_rq_getrequest(rqp, &mbp);
  409         smb_rq_wstart(rqp);
  410         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  411         mb_put_uint16le(mbp, 0);
  412         mb_put_uint32le(mbp, newsize);
  413         mb_put_uint16le(mbp, 0);
  414         smb_rq_wend(rqp);
  415         smb_rq_bstart(rqp);
  416         mb_put_uint8(mbp, SMB_DT_DATA);
  417         mb_put_uint16le(mbp, 0);
  418         smb_rq_bend(rqp);
  419         error = smb_rq_simple(rqp);
  420         smb_rq_done(rqp);
  421         return error;
  422 }
  423 
  424 int
  425 smbfs_smb_query_info(struct smbnode *np, const char *name, int len,
  426                      struct smbfattr *fap, struct smb_cred *scred)
  427 {
  428         struct smb_rq rq, *rqp = &rq;
  429         struct smb_share *ssp = np->n_mount->sm_share;
  430         struct mbchain *mbp;
  431         struct mdchain *mdp;
  432         u_int8_t wc;
  433         int error;
  434         u_int16_t wattr;
  435         u_int32_t lint;
  436 
  437         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred);
  438         if (error)
  439                 return error;
  440         smb_rq_getrequest(rqp, &mbp);
  441         smb_rq_wstart(rqp);
  442         smb_rq_wend(rqp);
  443         smb_rq_bstart(rqp);
  444         mb_put_uint8(mbp, SMB_DT_ASCII);
  445         do {
  446                 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len);
  447                 if (error)
  448                         break;
  449                 smb_rq_bend(rqp);
  450                 error = smb_rq_simple(rqp);
  451                 if (error)
  452                         break;
  453                 smb_rq_getreply(rqp, &mdp);
  454                 if (md_get_uint8(mdp, &wc) != 0 || wc != 10) {
  455                         error = EBADRPC;
  456                         break;
  457                 }
  458                 md_get_uint16le(mdp, &wattr);
  459                 fap->fa_attr = wattr;
  460                 /*
  461                  * Be careful using the time returned here, as
  462                  * with FAT on NT4SP6, at least, the time returned is low
  463                  * 32 bits of 100s of nanoseconds (since 1601) so it rolls
  464                  * over about every seven minutes!
  465                  */
  466                 md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */
  467                 if (lint)       /* avoid bogus zero returns */
  468                         smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz,
  469                                               &fap->fa_mtime);
  470                 md_get_uint32le(mdp, &lint);
  471                 fap->fa_size = lint;
  472         } while(0);
  473         smb_rq_done(rqp);
  474         return error;
  475 }
  476 
  477 /*
  478  * Set DOS file attributes. mtime should be NULL for dialects above lm10
  479  */
  480 int
  481 smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
  482         struct smb_cred *scred)
  483 {
  484         struct smb_rq rq, *rqp = &rq;
  485         struct smb_share *ssp = np->n_mount->sm_share;
  486         struct mbchain *mbp;
  487         u_long time;
  488         int error, svtz;
  489 
  490         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred);
  491         if (error)
  492                 return error;
  493         svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
  494         smb_rq_getrequest(rqp, &mbp);
  495         smb_rq_wstart(rqp);
  496         mb_put_uint16le(mbp, attr);
  497         if (mtime) {
  498                 smb_time_local2server(mtime, svtz, &time);
  499         } else
  500                 time = 0;
  501         mb_put_uint32le(mbp, time);             /* mtime */
  502         mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
  503         smb_rq_wend(rqp);
  504         smb_rq_bstart(rqp);
  505         mb_put_uint8(mbp, SMB_DT_ASCII);
  506         do {
  507                 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
  508                 if (error)
  509                         break;
  510                 mb_put_uint8(mbp, SMB_DT_ASCII);
  511                 mb_put_uint8(mbp, 0);
  512                 smb_rq_bend(rqp);
  513                 error = smb_rq_simple(rqp);
  514                 SMBERROR("%d\n", error);
  515                 if (error)
  516                         break;
  517         } while(0);
  518         smb_rq_done(rqp);
  519         return error;
  520 }
  521 
  522 /*
  523  * Note, win95 doesn't support this call.
  524  */
  525 int
  526 smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
  527         struct timespec *atime, int attr, struct smb_cred *scred)
  528 {
  529         struct smb_t2rq *t2p;
  530         struct smb_share *ssp = np->n_mount->sm_share;
  531         struct smb_vc *vcp = SSTOVC(ssp);
  532         struct mbchain *mbp;
  533         u_int16_t date, time;
  534         int error, tzoff;
  535 
  536         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
  537             scred, &t2p);
  538         if (error)
  539                 return error;
  540         mbp = &t2p->t2_tparam;
  541         mb_init(mbp);
  542         mb_put_uint16le(mbp, SMB_INFO_STANDARD);
  543         mb_put_uint32le(mbp, 0);                /* MBZ */
  544         /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
  545         error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
  546         if (error) {
  547                 smb_t2_done(t2p);
  548                 return error;
  549         }
  550         tzoff = vcp->vc_sopt.sv_tz;
  551         mbp = &t2p->t2_tdata;
  552         mb_init(mbp);
  553         mb_put_uint32le(mbp, 0);                /* creation time */
  554         if (atime)
  555                 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
  556         else
  557                 time = date = 0;
  558         mb_put_uint16le(mbp, date);
  559         mb_put_uint16le(mbp, time);
  560         if (mtime)
  561                 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
  562         else
  563                 time = date = 0;
  564         mb_put_uint16le(mbp, date);
  565         mb_put_uint16le(mbp, time);
  566         mb_put_uint32le(mbp, 0);                /* file size */
  567         mb_put_uint32le(mbp, 0);                /* allocation unit size */
  568         mb_put_uint16le(mbp, attr);     /* DOS attr */
  569         mb_put_uint32le(mbp, 0);                /* EA size */
  570         t2p->t2_maxpcount = 5 * 2;
  571         t2p->t2_maxdcount = vcp->vc_txmax;
  572         error = smb_t2_request(t2p);
  573         smb_t2_done(t2p);
  574         return error;
  575 }
  576 
  577 /*
  578  * NT level. Specially for win9x
  579  */
  580 int
  581 smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
  582         struct timespec *atime, struct smb_cred *scred)
  583 {
  584         struct smb_t2rq *t2p;
  585         struct smb_share *ssp = np->n_mount->sm_share;
  586         struct smb_vc *vcp = SSTOVC(ssp);
  587         struct mbchain *mbp;
  588         int64_t tm;
  589         int error, tzoff;
  590 
  591         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
  592             scred, &t2p);
  593         if (error)
  594                 return error;
  595         mbp = &t2p->t2_tparam;
  596         mb_init(mbp);
  597         mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
  598         mb_put_uint32le(mbp, 0);                /* MBZ */
  599         /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
  600         error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
  601         if (error) {
  602                 smb_t2_done(t2p);
  603                 return error;
  604         }
  605         tzoff = vcp->vc_sopt.sv_tz;
  606         mbp = &t2p->t2_tdata;
  607         mb_init(mbp);
  608         mb_put_int64le(mbp, 0);         /* creation time */
  609         if (atime) {
  610                 smb_time_local2NT(atime, tzoff, &tm);
  611         } else
  612                 tm = 0;
  613         mb_put_int64le(mbp, tm);
  614         if (mtime) {
  615                 smb_time_local2NT(mtime, tzoff, &tm);
  616         } else
  617                 tm = 0;
  618         mb_put_int64le(mbp, tm);
  619         mb_put_int64le(mbp, tm);                /* change time */
  620         mb_put_uint32le(mbp, attr);             /* attr */
  621         t2p->t2_maxpcount = 24;
  622         t2p->t2_maxdcount = 56;
  623         error = smb_t2_request(t2p);
  624         smb_t2_done(t2p);
  625         return error;
  626 }
  627 
  628 /*
  629  * Set file atime and mtime. Doesn't supported by core dialect.
  630  */
  631 int
  632 smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
  633         struct timespec *atime, struct smb_cred *scred)
  634 {
  635         struct smb_rq rq, *rqp = &rq;
  636         struct smb_share *ssp = np->n_mount->sm_share;
  637         struct mbchain *mbp;
  638         u_int16_t date, time;
  639         int error, tzoff;
  640 
  641         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred);
  642         if (error)
  643                 return error;
  644         tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
  645         smb_rq_getrequest(rqp, &mbp);
  646         smb_rq_wstart(rqp);
  647         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  648         mb_put_uint32le(mbp, 0);                /* creation time */
  649 
  650         if (atime)
  651                 smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
  652         else
  653                 time = date = 0;
  654         mb_put_uint16le(mbp, date);
  655         mb_put_uint16le(mbp, time);
  656         if (mtime)
  657                 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
  658         else
  659                 time = date = 0;
  660         mb_put_uint16le(mbp, date);
  661         mb_put_uint16le(mbp, time);
  662         smb_rq_wend(rqp);
  663         smb_rq_bstart(rqp);
  664         smb_rq_bend(rqp);
  665         error = smb_rq_simple(rqp);
  666         SMBSDEBUG("%d\n", error);
  667         smb_rq_done(rqp);
  668         return error;
  669 }
  670 
  671 /*
  672  * Set DOS file attributes.
  673  * Looks like this call can be used only if CAP_NT_SMBS bit is on.
  674  */
  675 int
  676 smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
  677         struct timespec *atime, struct smb_cred *scred)
  678 {
  679         struct smb_t2rq *t2p;
  680         struct smb_share *ssp = np->n_mount->sm_share;
  681         struct mbchain *mbp;
  682         int64_t tm;
  683         int error, svtz;
  684 
  685         error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
  686             scred, &t2p);
  687         if (error)
  688                 return error;
  689         svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
  690         mbp = &t2p->t2_tparam;
  691         mb_init(mbp);
  692         mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
  693         mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
  694         mb_put_uint32le(mbp, 0);
  695         mbp = &t2p->t2_tdata;
  696         mb_init(mbp);
  697         mb_put_int64le(mbp, 0);         /* creation time */
  698         if (atime) {
  699                 smb_time_local2NT(atime, svtz, &tm);
  700         } else
  701                 tm = 0;
  702         mb_put_int64le(mbp, tm);
  703         if (mtime) {
  704                 smb_time_local2NT(mtime, svtz, &tm);
  705         } else
  706                 tm = 0;
  707         mb_put_int64le(mbp, tm);
  708         mb_put_int64le(mbp, tm);                /* change time */
  709         mb_put_uint16le(mbp, attr);
  710         mb_put_uint32le(mbp, 0);                        /* padding */
  711         mb_put_uint16le(mbp, 0);
  712         t2p->t2_maxpcount = 2;
  713         t2p->t2_maxdcount = 0;
  714         error = smb_t2_request(t2p);
  715         smb_t2_done(t2p);
  716         return error;
  717 }
  718 
  719 
  720 int
  721 smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
  722 {
  723         struct smb_rq rq, *rqp = &rq;
  724         struct smb_share *ssp = np->n_mount->sm_share;
  725         struct mbchain *mbp;
  726         struct mdchain *mdp;
  727         u_int8_t wc;
  728         u_int16_t fid, wattr, grantedmode;
  729         int error;
  730 
  731         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred);
  732         if (error)
  733                 return error;
  734         smb_rq_getrequest(rqp, &mbp);
  735         smb_rq_wstart(rqp);
  736         mb_put_uint16le(mbp, accmode);
  737         mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
  738         smb_rq_wend(rqp);
  739         smb_rq_bstart(rqp);
  740         mb_put_uint8(mbp, SMB_DT_ASCII);
  741         do {
  742                 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
  743                 if (error)
  744                         break;
  745                 smb_rq_bend(rqp);
  746                 error = smb_rq_simple(rqp);
  747                 if (error)
  748                         break;
  749                 smb_rq_getreply(rqp, &mdp);
  750                 if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
  751                         error = EBADRPC;
  752                         break;
  753                 }
  754                 md_get_uint16(mdp, &fid);
  755                 md_get_uint16le(mdp, &wattr);
  756                 md_get_uint32(mdp, NULL);       /* mtime */
  757                 md_get_uint32(mdp, NULL);       /* fsize */
  758                 md_get_uint16le(mdp, &grantedmode);
  759                 /*
  760                  * TODO: refresh attributes from this reply
  761                  */
  762         } while(0);
  763         smb_rq_done(rqp);
  764         if (error)
  765                 return error;
  766         np->n_fid = fid;
  767         np->n_rwstate = grantedmode;
  768         return 0;
  769 }
  770 
  771 
  772 int
  773 smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
  774         struct smb_cred *scred)
  775 {
  776         struct smb_rq rq, *rqp = &rq;
  777         struct mbchain *mbp;
  778         u_long time;
  779         int error;
  780 
  781         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred);
  782         if (error)
  783                 return error;
  784         smb_rq_getrequest(rqp, &mbp);
  785         smb_rq_wstart(rqp);
  786         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  787         if (mtime) {
  788                 smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
  789         } else
  790                 time = 0;
  791         mb_put_uint32le(mbp, time);
  792         smb_rq_wend(rqp);
  793         smb_rq_bstart(rqp);
  794         smb_rq_bend(rqp);
  795         error = smb_rq_simple(rqp);
  796         smb_rq_done(rqp);
  797         return error;
  798 }
  799 
  800 int
  801 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
  802         struct smb_cred *scred)
  803 {
  804         struct smb_rq rq, *rqp = &rq;
  805         struct smb_share *ssp = dnp->n_mount->sm_share;
  806         struct mbchain *mbp;
  807         struct mdchain *mdp;
  808         struct timespec ctime;
  809         u_int8_t wc;
  810         u_int16_t fid;
  811         u_long tm;
  812         int error;
  813 
  814         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred);
  815         if (error)
  816                 return error;
  817         smb_rq_getrequest(rqp, &mbp);
  818         smb_rq_wstart(rqp);
  819         mb_put_uint16le(mbp, SMB_FA_ARCHIVE);           /* attributes  */
  820         nanotime(&ctime);
  821         smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
  822         mb_put_uint32le(mbp, tm);
  823         smb_rq_wend(rqp);
  824         smb_rq_bstart(rqp);
  825         mb_put_uint8(mbp, SMB_DT_ASCII);
  826         error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen);
  827         if (!error) {
  828                 smb_rq_bend(rqp);
  829                 error = smb_rq_simple(rqp);
  830                 if (!error) {
  831                         smb_rq_getreply(rqp, &mdp);
  832                         md_get_uint8(mdp, &wc);
  833                         if (wc == 1)
  834                                 md_get_uint16(mdp, &fid);
  835                         else
  836                                 error = EBADRPC;
  837                 }
  838         }
  839         smb_rq_done(rqp);
  840         if (error)
  841                 return error;
  842         smbfs_smb_close(ssp, fid, &ctime, scred);
  843         return error;
  844 }
  845 
  846 int
  847 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
  848 {
  849         struct smb_rq rq, *rqp = &rq;
  850         struct smb_share *ssp = np->n_mount->sm_share;
  851         struct mbchain *mbp;
  852         int error;
  853 
  854         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred);
  855         if (error)
  856                 return error;
  857         smb_rq_getrequest(rqp, &mbp);
  858         smb_rq_wstart(rqp);
  859         mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
  860         smb_rq_wend(rqp);
  861         smb_rq_bstart(rqp);
  862         mb_put_uint8(mbp, SMB_DT_ASCII);
  863         error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
  864         if (!error) {
  865                 smb_rq_bend(rqp);
  866                 error = smb_rq_simple(rqp);
  867         }
  868         smb_rq_done(rqp);
  869         return error;
  870 }
  871 
  872 int
  873 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
  874         const char *tname, int tnmlen, struct smb_cred *scred)
  875 {
  876         struct smb_rq rq, *rqp = &rq;
  877         struct smb_share *ssp = src->n_mount->sm_share;
  878         struct mbchain *mbp;
  879         int error;
  880 
  881         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred);
  882         if (error)
  883                 return error;
  884         smb_rq_getrequest(rqp, &mbp);
  885         smb_rq_wstart(rqp);
  886         mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
  887         smb_rq_wend(rqp);
  888         smb_rq_bstart(rqp);
  889         mb_put_uint8(mbp, SMB_DT_ASCII);
  890         do {
  891                 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
  892                 if (error)
  893                         break;
  894                 mb_put_uint8(mbp, SMB_DT_ASCII);
  895                 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
  896                 if (error)
  897                         break;
  898                 smb_rq_bend(rqp);
  899                 error = smb_rq_simple(rqp);
  900         } while(0);
  901         smb_rq_done(rqp);
  902         return error;
  903 }
  904 
  905 int
  906 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
  907         const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
  908 {
  909         struct smb_rq rq, *rqp = &rq;
  910         struct smb_share *ssp = src->n_mount->sm_share;
  911         struct mbchain *mbp;
  912         int error;
  913 
  914         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred);
  915         if (error)
  916                 return error;
  917         smb_rq_getrequest(rqp, &mbp);
  918         smb_rq_wstart(rqp);
  919         mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
  920         mb_put_uint16le(mbp, 0x20);     /* delete target file */
  921         mb_put_uint16le(mbp, flags);
  922         smb_rq_wend(rqp);
  923         smb_rq_bstart(rqp);
  924         mb_put_uint8(mbp, SMB_DT_ASCII);
  925         do {
  926                 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
  927                 if (error)
  928                         break;
  929                 mb_put_uint8(mbp, SMB_DT_ASCII);
  930                 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
  931                 if (error)
  932                         break;
  933                 smb_rq_bend(rqp);
  934                 error = smb_rq_simple(rqp);
  935         } while(0);
  936         smb_rq_done(rqp);
  937         return error;
  938 }
  939 
  940 int
  941 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
  942         struct smb_cred *scred)
  943 {
  944         struct smb_rq rq, *rqp = &rq;
  945         struct smb_share *ssp = dnp->n_mount->sm_share;
  946         struct mbchain *mbp;
  947         int error;
  948 
  949         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred);
  950         if (error)
  951                 return error;
  952         smb_rq_getrequest(rqp, &mbp);
  953         smb_rq_wstart(rqp);
  954         smb_rq_wend(rqp);
  955         smb_rq_bstart(rqp);
  956         mb_put_uint8(mbp, SMB_DT_ASCII);
  957         error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len);
  958         if (!error) {
  959                 smb_rq_bend(rqp);
  960                 error = smb_rq_simple(rqp);
  961         }
  962         smb_rq_done(rqp);
  963         return error;
  964 }
  965 
  966 int
  967 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred)
  968 {
  969         struct smb_rq rq, *rqp = &rq;
  970         struct smb_share *ssp = np->n_mount->sm_share;
  971         struct mbchain *mbp;
  972         int error;
  973 
  974         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred);
  975         if (error)
  976                 return error;
  977         smb_rq_getrequest(rqp, &mbp);
  978         smb_rq_wstart(rqp);
  979         smb_rq_wend(rqp);
  980         smb_rq_bstart(rqp);
  981         mb_put_uint8(mbp, SMB_DT_ASCII);
  982         error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
  983         if (!error) {
  984                 smb_rq_bend(rqp);
  985                 error = smb_rq_simple(rqp);
  986         }
  987         smb_rq_done(rqp);
  988         return error;
  989 }
  990 
  991 static int
  992 smbfs_smb_search(struct smbfs_fctx *ctx)
  993 {
  994         struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
  995         struct smb_rq *rqp;
  996         struct mbchain *mbp;
  997         struct mdchain *mdp;
  998         u_int8_t wc, bt;
  999         u_int16_t ec, dlen, bc;
 1000         int maxent, error, iseof = 0;
 1001 
 1002         maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
 1003         if (ctx->f_rq) {
 1004                 smb_rq_done(ctx->f_rq);
 1005                 ctx->f_rq = NULL;
 1006         }
 1007         error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
 1008         if (error)
 1009                 return error;
 1010         ctx->f_rq = rqp;
 1011         smb_rq_getrequest(rqp, &mbp);
 1012         smb_rq_wstart(rqp);
 1013         mb_put_uint16le(mbp, maxent);   /* max entries to return */
 1014         mb_put_uint16le(mbp, ctx->f_attrmask);
 1015         smb_rq_wend(rqp);
 1016         smb_rq_bstart(rqp);
 1017         mb_put_uint8(mbp, SMB_DT_ASCII);        /* buffer format */
 1018         if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
 1019                 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
 1020                 if (error)
 1021                         return error;
 1022                 mb_put_uint8(mbp, SMB_DT_VARIABLE);
 1023                 mb_put_uint16le(mbp, 0);        /* context length */
 1024                 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
 1025         } else {
 1026                 mb_put_uint8(mbp, 0);   /* file name length */
 1027                 mb_put_uint8(mbp, SMB_DT_VARIABLE);
 1028                 mb_put_uint16le(mbp, SMB_SKEYLEN);
 1029                 mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
 1030         }
 1031         smb_rq_bend(rqp);
 1032         error = smb_rq_simple(rqp);
 1033         if (error) {
 1034                 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
 1035                         error = 0;
 1036                         iseof = 1;
 1037                         ctx->f_flags |= SMBFS_RDD_EOF;
 1038                 } else
 1039                         return error;
 1040         }
 1041         smb_rq_getreply(rqp, &mdp);
 1042         md_get_uint8(mdp, &wc);
 1043         if (wc != 1) 
 1044                 return iseof ? ENOENT : EBADRPC;
 1045         md_get_uint16le(mdp, &ec);
 1046         if (ec == 0)
 1047                 return ENOENT;
 1048         ctx->f_ecnt = ec;
 1049         md_get_uint16le(mdp, &bc);
 1050         if (bc < 3)
 1051                 return EBADRPC;
 1052         bc -= 3;
 1053         md_get_uint8(mdp, &bt);
 1054         if (bt != SMB_DT_VARIABLE)
 1055                 return EBADRPC;
 1056         md_get_uint16le(mdp, &dlen);
 1057         if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
 1058                 return EBADRPC;
 1059         return 0;
 1060 }
 1061 
 1062 static int
 1063 smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
 1064         const char *wildcard, int wclen, int attr, struct smb_cred *scred)
 1065 {
 1066         ctx->f_attrmask = attr;
 1067         if (wildcard) {
 1068                 if (wclen == 1 && wildcard[0] == '*') {
 1069                         ctx->f_wildcard = "*.*";
 1070                         ctx->f_wclen = 3;
 1071                 } else {
 1072                         ctx->f_wildcard = wildcard;
 1073                         ctx->f_wclen = wclen;
 1074                 }
 1075         } else {
 1076                 ctx->f_wildcard = NULL;
 1077                 ctx->f_wclen = 0;
 1078         }
 1079         ctx->f_name = ctx->f_fname;
 1080         return 0;
 1081 }
 1082 
 1083 static int
 1084 smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
 1085 {
 1086         struct mdchain *mbp;
 1087         struct smb_rq *rqp;
 1088         char *cp;
 1089         u_int8_t battr;
 1090         u_int16_t date, time;
 1091         u_int32_t size;
 1092         int error;
 1093 
 1094         if (ctx->f_ecnt == 0) {
 1095                 if (ctx->f_flags & SMBFS_RDD_EOF)
 1096                         return ENOENT;
 1097                 ctx->f_left = ctx->f_limit = limit;
 1098                 error = smbfs_smb_search(ctx);
 1099                 if (error)
 1100                         return error;
 1101         }
 1102         rqp = ctx->f_rq;
 1103         smb_rq_getreply(rqp, &mbp);
 1104         md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
 1105         md_get_uint8(mbp, &battr);
 1106         md_get_uint16le(mbp, &time);
 1107         md_get_uint16le(mbp, &date);
 1108         md_get_uint32le(mbp, &size);
 1109         cp = ctx->f_name;
 1110         md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM);
 1111         cp[sizeof(ctx->f_fname) - 1] = 0;
 1112         cp += strlen(cp) - 1;
 1113         while (*cp == ' ' && cp >= ctx->f_name)
 1114                 *cp-- = 0;
 1115         ctx->f_attr.fa_attr = battr;
 1116         smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
 1117             &ctx->f_attr.fa_mtime);
 1118         ctx->f_attr.fa_size = size;
 1119         ctx->f_nmlen = strlen(ctx->f_name);
 1120         ctx->f_ecnt--;
 1121         ctx->f_left--;
 1122         return 0;
 1123 }
 1124 
 1125 static int
 1126 smbfs_findcloseLM1(struct smbfs_fctx *ctx)
 1127 {
 1128         if (ctx->f_rq)
 1129                 smb_rq_done(ctx->f_rq);
 1130         return 0;
 1131 }
 1132 
 1133 /*
 1134  * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
 1135  */
 1136 static int
 1137 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
 1138 {
 1139         struct smb_t2rq *t2p;
 1140         struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
 1141         struct mbchain *mbp;
 1142         struct mdchain *mdp;
 1143         u_int16_t tw, flags;
 1144         int error;
 1145 
 1146         if (ctx->f_t2) {
 1147                 smb_t2_done(ctx->f_t2);
 1148                 ctx->f_t2 = NULL;
 1149         }
 1150         ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
 1151         flags = 8 | 2;                  /* <resume> | <close if EOS> */
 1152         if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
 1153                 flags |= 1;             /* close search after this request */
 1154                 ctx->f_flags |= SMBFS_RDD_NOCLOSE;
 1155         }
 1156         if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
 1157                 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
 1158                     ctx->f_scred, &t2p);
 1159                 if (error)
 1160                         return error;
 1161                 ctx->f_t2 = t2p;
 1162                 mbp = &t2p->t2_tparam;
 1163                 mb_init(mbp);
 1164                 mb_put_uint16le(mbp, ctx->f_attrmask);
 1165                 mb_put_uint16le(mbp, ctx->f_limit);
 1166                 mb_put_uint16le(mbp, flags);
 1167                 mb_put_uint16le(mbp, ctx->f_infolevel);
 1168                 mb_put_uint32le(mbp, 0);
 1169                 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
 1170                 if (error)
 1171                         return error;
 1172         } else  {
 1173                 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
 1174                     ctx->f_scred, &t2p);
 1175                 if (error)
 1176                         return error;
 1177                 ctx->f_t2 = t2p;
 1178                 mbp = &t2p->t2_tparam;
 1179                 mb_init(mbp);
 1180                 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
 1181                 mb_put_uint16le(mbp, ctx->f_limit);
 1182                 mb_put_uint16le(mbp, ctx->f_infolevel);
 1183                 mb_put_uint32le(mbp, 0);                /* resume key */
 1184                 mb_put_uint16le(mbp, flags);
 1185                 if (ctx->f_rname)
 1186                         mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM);
 1187                 else
 1188                         mb_put_uint8(mbp, 0);   /* resume file name */
 1189 #if 0
 1190         struct timeval tv;
 1191         tv.tv_sec = 0;
 1192         tv.tv_usec = 200 * 1000;        /* 200ms */
 1193                 if (vcp->vc_flags & SMBC_WIN95) {
 1194                         /*
 1195                          * some implementations suggests to sleep here
 1196                          * for 200ms, due to the bug in the Win95.
 1197                          * I've didn't notice any problem, but put code
 1198                          * for it.
 1199                          */
 1200                          tsleep(&flags, PVFS, "fix95", tvtohz(&tv));
 1201                 }
 1202 #endif
 1203         }
 1204         t2p->t2_maxpcount = 5 * 2;
 1205         t2p->t2_maxdcount = vcp->vc_txmax;
 1206         error = smb_t2_request(t2p);
 1207         if (error)
 1208                 return error;
 1209         mdp = &t2p->t2_rparam;
 1210         if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
 1211                 if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
 1212                         return error;
 1213                 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
 1214         }
 1215         if ((error = md_get_uint16le(mdp, &tw)) != 0)
 1216                 return error;
 1217         ctx->f_ecnt = tw;
 1218         if ((error = md_get_uint16le(mdp, &tw)) != 0)
 1219                 return error;
 1220         if (tw)
 1221                 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
 1222         if ((error = md_get_uint16le(mdp, &tw)) != 0)
 1223                 return error;
 1224         if ((error = md_get_uint16le(mdp, &tw)) != 0)
 1225                 return error;
 1226         if (ctx->f_ecnt == 0)
 1227                 return ENOENT;
 1228         ctx->f_rnameofs = tw;
 1229         mdp = &t2p->t2_rdata;
 1230         if (mdp->md_top == NULL) {
 1231                 printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt);
 1232                 return ENOENT;
 1233         }
 1234         if (mdp->md_top->m_len == 0) {
 1235                 printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next);
 1236                 return ENOENT;
 1237         }
 1238         ctx->f_eofs = 0;
 1239         return 0;
 1240 }
 1241 
 1242 static int
 1243 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
 1244 {
 1245         struct smb_rq rq, *rqp = &rq;
 1246         struct mbchain *mbp;
 1247         int error;
 1248 
 1249         error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred);
 1250         if (error)
 1251                 return error;
 1252         smb_rq_getrequest(rqp, &mbp);
 1253         smb_rq_wstart(rqp);
 1254         mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
 1255         smb_rq_wend(rqp);
 1256         smb_rq_bstart(rqp);
 1257         smb_rq_bend(rqp);
 1258         error = smb_rq_simple(rqp);
 1259         smb_rq_done(rqp);
 1260         return error;
 1261 }
 1262 
 1263 static int
 1264 smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
 1265         const char *wildcard, int wclen, int attr, struct smb_cred *scred)
 1266 {
 1267         ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
 1268         if (ctx->f_name == NULL)
 1269                 return ENOMEM;
 1270         ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
 1271             SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
 1272         ctx->f_attrmask = attr;
 1273         ctx->f_wildcard = wildcard;
 1274         ctx->f_wclen = wclen;
 1275         return 0;
 1276 }
 1277 
 1278 static int
 1279 smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
 1280 {
 1281         struct mdchain *mbp;
 1282         struct smb_t2rq *t2p;
 1283         char *cp;
 1284         u_int8_t tb;
 1285         u_int16_t date, time, wattr;
 1286         u_int32_t size, next, dattr;
 1287         int64_t lint;
 1288         int error, svtz, cnt, fxsz, nmlen, recsz;
 1289 
 1290         if (ctx->f_ecnt == 0) {
 1291                 if (ctx->f_flags & SMBFS_RDD_EOF)
 1292                         return ENOENT;
 1293                 ctx->f_left = ctx->f_limit = limit;
 1294                 error = smbfs_smb_trans2find2(ctx);
 1295                 if (error)
 1296                         return error;
 1297         }
 1298         t2p = ctx->f_t2;
 1299         mbp = &t2p->t2_rdata;
 1300         svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
 1301         switch (ctx->f_infolevel) {
 1302             case SMB_INFO_STANDARD:
 1303                 next = 0;
 1304                 fxsz = 0;
 1305                 md_get_uint16le(mbp, &date);
 1306                 md_get_uint16le(mbp, &time);    /* creation time */
 1307                 md_get_uint16le(mbp, &date);
 1308                 md_get_uint16le(mbp, &time);    /* access time */
 1309                 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
 1310                 md_get_uint16le(mbp, &date);
 1311                 md_get_uint16le(mbp, &time);    /* access time */
 1312                 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
 1313                 md_get_uint32le(mbp, &size);
 1314                 ctx->f_attr.fa_size = size;
 1315                 md_get_uint32(mbp, NULL);       /* allocation size */
 1316                 md_get_uint16le(mbp, &wattr);
 1317                 ctx->f_attr.fa_attr = wattr;
 1318                 md_get_uint8(mbp, &tb);
 1319                 size = nmlen = tb;
 1320                 fxsz = 23;
 1321                 recsz = next = 24 + nmlen;      /* docs misses zero byte at end */
 1322                 break;
 1323             case SMB_FIND_FILE_DIRECTORY_INFO:
 1324                 md_get_uint32le(mbp, &next);
 1325                 md_get_uint32(mbp, NULL);       /* file index */
 1326                 md_get_int64(mbp, NULL);        /* creation time */
 1327                 md_get_int64le(mbp, &lint);
 1328                 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime);
 1329                 md_get_int64le(mbp, &lint);
 1330                 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime);
 1331                 md_get_int64le(mbp, &lint);
 1332                 smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime);
 1333                 md_get_int64le(mbp, &lint);     /* file size */
 1334                 ctx->f_attr.fa_size = lint;
 1335                 md_get_int64(mbp, NULL);        /* real size (should use) */
 1336                 md_get_uint32le(mbp, &dattr);   /* EA */
 1337                 ctx->f_attr.fa_attr = dattr;
 1338                 md_get_uint32le(mbp, &size);    /* name len */
 1339                 fxsz = 64;
 1340                 recsz = next ? next : fxsz + size;
 1341                 break;
 1342             default:
 1343                 SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
 1344                 return EINVAL;
 1345         }
 1346         nmlen = min(size, SMB_MAXFNAMELEN);
 1347         cp = ctx->f_name;
 1348         error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
 1349         if (error)
 1350                 return error;
 1351         if (next) {
 1352                 cnt = next - nmlen - fxsz;
 1353                 if (cnt > 0)
 1354                         md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
 1355                 else if (cnt < 0) {
 1356                         SMBERROR("out of sync\n");
 1357                         return EBADRPC;
 1358                 }
 1359         }
 1360         if (nmlen && cp[nmlen - 1] == 0)
 1361                 nmlen--;
 1362         if (nmlen == 0)
 1363                 return EBADRPC;
 1364 
 1365         next = ctx->f_eofs + recsz;
 1366         if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
 1367             (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
 1368                 /*
 1369                  * Server needs a resume filename.
 1370                  */
 1371                 if (ctx->f_rnamelen <= nmlen) {
 1372                         if (ctx->f_rname)
 1373                                 free(ctx->f_rname, M_SMBFSDATA);
 1374                         ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
 1375                         ctx->f_rnamelen = nmlen;
 1376                 }
 1377                 bcopy(ctx->f_name, ctx->f_rname, nmlen);
 1378                 ctx->f_rname[nmlen] = 0;
 1379                 ctx->f_flags |= SMBFS_RDD_GOTRNAME;
 1380         }
 1381         ctx->f_nmlen = nmlen;
 1382         ctx->f_eofs = next;
 1383         ctx->f_ecnt--;
 1384         ctx->f_left--;
 1385         return 0;
 1386 }
 1387 
 1388 static int
 1389 smbfs_findcloseLM2(struct smbfs_fctx *ctx)
 1390 {
 1391         if (ctx->f_name)
 1392                 free(ctx->f_name, M_SMBFSDATA);
 1393         if (ctx->f_t2)
 1394                 smb_t2_done(ctx->f_t2);
 1395         if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
 1396                 smbfs_smb_findclose2(ctx);
 1397         return 0;
 1398 }
 1399 
 1400 int
 1401 smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
 1402         struct smb_cred *scred, struct smbfs_fctx **ctxpp)
 1403 {
 1404         struct smbfs_fctx *ctx;
 1405         int error;
 1406 
 1407         ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK);
 1408         if (ctx == NULL)
 1409                 return ENOMEM;
 1410         bzero(ctx, sizeof(*ctx));
 1411         ctx->f_ssp = dnp->n_mount->sm_share;
 1412         ctx->f_dnp = dnp;
 1413         ctx->f_flags = SMBFS_RDD_FINDFIRST;
 1414         ctx->f_scred = scred;
 1415         if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
 1416             (dnp->n_mount->sm_args.flags & SMBFS_MOUNT_NO_LONG)) {
 1417                 ctx->f_flags |= SMBFS_RDD_USESEARCH;
 1418                 error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
 1419         } else
 1420                 error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
 1421         if (error)
 1422                 smbfs_findclose(ctx, scred);
 1423         else
 1424                 *ctxpp = ctx;
 1425         return error;
 1426 }
 1427 
 1428 int
 1429 smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
 1430 {
 1431         int error;
 1432 
 1433         if (limit == 0)
 1434                 limit = 1000000;
 1435         else if (limit > 1)
 1436                 limit *= 4;     /* imperical */
 1437         ctx->f_scred = scred;
 1438         for (;;) {
 1439                 if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
 1440                         error = smbfs_findnextLM1(ctx, limit);
 1441                 } else
 1442                         error = smbfs_findnextLM2(ctx, limit);
 1443                 if (error)
 1444                         return error;
 1445                 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
 1446                     (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
 1447                      ctx->f_name[1] == '.'))
 1448                         continue;
 1449                 break;
 1450         }
 1451         smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, ctx->f_nmlen,
 1452             ctx->f_dnp->n_mount->sm_caseopt);
 1453         ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
 1454         return 0;
 1455 }
 1456 
 1457 int
 1458 smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
 1459 {
 1460         ctx->f_scred = scred;
 1461         if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
 1462                 smbfs_findcloseLM1(ctx);
 1463         } else
 1464                 smbfs_findcloseLM2(ctx);
 1465         if (ctx->f_rname)
 1466                 free(ctx->f_rname, M_SMBFSDATA);
 1467         free(ctx, M_SMBFSDATA);
 1468         return 0;
 1469 }
 1470 
 1471 int
 1472 smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
 1473         struct smbfattr *fap, struct smb_cred *scred)
 1474 {
 1475         struct smbfs_fctx *ctx;
 1476         int error;
 1477 
 1478         if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
 1479                 bzero(fap, sizeof(*fap));
 1480                 fap->fa_attr = SMB_FA_DIR;
 1481                 fap->fa_ino = 2;
 1482                 return 0;
 1483         }
 1484         if (nmlen == 1 && name[0] == '.') {
 1485                 error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred);
 1486                 return error;
 1487         } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
 1488                 error = smbfs_smb_lookup(dnp->n_parent, NULL, 0, fap, scred);
 1489                 printf("%s: knows NOTHING about '..'\n", __func__);
 1490                 return error;
 1491         }
 1492         error = smbfs_findopen(dnp, name, nmlen,
 1493             SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
 1494         if (error)
 1495                 return error;
 1496         ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
 1497         error = smbfs_findnext(ctx, 1, scred);
 1498         if (error == 0) {
 1499                 *fap = ctx->f_attr;
 1500                 if (name == NULL)
 1501                         fap->fa_ino = dnp->n_ino;
 1502         }
 1503         smbfs_findclose(ctx, scred);
 1504         return error;
 1505 }

Cache object: 3a30ee0d5985b07eb45670b08a31f5e0


[ 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.