root/isofs/udf/udf_vnops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. udf_hashlookup
  2. udf_hashins
  3. udf_hashrem
  4. udf_allocv
  5. udf_permtomode
  6. udf_access
  7. udf_isaleapyear
  8. udf_timetotimespec
  9. udf_getattr
  10. udf_open
  11. udf_close
  12. udf_ioctl
  13. udf_pathconf
  14. udf_read
  15. udf_transname
  16. udf_cmpname
  17. udf_uiodir
  18. udf_opendir
  19. udf_getfid
  20. udf_closedir
  21. udf_readdir
  22. udf_readlink
  23. udf_strategy
  24. udf_lock
  25. udf_unlock
  26. udf_islocked
  27. udf_print
  28. udf_bmap
  29. udf_lookup
  30. udf_inactive
  31. udf_reclaim
  32. udf_readatoffset
  33. udf_bmap_internal

    1 /*      $OpenBSD: udf_vnops.c,v 1.27 2007/06/06 17:15:13 deraadt Exp $  */
    2 
    3 /*
    4  * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  * $FreeBSD: src/sys/fs/udf/udf_vnops.c,v 1.50 2005/01/28 14:42:16 phk Exp $
   29  */
   30 
   31 /*
   32  * Ported to OpenBSD by Pedro Martelletto <pedro@openbsd.org> in February 2005.
   33  */
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/namei.h>
   38 #include <sys/kernel.h>
   39 #include <sys/malloc.h>
   40 #include <sys/mutex.h>
   41 #include <sys/stat.h>
   42 #include <sys/buf.h>
   43 #include <sys/pool.h>
   44 #include <sys/lock.h>
   45 #include <sys/mount.h>
   46 #include <sys/vnode.h>
   47 #include <sys/dirent.h>
   48 #include <sys/queue.h>
   49 #include <sys/unistd.h>
   50 #include <sys/endian.h>
   51 
   52 #include <miscfs/specfs/specdev.h>
   53 
   54 #include <isofs/udf/ecma167-udf.h>
   55 #include <isofs/udf/udf.h>
   56 #include <isofs/udf/udf_extern.h>
   57 
   58 int udf_bmap_internal(struct unode *, off_t, daddr64_t *, uint32_t *);
   59 
   60 int (**udf_vnodeop_p)(void *);
   61 struct vnodeopv_entry_desc udf_vnodeop_entries[] = {
   62         { &vop_default_desc, vn_default_error },
   63         { &vop_access_desc, udf_access },               /* access */
   64         { &vop_bmap_desc, udf_bmap },                   /* bmap */
   65         { &vop_lookup_desc, udf_lookup },               /* lookup */
   66         { &vop_getattr_desc, udf_getattr },             /* getattr */
   67         { &vop_open_desc, udf_open },                   /* open */
   68         { &vop_close_desc, udf_close },                 /* close */
   69         { &vop_ioctl_desc, udf_ioctl },                 /* ioctl */
   70         { &vop_read_desc, udf_read },                   /* read */
   71         { &vop_readdir_desc, udf_readdir },             /* readdir */
   72         { &vop_readlink_desc, udf_readlink },           /* readlink */
   73         { &vop_inactive_desc, udf_inactive },           /* inactive */
   74         { &vop_reclaim_desc, udf_reclaim },             /* reclaim */
   75         { &vop_strategy_desc, udf_strategy },           /* strategy */
   76         { &vop_lock_desc, udf_lock },                   /* lock */
   77         { &vop_unlock_desc, udf_unlock },               /* unlock */
   78         { &vop_islocked_desc, udf_islocked },           /* islocked */
   79         { &vop_print_desc, udf_print },                 /* print */
   80         { NULL, NULL }
   81 };
   82 struct vnodeopv_desc udf_vnodeop_opv_desc =
   83         { &udf_vnodeop_p, udf_vnodeop_entries };
   84 
   85 #define UDF_INVALID_BMAP        -1
   86 
   87 /* Look up a unode based on the ino_t passed in and return its vnode */
   88 int
   89 udf_hashlookup(struct umount *ump, ino_t id, int flags, struct vnode **vpp)
   90 {
   91         struct unode *up;
   92         struct udf_hash_lh *lh;
   93         struct proc *p = curproc;
   94         int error;
   95 
   96         *vpp = NULL;
   97 
   98 loop:
   99         mtx_enter(&ump->um_hashmtx);
  100         lh = &ump->um_hashtbl[id & ump->um_hashsz];
  101         if (lh == NULL) {
  102                 mtx_leave(&ump->um_hashmtx);
  103                 return (ENOENT);
  104         }
  105 
  106         LIST_FOREACH(up, lh, u_le) {
  107                 if (up->u_ino == id) {
  108                         mtx_leave(&ump->um_hashmtx);
  109                         error = vget(up->u_vnode, flags, p);
  110                         if (error == ENOENT)
  111                                 goto loop;
  112                         if (error)
  113                                 return (error);
  114                         *vpp = up->u_vnode;
  115                         return (0);
  116                 }
  117         }
  118 
  119         mtx_leave(&ump->um_hashmtx);
  120 
  121         return (0);
  122 }
  123 
  124 int
  125 udf_hashins(struct unode *up)
  126 {
  127         struct umount *ump;
  128         struct udf_hash_lh *lh;
  129         struct proc *p = curproc;
  130 
  131         ump = up->u_ump;
  132 
  133         vn_lock(up->u_vnode, LK_EXCLUSIVE | LK_RETRY, p);
  134         mtx_enter(&ump->um_hashmtx);
  135         lh = &ump->um_hashtbl[up->u_ino & ump->um_hashsz];
  136         if (lh == NULL)
  137                 LIST_INIT(lh);
  138         LIST_INSERT_HEAD(lh, up, u_le);
  139         mtx_leave(&ump->um_hashmtx);
  140 
  141         return (0);
  142 }
  143 
  144 int
  145 udf_hashrem(struct unode *up)
  146 {
  147         struct umount *ump;
  148         struct udf_hash_lh *lh;
  149 
  150         ump = up->u_ump;
  151 
  152         mtx_enter(&ump->um_hashmtx);
  153         lh = &ump->um_hashtbl[up->u_ino & ump->um_hashsz];
  154         if (lh == NULL)
  155                 panic("hash entry is NULL, up->u_ino = %d", up->u_ino);
  156         LIST_REMOVE(up, u_le);
  157         mtx_leave(&ump->um_hashmtx);
  158 
  159         return (0);
  160 }
  161 
  162 int
  163 udf_allocv(struct mount *mp, struct vnode **vpp, struct proc *p)
  164 {
  165         int error;
  166         struct vnode *vp;
  167 
  168         error = getnewvnode(VT_UDF, mp, udf_vnodeop_p, &vp);
  169         if (error) {
  170                 printf("udf_allocv: failed to allocate new vnode\n");
  171                 return (error);
  172         }
  173 
  174         *vpp = vp;
  175         return (0);
  176 }
  177 
  178 /* Convert file entry permission (5 bits per owner/group/user) to a mode_t */
  179 static mode_t
  180 udf_permtomode(struct unode *up)
  181 {
  182         uint32_t perm;
  183         uint16_t flags;
  184         mode_t mode;
  185 
  186         perm = letoh32(up->u_fentry->perm);
  187         flags = letoh16(up->u_fentry->icbtag.flags);
  188 
  189         mode = perm & UDF_FENTRY_PERM_USER_MASK;
  190         mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2);
  191         mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
  192         mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4);
  193         mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6);
  194         mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8);
  195 
  196         return (mode);
  197 }
  198 
  199 int
  200 udf_access(void *v)
  201 {
  202         struct vop_access_args *ap = v;
  203         struct vnode *vp;
  204         struct unode *up;
  205         mode_t a_mode, mode;
  206 
  207         vp = ap->a_vp;
  208         up = VTOU(vp);
  209         a_mode = ap->a_mode;
  210 
  211         if (a_mode & VWRITE) {
  212                 switch (vp->v_type) {
  213                 case VDIR:
  214                 case VLNK:
  215                 case VREG:
  216                         return (EROFS);
  217                         /* NOTREACHED */
  218                 default:
  219                         break;
  220                 }
  221         }
  222 
  223         mode = udf_permtomode(up);
  224 
  225         return (vaccess(mode, up->u_fentry->uid, up->u_fentry->gid, a_mode,
  226             ap->a_cred));
  227 }
  228 
  229 static int mon_lens[2][12] = {
  230         {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  231         {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
  232 };
  233 
  234 static int
  235 udf_isaleapyear(int year)
  236 {
  237         int i;
  238 
  239         i = (year % 4) ? 0 : 1;
  240         i &= (year % 100) ? 1 : 0;
  241         i |= (year % 400) ? 0 : 1;
  242 
  243         return (i);
  244 }
  245 
  246 /*
  247  * This is just a rough hack.  Daylight savings isn't calculated and tv_nsec
  248  * is ignored.
  249  * Timezone calculation compliments of Julian Elischer <julian@elischer.org>.
  250  */
  251 static void
  252 udf_timetotimespec(struct timestamp *time, struct timespec *t)
  253 {
  254         int i, lpyear, daysinyear, year;
  255         union {
  256                 uint16_t        u_tz_offset;
  257                 int16_t         s_tz_offset;
  258         } tz;
  259 
  260         t->tv_nsec = 0;
  261 
  262         /* DirectCD seems to like using bogus year values */
  263         year = letoh16(time->year);
  264         if (year < 1970) {
  265                 t->tv_sec = 0;
  266                 return;
  267         }
  268 
  269         /* Calculate the time and day */
  270         t->tv_sec = time->second;
  271         t->tv_sec += time->minute * 60;
  272         t->tv_sec += time->hour * 3600;
  273         t->tv_sec += time->day * 3600 * 24;
  274 
  275         /* Calculate the month */
  276         lpyear = udf_isaleapyear(year);
  277         for (i = 1; i < time->month; i++)
  278                 t->tv_sec += mon_lens[lpyear][i] * 3600 * 24;
  279 
  280         /* Speed up the calculation */
  281         if (year > 1979)
  282                 t->tv_sec += 315532800;
  283         if (year > 1989)
  284                 t->tv_sec += 315619200;
  285         if (year > 1999)
  286                 t->tv_sec += 315532800;
  287         for (i = 2000; i < year; i++) {
  288                 daysinyear = udf_isaleapyear(i) + 365 ;
  289                 t->tv_sec += daysinyear * 3600 * 24;
  290         }
  291 
  292         /*
  293          * Calculate the time zone.  The timezone is 12 bit signed 2's
  294          * compliment, so we gotta do some extra magic to handle it right.
  295          */
  296         tz.u_tz_offset = letoh16(time->type_tz);
  297         tz.u_tz_offset &= 0x0fff;
  298         if (tz.u_tz_offset & 0x0800)
  299                 tz.u_tz_offset |= 0xf000;       /* extend the sign to 16 bits */
  300         if ((time->type_tz & 0x1000) && (tz.s_tz_offset != -2047))
  301                 t->tv_sec -= tz.s_tz_offset * 60;
  302 
  303         return;
  304 }
  305 
  306 int
  307 udf_getattr(void *v)
  308 {
  309         struct vop_getattr_args *ap = v;
  310         struct vnode *vp;
  311         struct unode *up;
  312         struct vattr *vap;
  313         struct file_entry *fentry;
  314         struct timespec ts;
  315 
  316         ts.tv_sec = 0;
  317 
  318         vp = ap->a_vp;
  319         vap = ap->a_vap;
  320         up = VTOU(vp);
  321         fentry = up->u_fentry;
  322 
  323         vap->va_fsid = up->u_dev;
  324         vap->va_fileid = up->u_ino;
  325         vap->va_mode = udf_permtomode(up);
  326         vap->va_nlink = letoh16(fentry->link_cnt);
  327         /*
  328          * The spec says that -1 is valid for uid/gid and indicates an
  329          * invalid uid/gid.  How should this be represented?
  330          */
  331         vap->va_uid = (letoh32(fentry->uid) == -1) ? 0 : letoh32(fentry->uid);
  332         vap->va_gid = (letoh32(fentry->gid) == -1) ? 0 : letoh32(fentry->gid);
  333         udf_timetotimespec(&fentry->atime, &vap->va_atime);
  334         udf_timetotimespec(&fentry->mtime, &vap->va_mtime);
  335         vap->va_ctime = vap->va_mtime; /* Stored as an Extended Attribute */
  336         vap->va_rdev = 0;
  337         if (vp->v_type & VDIR) {
  338                 vap->va_nlink++; /* Count a reference to ourselves */
  339                 /*
  340                  * Directories that are recorded within their ICB will show
  341                  * as having 0 blocks recorded.  Since tradition dictates
  342                  * that directories consume at least one logical block,
  343                  * make it appear so.
  344                  */
  345                 if (fentry->logblks_rec != 0) {
  346                         vap->va_size =
  347                             letoh64(fentry->logblks_rec) * up->u_ump->um_bsize;
  348                 } else {
  349                         vap->va_size = up->u_ump->um_bsize;
  350                 }
  351         } else {
  352                 vap->va_size = letoh64(fentry->inf_len);
  353         }
  354         vap->va_flags = 0;
  355         vap->va_gen = 1;
  356         vap->va_blocksize = up->u_ump->um_bsize;
  357         vap->va_bytes = letoh64(fentry->inf_len);
  358         vap->va_type = vp->v_type;
  359         vap->va_filerev = 0;
  360 
  361         return (0);
  362 }
  363 
  364 int
  365 udf_open(void *v)
  366 {
  367         return (0); /* Nothing to be done at this point */
  368 }
  369 
  370 int
  371 udf_close(void *v)
  372 {
  373         return (0); /* Nothing to be done at this point */
  374 }
  375 
  376 /*
  377  * File specific ioctls.
  378  */
  379 int
  380 udf_ioctl(void *v)
  381 {
  382         return (ENOTTY);
  383 }
  384 
  385 /*
  386  * I'm not sure that this has much value in a read-only filesystem, but
  387  * cd9660 has it too.
  388  */
  389 #if 0
  390 static int
  391 udf_pathconf(struct vop_pathconf_args *a)
  392 {
  393 
  394         switch (ap->a_name) {
  395         case _PC_LINK_MAX:
  396                 *ap->a_retval = 65535;
  397                 return (0);
  398         case _PC_NAME_MAX:
  399                 *ap->a_retval = NAME_MAX;
  400                 return (0);
  401         case _PC_PATH_MAX:
  402                 *ap->a_retval = PATH_MAX;
  403                 return (0);
  404         case _PC_NO_TRUNC:
  405                 *ap->a_retval = 1;
  406                 return (0);
  407         default:
  408                 return (EINVAL);
  409         }
  410 }
  411 #endif
  412 
  413 int
  414 udf_read(void *v)
  415 {
  416         struct vop_read_args *ap = v;
  417         struct vnode *vp = ap->a_vp;
  418         struct uio *uio = ap->a_uio;
  419         struct unode *up = VTOU(vp);
  420         struct buf *bp;
  421         uint8_t *data;
  422         off_t fsize, offset;
  423         int error = 0;
  424         int size;
  425 
  426         if (uio->uio_offset < 0)
  427                 return (EINVAL);
  428 
  429         fsize = letoh64(up->u_fentry->inf_len);
  430 
  431         while (uio->uio_offset < fsize && uio->uio_resid > 0) {
  432                 offset = uio->uio_offset;
  433                 if (uio->uio_resid + offset <= fsize)
  434                         size = uio->uio_resid;
  435                 else
  436                         size = fsize - offset;
  437                 error = udf_readatoffset(up, &size, offset, &bp, &data);
  438                 if (error == 0)
  439                         error = uiomove(data, size, uio);
  440                 if (bp != NULL)
  441                         brelse(bp);
  442                 if (error)
  443                         break;
  444         };
  445 
  446         return (error);
  447 }
  448 
  449 /*
  450  * Translate the name from a CS0 dstring to a 16-bit Unicode String.
  451  * Hooks need to be placed in here to translate from Unicode to the encoding
  452  * that the kernel/user expects.  Return the length of the translated string.
  453  */
  454 int
  455 udf_transname(char *cs0string, char *destname, int len, struct umount *ump)
  456 {
  457         unicode_t *transname;
  458         int i, unilen = 0, destlen;
  459 
  460         if (len > MAXNAMLEN) {
  461 #ifdef DIAGNOSTIC
  462                 printf("udf_transname(): name too long\n");
  463 #endif
  464                 return (0);
  465         }
  466 
  467         /* allocate a buffer big enough to hold an 8->16 bit expansion */
  468         transname = pool_get(&udf_trans_pool, PR_WAITOK);
  469 
  470         if ((unilen = udf_rawnametounicode(len, cs0string, transname)) == -1) {
  471 #ifdef DIAGNOSTIC
  472                 printf("udf_transname(): Unicode translation failed\n");
  473 #endif
  474                 pool_put(&udf_trans_pool, transname);
  475                 return (0);
  476         }
  477 
  478         /* Pack it back to 8-bit Unicode. */
  479         for (i = 0; i < unilen ; i++)
  480                 if (transname[i] & 0xff00)
  481                         destname[i] = '?';      /* Fudge the 16bit chars */
  482                 else
  483                         destname[i] = transname[i] & 0xff;
  484 
  485         pool_put(&udf_trans_pool, transname);
  486 
  487         /* Don't forget to terminate the string. */
  488         destname[unilen] = 0;
  489         destlen = unilen;
  490 
  491         return (destlen);
  492 }
  493 
  494 /*
  495  * Compare a CS0 dstring with a name passed in from the VFS layer.  Return
  496  * 0 on a successful match, nonzero otherwise.  Unicode work may need to be
  497  * done here also.
  498  */
  499 static int
  500 udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct umount *ump)
  501 {
  502         char *transname;
  503         int error = 0;
  504 
  505         /* This is overkill, but not worth creating a new pool */
  506         transname = pool_get(&udf_trans_pool, PR_WAITOK);
  507 
  508         cs0len = udf_transname(cs0string, transname, cs0len, ump);
  509 
  510         /* Easy check.  If they aren't the same length, they aren't equal */
  511         if ((cs0len == 0) || (cs0len != cmplen))
  512                 error = -1;
  513         else
  514                 error = bcmp(transname, cmpname, cmplen);
  515 
  516         pool_put(&udf_trans_pool, transname);
  517 
  518         return (error);
  519 }
  520 
  521 struct udf_uiodir {
  522         struct dirent *dirent;
  523         u_long *cookies;
  524         int ncookies;
  525         int acookies;
  526         int eofflag;
  527 };
  528 
  529 static int
  530 udf_uiodir(struct udf_uiodir *uiodir, int de_size, struct uio *uio, long cookie)
  531 {
  532         if (uiodir->cookies != NULL) {
  533                 if (++uiodir->acookies > uiodir->ncookies) {
  534                         uiodir->eofflag = 0;
  535                         return (-1);
  536                 }
  537                 *uiodir->cookies++ = cookie;
  538         }
  539 
  540         if (uio->uio_resid < de_size) {
  541                 uiodir->eofflag = 0;
  542                 return (-1);
  543         }
  544 
  545         return (uiomove(uiodir->dirent, de_size, uio));
  546 }
  547 
  548 static struct udf_dirstream *
  549 udf_opendir(struct unode *up, int offset, int fsize, struct umount *ump)
  550 {
  551         struct udf_dirstream *ds;
  552 
  553         ds = pool_get(&udf_ds_pool, PR_WAITOK);
  554         bzero(ds, sizeof(struct udf_dirstream));
  555 
  556         ds->node = up;
  557         ds->offset = offset;
  558         ds->ump = ump;
  559         ds->fsize = fsize;
  560 
  561         return (ds);
  562 }
  563 
  564 static struct fileid_desc *
  565 udf_getfid(struct udf_dirstream *ds)
  566 {
  567         struct fileid_desc *fid;
  568         int error, frag_size = 0, total_fid_size;
  569 
  570         /* End of directory? */
  571         if (ds->offset + ds->off >= ds->fsize) {
  572                 ds->error = 0;
  573                 return (NULL);
  574         }
  575 
  576         /* Grab the first extent of the directory */
  577         if (ds->off == 0) {
  578                 ds->size = 0;
  579                 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
  580                     &ds->bp, &ds->data);
  581                 if (error) {
  582                         ds->error = error;
  583                         if (ds->bp != NULL)
  584                                 brelse(ds->bp);
  585                         return (NULL);
  586                 }
  587         }
  588 
  589         /*
  590          * Clean up from a previous fragmented FID.
  591          * Is this the right place for this?
  592          */
  593         if (ds->fid_fragment && ds->buf != NULL) {
  594                 ds->fid_fragment = 0;
  595                 free(ds->buf, M_UDFFID);
  596         }
  597 
  598         fid = (struct fileid_desc*)&ds->data[ds->off];
  599 
  600         /*
  601          * Check to see if the fid is fragmented. The first test
  602          * ensures that we don't wander off the end of the buffer
  603          * looking for the l_iu and l_fi fields.
  604          */
  605         if (ds->off + UDF_FID_SIZE > ds->size ||
  606             ds->off + letoh16(fid->l_iu) + fid->l_fi + UDF_FID_SIZE > ds->size){
  607 
  608                 /* Copy what we have of the fid into a buffer */
  609                 frag_size = ds->size - ds->off;
  610                 if (frag_size >= ds->ump->um_bsize) {
  611                         printf("udf: invalid FID fragment\n");
  612                         ds->error = EINVAL;
  613                         return (NULL);
  614                 }
  615 
  616                 /*
  617                  * File ID descriptors can only be at most one
  618                  * logical sector in size.
  619                  */
  620                 ds->buf = malloc(ds->ump->um_bsize, M_UDFFID, M_WAITOK);
  621                 bzero(ds->buf, ds->ump->um_bsize);
  622                 bcopy(fid, ds->buf, frag_size);
  623 
  624                 /* Reduce all of the casting magic */
  625                 fid = (struct fileid_desc*)ds->buf;
  626 
  627                 if (ds->bp != NULL)
  628                         brelse(ds->bp);
  629 
  630                 /* Fetch the next allocation */
  631                 ds->offset += ds->size;
  632                 ds->size = 0;
  633                 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
  634                     &ds->bp, &ds->data);
  635                 if (error) {
  636                         ds->error = error;
  637                         return (NULL);
  638                 }
  639 
  640                 /*
  641                  * If the fragment was so small that we didn't get
  642                  * the l_iu and l_fi fields, copy those in.
  643                  */
  644                 if (frag_size < UDF_FID_SIZE)
  645                         bcopy(ds->data, &ds->buf[frag_size],
  646                             UDF_FID_SIZE - frag_size);
  647 
  648                 /*
  649                  * Now that we have enough of the fid to work with,
  650                  * copy in the rest of the fid from the new
  651                  * allocation.
  652                  */
  653                 total_fid_size = UDF_FID_SIZE + letoh16(fid->l_iu) + fid->l_fi;
  654                 if (total_fid_size > ds->ump->um_bsize) {
  655                         printf("udf: invalid FID\n");
  656                         ds->error = EIO;
  657                         return (NULL);
  658                 }
  659                 bcopy(ds->data, &ds->buf[frag_size],
  660                     total_fid_size - frag_size);
  661 
  662                 ds->fid_fragment = 1;
  663         } else {
  664                 total_fid_size = letoh16(fid->l_iu) + fid->l_fi + UDF_FID_SIZE;
  665         }
  666 
  667         /*
  668          * Update the offset. Align on a 4 byte boundary because the
  669          * UDF spec says so.
  670          */
  671         ds->this_off = ds->off;
  672         if (!ds->fid_fragment) {
  673                 ds->off += (total_fid_size + 3) & ~0x03;
  674         } else {
  675                 ds->off = (total_fid_size - frag_size + 3) & ~0x03;
  676         }
  677 
  678         return (fid);
  679 }
  680 
  681 static void
  682 udf_closedir(struct udf_dirstream *ds)
  683 {
  684 
  685         if (ds->bp != NULL)
  686                 brelse(ds->bp);
  687 
  688         if (ds->fid_fragment && ds->buf != NULL)
  689                 free(ds->buf, M_UDFFID);
  690 
  691         pool_put(&udf_ds_pool, ds);
  692 }
  693 
  694 int
  695 udf_readdir(void *v)
  696 {
  697         struct vop_readdir_args *ap = v;
  698         struct vnode *vp;
  699         struct uio *uio;
  700         struct dirent dir;
  701         struct unode *up;
  702         struct umount *ump;
  703         struct fileid_desc *fid;
  704         struct udf_uiodir uiodir;
  705         struct udf_dirstream *ds;
  706         u_long *cookies = NULL;
  707         int ncookies;
  708         int error = 0;
  709 
  710 #define GENERIC_DIRSIZ(dp) \
  711     ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
  712 
  713         vp = ap->a_vp;
  714         uio = ap->a_uio;
  715         up = VTOU(vp);
  716         ump = up->u_ump;
  717         uiodir.eofflag = 1;
  718 
  719         if (ap->a_ncookies != NULL) {
  720                 /*
  721                  * Guess how many entries are needed.  If we run out, this
  722                  * function will be called again and thing will pick up were
  723                  * it left off.
  724                  */
  725                 ncookies = uio->uio_resid / 8;
  726                 MALLOC(cookies, u_long *, sizeof(u_long) * ncookies,
  727                     M_TEMP, M_WAITOK);
  728                 uiodir.ncookies = ncookies;
  729                 uiodir.cookies = cookies;
  730                 uiodir.acookies = 0;
  731         } else {
  732                 uiodir.cookies = NULL;
  733         }
  734 
  735         /*
  736          * Iterate through the file id descriptors.  Give the parent dir
  737          * entry special attention.
  738          */
  739         ds = udf_opendir(up, uio->uio_offset,
  740             letoh64(up->u_fentry->inf_len), up->u_ump);
  741 
  742         while ((fid = udf_getfid(ds)) != NULL) {
  743 
  744                 /* Should we return an error on a bad fid? */
  745                 if (udf_checktag(&fid->tag, TAGID_FID)) {
  746                         printf("Invalid FID tag\n");
  747                         error = EIO;
  748                         break;
  749                 }
  750 
  751                 /* Is this a deleted file? */
  752                 if (fid->file_char & UDF_FILE_CHAR_DEL)
  753                         continue;
  754 
  755                 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
  756                         /* Do up the '.' and '..' entries.  Dummy values are
  757                          * used for the cookies since the offset here is
  758                          * usually zero, and NFS doesn't like that value
  759                          */
  760                         dir.d_fileno = up->u_ino;
  761                         dir.d_type = DT_DIR;
  762                         dir.d_name[0] = '.';
  763                         dir.d_name[1] = '\0';
  764                         dir.d_namlen = 1;
  765                         dir.d_reclen = GENERIC_DIRSIZ(&dir);
  766                         uiodir.dirent = &dir;
  767                         error = udf_uiodir(&uiodir, dir.d_reclen, uio, 1);
  768                         if (error)
  769                                 break;
  770 
  771                         dir.d_fileno = udf_getid(&fid->icb);
  772                         dir.d_type = DT_DIR;
  773                         dir.d_name[0] = '.';
  774                         dir.d_name[1] = '.';
  775                         dir.d_name[2] = '\0';
  776                         dir.d_namlen = 2;
  777                         dir.d_reclen = GENERIC_DIRSIZ(&dir);
  778                         uiodir.dirent = &dir;
  779                         error = udf_uiodir(&uiodir, dir.d_reclen, uio, 2);
  780                 } else {
  781                         dir.d_namlen = udf_transname(&fid->data[fid->l_iu],
  782                             &dir.d_name[0], fid->l_fi, ump);
  783                         dir.d_fileno = udf_getid(&fid->icb);
  784                         dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ?
  785                             DT_DIR : DT_UNKNOWN;
  786                         dir.d_reclen = GENERIC_DIRSIZ(&dir);
  787                         uiodir.dirent = &dir;
  788                         error = udf_uiodir(&uiodir, dir.d_reclen, uio,
  789                             ds->this_off);
  790                 }
  791                 if (error) {
  792                         printf("uiomove returned %d\n", error);
  793                         break;
  794                 }
  795 
  796         }
  797 
  798 #undef GENERIC_DIRSIZ
  799 
  800         /* tell the calling layer whether we need to be called again */
  801         *ap->a_eofflag = uiodir.eofflag;
  802         uio->uio_offset = ds->offset + ds->off;
  803 
  804         if (!error)
  805                 error = ds->error;
  806 
  807         udf_closedir(ds);
  808 
  809         if (ap->a_ncookies != NULL) {
  810                 if (error)
  811                         FREE(cookies, M_TEMP);
  812                 else {
  813                         *ap->a_ncookies = uiodir.acookies;
  814                         *ap->a_cookies = cookies;
  815                 }
  816         }
  817 
  818         return (error);
  819 }
  820 
  821 /* Are there any implementations out there that do soft-links? */
  822 int
  823 udf_readlink(void *v)
  824 {
  825         return (EOPNOTSUPP);
  826 }
  827 
  828 int
  829 udf_strategy(void *v)
  830 {
  831         struct vop_strategy_args *ap = v;
  832         struct buf *bp;
  833         struct vnode *vp;
  834         struct unode *up;
  835         int maxsize, s, error;
  836 
  837         bp = ap->a_bp;
  838         vp = bp->b_vp;
  839         up = VTOU(vp);
  840 
  841         /* cd9660 has this test reversed, but it seems more logical this way */
  842         if (bp->b_blkno != bp->b_lblkno) {
  843                 /*
  844                  * Files that are embedded in the fentry don't translate well
  845                  * to a block number.  Reject.
  846                  */
  847                 if (udf_bmap_internal(up, bp->b_lblkno * up->u_ump->um_bsize,
  848                     &bp->b_lblkno, &maxsize)) {
  849                         clrbuf(bp);
  850                         bp->b_blkno = -1;
  851                 }
  852         } else {
  853                 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL);
  854                 if (error) {
  855                         bp->b_error = error;
  856                         bp->b_flags |= B_ERROR;
  857                         s = splbio();
  858                         biodone(bp);
  859                         splx(s);
  860                         return (error);
  861                 }
  862 
  863                 if ((long)bp->b_blkno == -1)
  864                         clrbuf(bp);
  865         }
  866 
  867         if ((long)bp->b_blkno == -1) {
  868                 s = splbio();
  869                 biodone(bp);
  870                 splx(s);
  871         } else {
  872                 bp->b_dev = vp->v_rdev;
  873                 VOCALL(up->u_devvp->v_op, VOFFSET(vop_strategy), ap);
  874         }
  875 
  876         return (0);
  877 }
  878 
  879 int
  880 udf_lock(void *v)
  881 {
  882         struct vop_lock_args *ap = v;
  883 
  884         struct vnode *vp = ap->a_vp;
  885 
  886         return (lockmgr(&VTOU(vp)->u_lock, ap->a_flags, NULL));
  887 }
  888 
  889 int
  890 udf_unlock(void *v)
  891 {
  892         struct vop_unlock_args *ap = v;
  893 
  894         struct vnode *vp = ap->a_vp;
  895 
  896         return (lockmgr(&VTOU(vp)->u_lock, ap->a_flags | LK_RELEASE, NULL));
  897 }
  898 
  899 int
  900 udf_islocked(void *v)
  901 {
  902         struct vop_islocked_args *ap = v;
  903 
  904         return (lockstatus(&VTOU(ap->a_vp)->u_lock));
  905 }
  906 
  907 int
  908 udf_print(void *v)
  909 {
  910         struct vop_print_args *ap = v;
  911         struct vnode *vp = ap->a_vp;
  912         struct unode *up = VTOU(vp);
  913 
  914         /*
  915          * Complete the information given by vprint().
  916          */
  917         printf("tag VT_UDF, hash id %u\n", up->u_ino);
  918 #ifdef DIAGNOSTIC
  919         lockmgr_printinfo(&up->u_lock);
  920         printf("\n");
  921 #endif
  922         return (0);
  923 }
  924 
  925 int
  926 udf_bmap(void *v)
  927 {
  928         struct vop_bmap_args *ap = v;
  929         struct unode *up;
  930         uint32_t max_size;
  931         daddr64_t lsector;
  932         int error;
  933 
  934         up = VTOU(ap->a_vp);
  935 
  936         if (ap->a_vpp != NULL)
  937                 *ap->a_vpp = up->u_devvp;
  938         if (ap->a_bnp == NULL)
  939                 return (0);
  940 
  941         error = udf_bmap_internal(up, ap->a_bn * up->u_ump->um_bsize,
  942             &lsector, &max_size);
  943         if (error)
  944                 return (error);
  945 
  946         /* Translate logical to physical sector number */
  947         *ap->a_bnp = lsector << (up->u_ump->um_bshift - DEV_BSHIFT);
  948 
  949         /* Punt on read-ahead for now */
  950         if (ap->a_runp)
  951                 *ap->a_runp = 0;
  952 
  953         return (0);
  954 }
  955 
  956 /*
  957  * The all powerful VOP_LOOKUP().
  958  */
  959 int
  960 udf_lookup(void *v)
  961 {
  962         struct vop_lookup_args *ap = v;
  963         struct vnode *dvp;
  964         struct vnode *tdp = NULL;
  965         struct vnode **vpp = ap->a_vpp;
  966         struct unode *up;
  967         struct umount *ump;
  968         struct fileid_desc *fid = NULL;
  969         struct udf_dirstream *ds;
  970         struct proc *p;
  971         u_long nameiop;
  972         u_long flags;
  973         char *nameptr;
  974         long namelen;
  975         ino_t id = 0;
  976         int offset, error = 0;
  977         int numdirpasses, fsize;
  978 
  979         extern struct nchstats nchstats;
  980 
  981         dvp = ap->a_dvp;
  982         up = VTOU(dvp);
  983         ump = up->u_ump;
  984         nameiop = ap->a_cnp->cn_nameiop;
  985         flags = ap->a_cnp->cn_flags;
  986         nameptr = ap->a_cnp->cn_nameptr;
  987         namelen = ap->a_cnp->cn_namelen;
  988         fsize = letoh64(up->u_fentry->inf_len);
  989         p = ap->a_cnp->cn_proc;
  990         *vpp = NULL;
  991 
  992         /*
  993          * Make sure the process can scan the requested directory.
  994          */
  995         error = VOP_ACCESS(dvp, VEXEC, ap->a_cnp->cn_cred, p);
  996         if (error)
  997                 return (error);
  998 
  999         /*
 1000          * Check if the (directory, name) tuple has been already cached.
 1001          */
 1002         error = cache_lookup(dvp, vpp, ap->a_cnp);
 1003         if (error >= 0)
 1004                 return (error);
 1005         else
 1006                 error = 0;
 1007 
 1008         /*
 1009          * If dvp is what's being looked up, then return it.
 1010          */
 1011         if (ap->a_cnp->cn_namelen == 1 && ap->a_cnp->cn_nameptr[0] == '.') {
 1012                 VREF(dvp);
 1013                 *vpp = dvp;
 1014                 return (0);
 1015         }
 1016 
 1017         /*
 1018          * If this is a LOOKUP and we've already partially searched through
 1019          * the directory, pick up where we left off and flag that the
 1020          * directory may need to be searched twice.  For a full description,
 1021          * see /sys/isofs/cd9660/cd9660_lookup.c:cd9660_lookup()
 1022          */
 1023         if (nameiop != LOOKUP || up->u_diroff == 0 || up->u_diroff > fsize) {
 1024                 offset = 0;
 1025                 numdirpasses = 1;
 1026         } else {
 1027                 offset = up->u_diroff;
 1028                 numdirpasses = 2;
 1029                 nchstats.ncs_2passes++;
 1030         }
 1031 
 1032 lookloop:
 1033         ds = udf_opendir(up, offset, fsize, ump);
 1034 
 1035         while ((fid = udf_getfid(ds)) != NULL) {
 1036                 /* Check for a valid FID tag. */
 1037                 if (udf_checktag(&fid->tag, TAGID_FID)) {
 1038                         printf("udf_lookup: Invalid tag\n");
 1039                         error = EIO;
 1040                         break;
 1041                 }
 1042 
 1043                 /* Is this a deleted file? */
 1044                 if (fid->file_char & UDF_FILE_CHAR_DEL)
 1045                         continue;
 1046 
 1047                 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
 1048                         if (flags & ISDOTDOT) {
 1049                                 id = udf_getid(&fid->icb);
 1050                                 break;
 1051                         }
 1052                 } else {
 1053                         if (!(udf_cmpname(&fid->data[fid->l_iu],
 1054                             nameptr, fid->l_fi, namelen, ump))) {
 1055                                 id = udf_getid(&fid->icb);
 1056                                 break;
 1057                         }
 1058                 }
 1059         }
 1060 
 1061         if (!error)
 1062                 error = ds->error;
 1063 
 1064         if (error) {
 1065                 udf_closedir(ds);
 1066                 return (error);
 1067         }
 1068 
 1069         /* Did we have a match? */
 1070         if (id) {
 1071                 error = udf_vget(ump->um_mountp, id, &tdp);
 1072                 if (!error) {
 1073                         /*
 1074                          * Remember where this entry was if it's the final
 1075                          * component.
 1076                          */
 1077                         if ((flags & ISLASTCN) && nameiop == LOOKUP)
 1078                                 up->u_diroff = ds->offset + ds->off;
 1079                         if (numdirpasses == 2)
 1080                                 nchstats.ncs_pass2++;
 1081                         if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) {
 1082                                 ap->a_cnp->cn_flags |= PDIRUNLOCK;
 1083                                 VOP_UNLOCK(dvp, 0, p);
 1084                         }
 1085 
 1086                         *vpp = tdp;
 1087                 }
 1088         } else {
 1089                 /* Name wasn't found on this pass.  Do another pass? */
 1090                 if (numdirpasses == 2) {
 1091                         numdirpasses--;
 1092                         offset = 0;
 1093                         udf_closedir(ds);
 1094                         goto lookloop;
 1095                 }
 1096 
 1097                 if ((flags & ISLASTCN) &&
 1098                     (nameiop == CREATE || nameiop == RENAME)) {
 1099                         error = EROFS;
 1100                 } else {
 1101                         error = ENOENT;
 1102                 }
 1103         }
 1104 
 1105         /*
 1106          * Cache the result of this lookup.
 1107          */
 1108         if (flags & MAKEENTRY)
 1109                 cache_enter(dvp, *vpp, ap->a_cnp);
 1110 
 1111         udf_closedir(ds);
 1112 
 1113         return (error);
 1114 }
 1115 
 1116 int
 1117 udf_inactive(void *v)
 1118 {
 1119         struct vop_inactive_args *ap = v;
 1120         struct vnode *vp = ap->a_vp;
 1121         struct proc *p = ap->a_p;
 1122 
 1123         /*
 1124          * No need to sync anything, so just unlock the vnode and return.
 1125          */
 1126         VOP_UNLOCK(vp, 0, p);
 1127 
 1128         return (0);
 1129 }
 1130 
 1131 int
 1132 udf_reclaim(void *v)
 1133 {
 1134         struct vop_reclaim_args *ap = v;
 1135         struct vnode *vp;
 1136         struct unode *up;
 1137 
 1138         vp = ap->a_vp;
 1139         up = VTOU(vp);
 1140 
 1141         if (up != NULL) {
 1142                 udf_hashrem(up);
 1143                 if (up->u_devvp) {
 1144                         vrele(up->u_devvp);
 1145                         up->u_devvp = 0;
 1146                 }
 1147 
 1148                 if (up->u_fentry != NULL)
 1149                         free(up->u_fentry, M_UDFFENTRY);
 1150 
 1151                 pool_put(&unode_pool, up);
 1152                 vp->v_data = NULL;
 1153         }
 1154         
 1155         return (0);
 1156 }
 1157 
 1158 /*
 1159  * Read the block and then set the data pointer to correspond with the
 1160  * offset passed in.  Only read in at most 'size' bytes, and then set 'size'
 1161  * to the number of bytes pointed to.  If 'size' is zero, try to read in a
 1162  * whole extent.
 1163  *
 1164  * Note that *bp may be assigned error or not.
 1165  *
 1166  */
 1167 int
 1168 udf_readatoffset(struct unode *up, int *size, off_t offset,
 1169     struct buf **bp, uint8_t **data)
 1170 {
 1171         struct umount *ump;
 1172         struct file_entry *fentry = NULL;
 1173         struct buf *bp1;
 1174         uint32_t max_size;
 1175         daddr64_t sector;
 1176         int error;
 1177 
 1178         ump = up->u_ump;
 1179 
 1180         *bp = NULL;
 1181         error = udf_bmap_internal(up, offset, &sector, &max_size);
 1182         if (error == UDF_INVALID_BMAP) {
 1183                 /*
 1184                  * This error means that the file *data* is stored in the
 1185                  * allocation descriptor field of the file entry.
 1186                  */
 1187                 fentry = up->u_fentry;
 1188                 *data = &fentry->data[letoh32(fentry->l_ea)];
 1189                 *size = letoh32(fentry->l_ad);
 1190                 return (0);
 1191         } else if (error != 0) {
 1192                 return (error);
 1193         }
 1194 
 1195         /* Adjust the size so that it is within range */
 1196         if (*size == 0 || *size > max_size)
 1197                 *size = max_size;
 1198         *size = min(*size, MAXBSIZE);
 1199 
 1200         if ((error = udf_readlblks(ump, sector, *size, bp))) {
 1201                 printf("warning: udf_readlblks returned error %d\n", error);
 1202                 /* note: *bp may be non-NULL */
 1203                 return (error);
 1204         }
 1205 
 1206         bp1 = *bp;
 1207         *data = (uint8_t *)&bp1->b_data[offset % ump->um_bsize];
 1208         return (0);
 1209 }
 1210 
 1211 /*
 1212  * Translate a file offset into a logical block and then into a physical
 1213  * block.
 1214  */
 1215 int
 1216 udf_bmap_internal(struct unode *up, off_t offset, daddr64_t *sector,
 1217     uint32_t *max_size)
 1218 {
 1219         struct umount *ump;
 1220         struct file_entry *fentry;
 1221         void *icb;
 1222         struct icb_tag *tag;
 1223         uint32_t icblen = 0;
 1224         daddr64_t lsector;
 1225         int ad_offset, ad_num = 0;
 1226         int i, p_offset;
 1227 
 1228         ump = up->u_ump;
 1229         fentry = up->u_fentry;
 1230         tag = &fentry->icbtag;
 1231 
 1232         switch (letoh16(tag->strat_type)) {
 1233         case 4:
 1234                 break;
 1235 
 1236         case 4096:
 1237                 printf("Cannot deal with strategy4096 yet!\n");
 1238                 return (ENODEV);
 1239 
 1240         default:
 1241                 printf("Unknown strategy type %d\n", tag->strat_type);
 1242                 return (ENODEV);
 1243         }
 1244 
 1245         switch (letoh16(tag->flags) & 0x7) {
 1246         case 0:
 1247                 /*
 1248                  * The allocation descriptor field is filled with short_ad's.
 1249                  * If the offset is beyond the current extent, look for the
 1250                  * next extent.
 1251                  */
 1252                 do {
 1253                         offset -= icblen;
 1254                         ad_offset = sizeof(struct short_ad) * ad_num;
 1255                         if (ad_offset > letoh32(fentry->l_ad)) {
 1256                                 printf("File offset out of bounds\n");
 1257                                 return (EINVAL);
 1258                         }
 1259                         icb = GETICB(short_ad, fentry,
 1260                             letoh32(fentry->l_ea) + ad_offset);
 1261                         icblen = GETICBLEN(short_ad, icb);
 1262                         ad_num++;
 1263                 } while(offset >= icblen);
 1264 
 1265                 lsector = (offset  >> ump->um_bshift) +
 1266                     letoh32(((struct short_ad *)(icb))->pos);
 1267 
 1268                 *max_size = GETICBLEN(short_ad, icb);
 1269 
 1270                 break;
 1271         case 1:
 1272                 /*
 1273                  * The allocation descriptor field is filled with long_ad's
 1274                  * If the offset is beyond the current extent, look for the
 1275                  * next extent.
 1276                  */
 1277                 do {
 1278                         offset -= icblen;
 1279                         ad_offset = sizeof(struct long_ad) * ad_num;
 1280                         if (ad_offset > letoh32(fentry->l_ad)) {
 1281                                 printf("File offset out of bounds\n");
 1282                                 return (EINVAL);
 1283                         }
 1284                         icb = GETICB(long_ad, fentry,
 1285                             letoh32(fentry->l_ea) + ad_offset);
 1286                         icblen = GETICBLEN(long_ad, icb);
 1287                         ad_num++;
 1288                 } while(offset >= icblen);
 1289 
 1290                 lsector = (offset >> ump->um_bshift) +
 1291                     letoh32(((struct long_ad *)(icb))->loc.lb_num);
 1292 
 1293                 *max_size = GETICBLEN(long_ad, icb);
 1294 
 1295                 break;
 1296         case 3:
 1297                 /*
 1298                  * This type means that the file *data* is stored in the
 1299                  * allocation descriptor field of the file entry.
 1300                  */
 1301                 *max_size = 0;
 1302                 *sector = up->u_ino + ump->um_start;
 1303 
 1304                 return (UDF_INVALID_BMAP);
 1305         case 2:
 1306                 /* DirectCD does not use extended_ad's */
 1307         default:
 1308                 printf("Unsupported allocation descriptor %d\n",
 1309                        tag->flags & 0x7);
 1310                 return (ENODEV);
 1311         }
 1312 
 1313         *sector = lsector + ump->um_start;
 1314 
 1315         /*
 1316          * Check the sparing table.  Each entry represents the beginning of
 1317          * a packet.
 1318          */
 1319         if (ump->um_stbl != NULL) {
 1320                 for (i = 0; i< ump->um_stbl_len; i++) {
 1321                         p_offset =
 1322                             lsector - letoh32(ump->um_stbl->entries[i].org);
 1323                         if ((p_offset < ump->um_psecs) && (p_offset >= 0)) {
 1324                                 *sector =
 1325                                    letoh32(ump->um_stbl->entries[i].map) +
 1326                                     p_offset;
 1327                                 break;
 1328                         }
 1329                 }
 1330         }
 1331 
 1332         return (0);
 1333 }

/* [<][>][^][v][top][bottom][index][help] */