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

Cache object: 7a5e88d82583d2db80d5a33fc3a88f68


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