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/udf/udf_vnops.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) 2001, 2002 Scott Long <scottl@freebsd.org>
    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 
   29 /* udf_vnops.c */
   30 /* Take care of the vnode side of things */
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/namei.h>
   35 #include <sys/kernel.h>
   36 #include <sys/malloc.h>
   37 #include <sys/stat.h>
   38 #include <sys/bio.h>
   39 #include <sys/buf.h>
   40 #include <sys/iconv.h>
   41 #include <sys/mount.h>
   42 #include <sys/vnode.h>
   43 #include <sys/dirent.h>
   44 #include <sys/queue.h>
   45 #include <sys/unistd.h>
   46 #include <sys/endian.h>
   47 
   48 #include <vm/uma.h>
   49 
   50 #include <fs/udf/ecma167-udf.h>
   51 #include <fs/udf/osta.h>
   52 #include <fs/udf/udf.h>
   53 #include <fs/udf/udf_mount.h>
   54 
   55 extern struct iconv_functions *udf_iconv;
   56 
   57 static int udf_access(struct vop_access_args *);
   58 static int udf_getattr(struct vop_getattr_args *);
   59 static int udf_ioctl(struct vop_ioctl_args *);
   60 static int udf_pathconf(struct vop_pathconf_args *);
   61 static int udf_read(struct vop_read_args *);
   62 static int udf_readdir(struct vop_readdir_args *);
   63 static int udf_readlink(struct vop_readlink_args *ap);
   64 static int udf_strategy(struct vop_strategy_args *);
   65 static int udf_bmap(struct vop_bmap_args *);
   66 static int udf_lookup(struct vop_cachedlookup_args *);
   67 static int udf_reclaim(struct vop_reclaim_args *);
   68 static int udf_readatoffset(struct udf_node *, int *, int, struct buf **, uint8_t **);
   69 static int udf_bmap_internal(struct udf_node *, uint32_t, daddr_t *, uint32_t *);
   70 
   71 vop_t **udf_vnodeop_p;
   72 static struct vnodeopv_entry_desc udf_vnodeop_entries[] = {
   73         { &vop_default_desc,            (vop_t *) vop_defaultop },
   74         { &vop_access_desc,             (vop_t *) udf_access },
   75         { &vop_bmap_desc,               (vop_t *) udf_bmap },
   76         { &vop_cachedlookup_desc,       (vop_t *) udf_lookup },
   77         { &vop_getattr_desc,            (vop_t *) udf_getattr },
   78         { &vop_ioctl_desc,              (vop_t *) udf_ioctl },
   79         { &vop_lookup_desc,             (vop_t *) vfs_cache_lookup },
   80         { &vop_pathconf_desc,           (vop_t *) udf_pathconf },
   81         { &vop_read_desc,               (vop_t *) udf_read },
   82         { &vop_readdir_desc,            (vop_t *) udf_readdir },
   83         { &vop_readlink_desc,           (vop_t *) udf_readlink },
   84         { &vop_reclaim_desc,            (vop_t *) udf_reclaim },
   85         { &vop_strategy_desc,           (vop_t *) udf_strategy },
   86         { NULL, NULL }
   87 };
   88 static struct vnodeopv_desc udf_vnodeop_opv_desc =
   89         { &udf_vnodeop_p, udf_vnodeop_entries };
   90 VNODEOP_SET(udf_vnodeop_opv_desc);
   91 
   92 MALLOC_DEFINE(M_UDFFID, "UDF FID", "UDF FileId structure");
   93 MALLOC_DEFINE(M_UDFDS, "UDF DS", "UDF Dirstream structure");
   94 
   95 #define UDF_INVALID_BMAP        -1
   96 
   97 /* Look up a udf_node based on the ino_t passed in and return it's vnode */
   98 int
   99 udf_hashlookup(struct udf_mnt *udfmp, ino_t id, int flags, struct vnode **vpp)
  100 {
  101         struct udf_node *node;
  102         struct udf_hash_lh *lh;
  103         int error;
  104 
  105         *vpp = NULL;
  106 
  107 loop:
  108         mtx_lock(&udfmp->hash_mtx);
  109         lh = &udfmp->hashtbl[id % udfmp->hashsz];
  110         if (lh == NULL)
  111                 return (ENOENT);
  112         LIST_FOREACH(node, lh, le) {
  113                 if (node->hash_id == id) {
  114                         VI_LOCK(node->i_vnode);
  115                         mtx_unlock(&udfmp->hash_mtx);
  116                         error = vget(node->i_vnode, flags | LK_INTERLOCK,
  117                             curthread);
  118                         if (error == ENOENT)
  119                                 goto loop;
  120                         if (error)
  121                                 return (error);
  122                         *vpp = node->i_vnode;
  123                         return (0);
  124                 }
  125         }
  126 
  127         mtx_unlock(&udfmp->hash_mtx);
  128         return (0);
  129 }
  130 
  131 int
  132 udf_hashins(struct udf_node *node)
  133 {
  134         struct udf_mnt *udfmp;
  135         struct udf_hash_lh *lh;
  136 
  137         udfmp = node->udfmp;
  138 
  139         vn_lock(node->i_vnode, LK_EXCLUSIVE | LK_RETRY, curthread);
  140         mtx_lock(&udfmp->hash_mtx);
  141         lh = &udfmp->hashtbl[node->hash_id % udfmp->hashsz];
  142         if (lh == NULL)
  143                 LIST_INIT(lh);
  144         LIST_INSERT_HEAD(lh, node, le);
  145         mtx_unlock(&udfmp->hash_mtx);
  146 
  147         return (0);
  148 }
  149 
  150 int
  151 udf_hashrem(struct udf_node *node)
  152 {
  153         struct udf_mnt *udfmp;
  154         struct udf_hash_lh *lh;
  155 
  156         udfmp = node->udfmp;
  157 
  158         mtx_lock(&udfmp->hash_mtx);
  159         lh = &udfmp->hashtbl[node->hash_id % udfmp->hashsz];
  160         if (lh == NULL)
  161                 panic("hash entry is NULL, node->hash_id= %d\n", node->hash_id);
  162         LIST_REMOVE(node, le);
  163         mtx_unlock(&udfmp->hash_mtx);
  164 
  165         return (0);
  166 }
  167 
  168 int
  169 udf_allocv(struct mount *mp, struct vnode **vpp, struct thread *td)
  170 {
  171         int error;
  172         struct vnode *vp;
  173 
  174         error = getnewvnode("udf", mp, udf_vnodeop_p, &vp);
  175         if (error) {
  176                 printf("udf_allocv: failed to allocate new vnode\n");
  177                 return (error);
  178         }
  179 
  180         *vpp = vp;
  181         return (0);
  182 }
  183 
  184 /* Convert file entry permission (5 bits per owner/group/user) to a mode_t */
  185 static mode_t
  186 udf_permtomode(struct udf_node *node)
  187 {
  188         uint32_t perm;
  189         uint16_t flags;
  190         mode_t mode;
  191 
  192         perm = le32toh(node->fentry->perm);
  193         flags = le16toh(node->fentry->icbtag.flags);
  194 
  195         mode = perm & UDF_FENTRY_PERM_USER_MASK;
  196         mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2);
  197         mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
  198         mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4);
  199         mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6);
  200         mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8);
  201 
  202         return (mode);
  203 }
  204 
  205 static int
  206 udf_access(struct vop_access_args *a)
  207 {
  208         struct vnode *vp;
  209         struct udf_node *node;
  210         mode_t a_mode, mode;
  211 
  212         vp = a->a_vp;
  213         node = VTON(vp);
  214         a_mode = a->a_mode;
  215 
  216         if (a_mode & VWRITE) {
  217                 switch (vp->v_type) {
  218                 case VDIR:
  219                 case VLNK:
  220                 case VREG:
  221                         return (EROFS);
  222                         /* NOT REACHED */
  223                 default:
  224                         break;
  225                 }
  226         }
  227 
  228         mode = udf_permtomode(node);
  229 
  230         return (vaccess(vp->v_type, mode, node->fentry->uid, node->fentry->gid,
  231             a_mode, a->a_cred, NULL));
  232 }
  233 
  234 static int mon_lens[2][12] = {
  235         {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  236         {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
  237 };
  238 
  239 static int
  240 udf_isaleapyear(int year)
  241 {
  242         int i;
  243 
  244         i = (year % 4) ? 0 : 1;
  245         i &= (year % 100) ? 1 : 0;
  246         i |= (year % 400) ? 0 : 1;
  247 
  248         return i;
  249 }
  250 
  251 /*
  252  * XXX This is just a rough hack.  Daylight savings isn't calculated and tv_nsec
  253  * is ignored.
  254  * Timezone calculation compliments of Julian Elischer <julian@elischer.org>.
  255  */
  256 static void
  257 udf_timetotimespec(struct timestamp *time, struct timespec *t)
  258 {
  259         int i, lpyear, daysinyear, year;
  260         union {
  261                 uint16_t        u_tz_offset;
  262                 int16_t         s_tz_offset;
  263         } tz;
  264 
  265         t->tv_nsec = 0;
  266 
  267         /* DirectCD seems to like using bogus year values */
  268         year = le16toh(time->year);
  269         if (year < 1970) {
  270                 t->tv_sec = 0;
  271                 return;
  272         }
  273 
  274         /* Calculate the time and day */
  275         t->tv_sec = time->second;
  276         t->tv_sec += time->minute * 60;
  277         t->tv_sec += time->hour * 3600;
  278         t->tv_sec += time->day * 3600 * 24;
  279 
  280         /* Calculate the month */
  281         lpyear = udf_isaleapyear(year);
  282         for (i = 1; i < time->month; i++)
  283                 t->tv_sec += mon_lens[lpyear][i] * 3600 * 24;
  284 
  285         /* Speed up the calculation */
  286         if (year > 1979)
  287                 t->tv_sec += 315532800;
  288         if (year > 1989)
  289                 t->tv_sec += 315619200;
  290         if (year > 1999)
  291                 t->tv_sec += 315532800;
  292         for (i = 2000; i < year; i++) {
  293                 daysinyear = udf_isaleapyear(i) + 365 ;
  294                 t->tv_sec += daysinyear * 3600 * 24;
  295         }
  296 
  297         /*
  298          * Calculate the time zone.  The timezone is 12 bit signed 2's
  299          * complement, so we gotta do some extra magic to handle it right.
  300          */
  301         tz.u_tz_offset = le16toh(time->type_tz);
  302         tz.u_tz_offset &= 0x0fff;
  303         if (tz.u_tz_offset & 0x0800)
  304                 tz.u_tz_offset |= 0xf000;       /* extend the sign to 16 bits */
  305         if ((time->type_tz & 0x1000) && (tz.s_tz_offset != -2047))
  306                 t->tv_sec -= tz.s_tz_offset * 60;
  307 
  308         return;
  309 }
  310 
  311 static int
  312 udf_getattr(struct vop_getattr_args *a)
  313 {
  314         struct vnode *vp;
  315         struct udf_node *node;
  316         struct vattr *vap;
  317         struct file_entry *fentry;
  318         struct timespec ts;
  319 
  320         ts.tv_sec = 0;
  321 
  322         vp = a->a_vp;
  323         vap = a->a_vap;
  324         node = VTON(vp);
  325         fentry = node->fentry;
  326 
  327         vap->va_fsid = dev2udev(node->i_dev);
  328         vap->va_fileid = node->hash_id;
  329         vap->va_mode = udf_permtomode(node);
  330         vap->va_nlink = le16toh(fentry->link_cnt);
  331         /*
  332          * XXX The spec says that -1 is valid for uid/gid and indicates an
  333          * invalid uid/gid.  How should this be represented?
  334          */
  335         vap->va_uid = (le32toh(fentry->uid) == -1) ? 0 : le32toh(fentry->uid);
  336         vap->va_gid = (le32toh(fentry->gid) == -1) ? 0 : le32toh(fentry->gid);
  337         udf_timetotimespec(&fentry->atime, &vap->va_atime);
  338         udf_timetotimespec(&fentry->mtime, &vap->va_mtime);
  339         vap->va_ctime = vap->va_mtime; /* XXX Stored as an Extended Attribute */
  340         vap->va_rdev = 0; /* XXX */
  341         if (vp->v_type & VDIR) {
  342                 /*
  343                  * Directories that are recorded within their ICB will show
  344                  * as having 0 blocks recorded.  Since tradition dictates
  345                  * that directories consume at least one logical block,
  346                  * make it appear so.
  347                  */
  348                 if (fentry->logblks_rec != 0) {
  349                         vap->va_size =
  350                             le64toh(fentry->logblks_rec) * node->udfmp->bsize;
  351                 } else {
  352                         vap->va_size = node->udfmp->bsize;
  353                 }
  354         } else {
  355                 vap->va_size = le64toh(fentry->inf_len);
  356         }
  357         vap->va_flags = 0;
  358         vap->va_gen = 1;
  359         vap->va_blocksize = node->udfmp->bsize;
  360         vap->va_bytes = le64toh(fentry->inf_len);
  361         vap->va_type = vp->v_type;
  362         vap->va_filerev = 0; /* XXX */
  363         return (0);
  364 }
  365 
  366 /*
  367  * File specific ioctls.
  368  */
  369 static int
  370 udf_ioctl(struct vop_ioctl_args *a)
  371 {
  372         printf("%s called\n", __func__);
  373         return (ENOTTY);
  374 }
  375 
  376 /*
  377  * I'm not sure that this has much value in a read-only filesystem, but
  378  * cd9660 has it too.
  379  */
  380 static int
  381 udf_pathconf(struct vop_pathconf_args *a)
  382 {
  383 
  384         switch (a->a_name) {
  385         case _PC_LINK_MAX:
  386                 *a->a_retval = 65535;
  387                 return (0);
  388         case _PC_NAME_MAX:
  389                 *a->a_retval = NAME_MAX;
  390                 return (0);
  391         case _PC_PATH_MAX:
  392                 *a->a_retval = PATH_MAX;
  393                 return (0);
  394         case _PC_NO_TRUNC:
  395                 *a->a_retval = 1;
  396                 return (0);
  397         default:
  398                 return (EINVAL);
  399         }
  400 }
  401 
  402 static int
  403 udf_read(struct vop_read_args *a)
  404 {
  405         struct vnode *vp = a->a_vp;
  406         struct uio *uio = a->a_uio;
  407         struct udf_node *node = VTON(vp);
  408         struct buf *bp;
  409         uint8_t *data;
  410         int error = 0;
  411         int size, fsize, offset;
  412 
  413         if (uio->uio_offset < 0)
  414                 return (EINVAL);
  415 
  416         fsize = le64toh(node->fentry->inf_len);
  417 
  418         while (uio->uio_offset < fsize && uio->uio_resid > 0) {
  419                 offset = uio->uio_offset;
  420                 size = uio->uio_resid;
  421                 error = udf_readatoffset(node, &size, offset, &bp, &data);
  422                 if (error == 0)
  423                         error = uiomove(data, size, uio);
  424                 if (bp != NULL)
  425                         brelse(bp);
  426                 if (error)
  427                         break;
  428         };
  429 
  430         return (error);
  431 }
  432 
  433 /*
  434  * Call the OSTA routines to translate the name from a CS0 dstring to a
  435  * 16-bit Unicode String.  Hooks need to be placed in here to translate from
  436  * Unicode to the encoding that the kernel/user expects.  Return the length
  437  * of the translated string.
  438  */
  439 static int
  440 udf_transname(char *cs0string, char *destname, int len, struct udf_mnt *udfmp)
  441 {
  442         unicode_t *transname;
  443         char *unibuf, *unip;
  444         int i, destlen;
  445         ssize_t unilen = 0;
  446         size_t destleft = MAXNAMLEN;
  447 
  448         /* Convert 16-bit Unicode to destname */
  449         if (udfmp->im_flags & UDFMNT_KICONV && udf_iconv) {
  450                 /* allocate a buffer big enough to hold an 8->16 bit expansion */
  451                 unibuf = uma_zalloc(udf_zone_trans, M_WAITOK);
  452                 unip = unibuf;
  453                 if ((unilen = (ssize_t)udf_UncompressUnicodeByte(len, cs0string, unibuf)) == -1) {
  454                         printf("udf: Unicode translation failed\n");
  455                         uma_zfree(udf_zone_trans, unibuf);
  456                         return 0;
  457                 }
  458 
  459                 while (unilen > 0 && destleft > 0) {
  460                         udf_iconv->conv(udfmp->im_d2l, (const char **)&unibuf,
  461                                 (size_t *)&unilen, (char **)&destname, &destleft);
  462                         /* Unconverted character found */
  463                         if (unilen > 0 && destleft > 0) {
  464                                 *destname++ = '?';
  465                                 destleft--;
  466                                 unibuf += 2;
  467                                 unilen -= 2;
  468                         }
  469                 }
  470                 uma_zfree(udf_zone_trans, unip);
  471                 *destname = '\0';
  472                 destlen = MAXNAMLEN - (int)destleft;
  473         } else {
  474                 /* allocate a buffer big enough to hold an 8->16 bit expansion */
  475                 transname = uma_zalloc(udf_zone_trans, M_WAITOK);
  476 
  477                 if ((unilen = (ssize_t)udf_UncompressUnicode(len, cs0string, transname)) == -1) {
  478                         printf("udf: Unicode translation failed\n");
  479                         uma_zfree(udf_zone_trans, transname);
  480                         return 0;
  481                 }
  482 
  483                 for (i = 0; i < unilen ; i++) {
  484                         if (transname[i] & 0xff00) {
  485                                 destname[i] = '.';      /* Fudge the 16bit chars */
  486                         } else {
  487                                 destname[i] = transname[i] & 0xff;
  488                         }
  489                 }
  490                 uma_zfree(udf_zone_trans, transname);
  491                 destname[unilen] = 0;
  492                 destlen = (int)unilen;
  493         }
  494 
  495         return (destlen);
  496 }
  497 
  498 /*
  499  * Compare a CS0 dstring with a name passed in from the VFS layer.  Return
  500  * 0 on a successful match, nonzero otherwise.  Unicode work may need to be done
  501  * here also.
  502  */
  503 static int
  504 udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct udf_mnt *udfmp)
  505 {
  506         char *transname;
  507         int error = 0;
  508 
  509         /* This is overkill, but not worth creating a new zone */
  510         transname = uma_zalloc(udf_zone_trans, M_WAITOK);
  511 
  512         cs0len = udf_transname(cs0string, transname, cs0len, udfmp);
  513 
  514         /* Easy check.  If they aren't the same length, they aren't equal */
  515         if ((cs0len == 0) || (cs0len != cmplen))
  516                 error = -1;
  517         else
  518                 error = bcmp(transname, cmpname, cmplen);
  519 
  520         uma_zfree(udf_zone_trans, transname);
  521         return (error);
  522 }
  523 
  524 struct udf_uiodir {
  525         struct dirent *dirent;
  526         u_long *cookies;
  527         int ncookies;
  528         int acookies;
  529         int eofflag;
  530 };
  531 
  532 static int
  533 udf_uiodir(struct udf_uiodir *uiodir, int de_size, struct uio *uio, long cookie)
  534 {
  535         if (uiodir->cookies != NULL) {
  536                 if (++uiodir->acookies > uiodir->ncookies) {
  537                         uiodir->eofflag = 0;
  538                         return (-1);
  539                 }
  540                 *uiodir->cookies++ = cookie;
  541         }
  542 
  543         if (uio->uio_resid < de_size) {
  544                 uiodir->eofflag = 0;
  545                 return (-1);
  546         }
  547 
  548         return (uiomove(uiodir->dirent, de_size, uio));
  549 }
  550 
  551 static struct udf_dirstream *
  552 udf_opendir(struct udf_node *node, int offset, int fsize, struct udf_mnt *udfmp)
  553 {
  554         struct udf_dirstream *ds;
  555 
  556         ds = uma_zalloc(udf_zone_ds, M_WAITOK | M_ZERO);
  557 
  558         ds->node = node;
  559         ds->offset = offset;
  560         ds->udfmp = udfmp;
  561         ds->fsize = fsize;
  562 
  563         return (ds);
  564 }
  565 
  566 static struct fileid_desc *
  567 udf_getfid(struct udf_dirstream *ds)
  568 {
  569         struct fileid_desc *fid;
  570         int error, frag_size = 0, total_fid_size;
  571 
  572         /* End of directory? */
  573         if (ds->offset + ds->off >= ds->fsize) {
  574                 ds->error = 0;
  575                 return (NULL);
  576         }
  577 
  578         /* Grab the first extent of the directory */
  579         if (ds->off == 0) {
  580                 ds->size = 0;
  581                 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
  582                     &ds->bp, &ds->data);
  583                 if (error) {
  584                         ds->error = error;
  585                         if (ds->bp != NULL)
  586                                 brelse(ds->bp);
  587                         return (NULL);
  588                 }
  589         }
  590 
  591         /*
  592          * Clean up from a previous fragmented FID.
  593          * XXX Is this the right place for this?
  594          */
  595         if (ds->fid_fragment && ds->buf != NULL) {
  596                 ds->fid_fragment = 0;
  597                 FREE(ds->buf, M_UDFFID);
  598         }
  599 
  600         fid = (struct fileid_desc*)&ds->data[ds->off];
  601 
  602         /*
  603          * Check to see if the fid is fragmented. The first test
  604          * ensures that we don't wander off the end of the buffer
  605          * looking for the l_iu and l_fi fields.
  606          */
  607         if (ds->off + UDF_FID_SIZE > ds->size ||
  608             ds->off + le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE > ds->size){
  609 
  610                 /* Copy what we have of the fid into a buffer */
  611                 frag_size = ds->size - ds->off;
  612                 if (frag_size >= ds->udfmp->bsize) {
  613                         printf("udf: invalid FID fragment\n");
  614                         ds->error = EINVAL;
  615                         return (NULL);
  616                 }
  617 
  618                 /*
  619                  * File ID descriptors can only be at most one
  620                  * logical sector in size.
  621                  */
  622                 MALLOC(ds->buf, uint8_t*, ds->udfmp->bsize, M_UDFFID,
  623                      M_WAITOK | M_ZERO);
  624                 bcopy(fid, ds->buf, frag_size);
  625 
  626                 /* Reduce all of the casting magic */
  627                 fid = (struct fileid_desc*)ds->buf;
  628 
  629                 if (ds->bp != NULL)
  630                         brelse(ds->bp);
  631 
  632                 /* Fetch the next allocation */
  633                 ds->offset += ds->size;
  634                 ds->size = 0;
  635                 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
  636                     &ds->bp, &ds->data);
  637                 if (error) {
  638                         ds->error = error;
  639                         return (NULL);
  640                 }
  641 
  642                 /*
  643                  * If the fragment was so small that we didn't get
  644                  * the l_iu and l_fi fields, copy those in.
  645                  */
  646                 if (frag_size < UDF_FID_SIZE)
  647                         bcopy(ds->data, &ds->buf[frag_size],
  648                             UDF_FID_SIZE - frag_size);
  649 
  650                 /*
  651                  * Now that we have enough of the fid to work with,
  652                  * copy in the rest of the fid from the new
  653                  * allocation.
  654                  */
  655                 total_fid_size = UDF_FID_SIZE + le16toh(fid->l_iu) + fid->l_fi;
  656                 if (total_fid_size > ds->udfmp->bsize) {
  657                         printf("udf: invalid FID\n");
  658                         ds->error = EIO;
  659                         return (NULL);
  660                 }
  661                 bcopy(ds->data, &ds->buf[frag_size],
  662                     total_fid_size - frag_size);
  663 
  664                 ds->fid_fragment = 1;
  665         } else {
  666                 total_fid_size = le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE;
  667         }
  668 
  669         /*
  670          * Update the offset. Align on a 4 byte boundary because the
  671          * UDF spec says so.
  672          */
  673         ds->this_off = ds->off;
  674         if (!ds->fid_fragment) {
  675                 ds->off += (total_fid_size + 3) & ~0x03;
  676         } else {
  677                 ds->off = (total_fid_size - frag_size + 3) & ~0x03;
  678         }
  679 
  680         return (fid);
  681 }
  682 
  683 static void
  684 udf_closedir(struct udf_dirstream *ds)
  685 {
  686 
  687         if (ds->bp != NULL)
  688                 brelse(ds->bp);
  689 
  690         if (ds->fid_fragment && ds->buf != NULL)
  691                 FREE(ds->buf, M_UDFFID);
  692 
  693         uma_zfree(udf_zone_ds, ds);
  694 }
  695 
  696 static int
  697 udf_readdir(struct vop_readdir_args *a)
  698 {
  699         struct vnode *vp;
  700         struct uio *uio;
  701         struct dirent dir;
  702         struct udf_node *node;
  703         struct udf_mnt *udfmp;
  704         struct fileid_desc *fid;
  705         struct udf_uiodir uiodir;
  706         struct udf_dirstream *ds;
  707         u_long *cookies = NULL;
  708         int ncookies;
  709         int error = 0;
  710 
  711         vp = a->a_vp;
  712         uio = a->a_uio;
  713         node = VTON(vp);
  714         udfmp = node->udfmp;
  715         uiodir.eofflag = 1;
  716 
  717         if (a->a_ncookies != NULL) {
  718                 /*
  719                  * Guess how many entries are needed.  If we run out, this
  720                  * function will be called again and thing will pick up were
  721                  * it left off.
  722                  */
  723                 ncookies = uio->uio_resid / 8;
  724                 MALLOC(cookies, u_long *, sizeof(u_long) * ncookies,
  725                     M_TEMP, M_WAITOK);
  726                 if (cookies == NULL)
  727                         return (ENOMEM);
  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(node, uio->uio_offset, le64toh(node->fentry->inf_len),
  740             node->udfmp);
  741 
  742         while ((fid = udf_getfid(ds)) != NULL) {
  743 
  744                 /* XXX Should we return an error on a bad fid? */
  745                 if (udf_checktag(&fid->tag, TAGID_FID)) {
  746                         printf("Invalid FID tag\n");
  747                         hexdump(fid, UDF_FID_SIZE, NULL, 0);
  748                         error = EIO;
  749                         break;
  750                 }
  751 
  752                 /* Is this a deleted file? */
  753                 if (fid->file_char & UDF_FILE_CHAR_DEL)
  754                         continue;
  755 
  756                 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
  757                         /* Do up the '.' and '..' entries.  Dummy values are
  758                          * used for the cookies since the offset here is
  759                          * usually zero, and NFS doesn't like that value
  760                          */
  761                         dir.d_fileno = node->hash_id;
  762                         dir.d_type = DT_DIR;
  763                         dir.d_name[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_namlen = 2;
  776                         dir.d_reclen = GENERIC_DIRSIZ(&dir);
  777                         uiodir.dirent = &dir;
  778                         error = udf_uiodir(&uiodir, dir.d_reclen, uio, 2);
  779                 } else {
  780                         dir.d_namlen = udf_transname(&fid->data[fid->l_iu],
  781                             &dir.d_name[0], fid->l_fi, udfmp);
  782                         dir.d_fileno = udf_getid(&fid->icb);
  783                         dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ?
  784                             DT_DIR : DT_UNKNOWN;
  785                         dir.d_reclen = GENERIC_DIRSIZ(&dir);
  786                         uiodir.dirent = &dir;
  787                         error = udf_uiodir(&uiodir, dir.d_reclen, uio,
  788                             ds->this_off);
  789                 }
  790                 if (error) {
  791                         printf("uiomove returned %d\n", error);
  792                         break;
  793                 }
  794 
  795         }
  796 
  797         /* tell the calling layer whether we need to be called again */
  798         *a->a_eofflag = uiodir.eofflag;
  799         uio->uio_offset = ds->offset + ds->off;
  800 
  801         if (!error)
  802                 error = ds->error;
  803 
  804         udf_closedir(ds);
  805 
  806         if (a->a_ncookies != NULL) {
  807                 if (error)
  808                         FREE(cookies, M_TEMP);
  809                 else {
  810                         *a->a_ncookies = uiodir.acookies;
  811                         *a->a_cookies = cookies;
  812                 }
  813         }
  814 
  815         return (error);
  816 }
  817 
  818 /* Are there any implementations out there that do soft-links? */
  819 static int
  820 udf_readlink(struct vop_readlink_args *ap)
  821 {
  822         printf("%s called\n", __func__);
  823         return (EOPNOTSUPP);
  824 }
  825 
  826 static int
  827 udf_strategy(struct vop_strategy_args *a)
  828 {
  829         struct buf *bp;
  830         struct vnode *vp;
  831         struct udf_node *node;
  832         int maxsize;
  833 
  834         bp = a->a_bp;
  835         vp = bp->b_vp;
  836         node = VTON(vp);
  837 
  838         KASSERT(a->a_vp == a->a_bp->b_vp, ("%s(%p != %p)",
  839             __func__, a->a_vp, a->a_bp->b_vp));
  840         /* cd9660 has this test reversed, but it seems more logical this way */
  841         if (bp->b_blkno != bp->b_lblkno) {
  842                 /*
  843                  * Files that are embedded in the fentry don't translate well
  844                  * to a block number.  Reject.
  845                  */
  846                 if (udf_bmap_internal(node, bp->b_lblkno * node->udfmp->bsize,
  847                     &bp->b_lblkno, &maxsize)) {
  848                         clrbuf(bp);
  849                         bp->b_blkno = -1;
  850                 }
  851         }
  852         if ((long)bp->b_blkno == -1) {
  853                 bufdone(bp);
  854                 return (0);
  855         }
  856         vp = node->i_devvp;
  857         bp->b_dev = vp->v_rdev;
  858         bp->b_iooffset = dbtob(bp->b_blkno);
  859         VOP_SPECSTRATEGY(vp, bp);
  860         return (0);
  861 }
  862 
  863 static int
  864 udf_bmap(struct vop_bmap_args *a)
  865 {
  866         struct udf_node *node;
  867         uint32_t max_size;
  868         daddr_t lsector;
  869         int error;
  870 
  871         node = VTON(a->a_vp);
  872 
  873         if (a->a_vpp != NULL)
  874                 *a->a_vpp = node->i_devvp;
  875         if (a->a_bnp == NULL)
  876                 return (0);
  877         if (a->a_runb)
  878                 *a->a_runb = 0;
  879 
  880         error = udf_bmap_internal(node, a->a_bn * node->udfmp->bsize, &lsector,
  881             &max_size);
  882         if (error)
  883                 return (error);
  884 
  885         /* Translate logical to physical sector number */
  886         *a->a_bnp = lsector << (node->udfmp->bshift - DEV_BSHIFT);
  887 
  888         /* Punt on read-ahead for now */
  889         if (a->a_runp)
  890                 *a->a_runp = 0;
  891 
  892         return (0);
  893 }
  894 
  895 /*
  896  * The all powerful VOP_LOOKUP().
  897  */
  898 static int
  899 udf_lookup(struct vop_cachedlookup_args *a)
  900 {
  901         struct vnode *dvp;
  902         struct vnode *tdp = NULL;
  903         struct vnode **vpp = a->a_vpp;
  904         struct udf_node *node;
  905         struct udf_mnt *udfmp;
  906         struct fileid_desc *fid = NULL;
  907         struct udf_dirstream *ds;
  908         struct thread *td;
  909         u_long nameiop;
  910         u_long flags;
  911         char *nameptr;
  912         long namelen;
  913         ino_t id = 0;
  914         int offset, error = 0;
  915         int numdirpasses, fsize;
  916 
  917         dvp = a->a_dvp;
  918         node = VTON(dvp);
  919         udfmp = node->udfmp;
  920         nameiop = a->a_cnp->cn_nameiop;
  921         flags = a->a_cnp->cn_flags;
  922         nameptr = a->a_cnp->cn_nameptr;
  923         namelen = a->a_cnp->cn_namelen;
  924         fsize = le64toh(node->fentry->inf_len);
  925         td = a->a_cnp->cn_thread;
  926 
  927         /*
  928          * If this is a LOOKUP and we've already partially searched through
  929          * the directory, pick up where we left off and flag that the
  930          * directory may need to be searched twice.  For a full description,
  931          * see /sys/isofs/cd9660/cd9660_lookup.c:cd9660_lookup()
  932          */
  933         if (nameiop != LOOKUP || node->diroff == 0 || node->diroff > fsize) {
  934                 offset = 0;
  935                 numdirpasses = 1;
  936         } else {
  937                 offset = node->diroff;
  938                 numdirpasses = 2;
  939                 nchstats.ncs_2passes++;
  940         }
  941 
  942 lookloop:
  943         ds = udf_opendir(node, offset, fsize, udfmp);
  944 
  945         while ((fid = udf_getfid(ds)) != NULL) {
  946 
  947                 /* XXX Should we return an error on a bad fid? */
  948                 if (udf_checktag(&fid->tag, TAGID_FID)) {
  949                         printf("udf_lookup: Invalid tag\n");
  950                         error = EIO;
  951                         break;
  952                 }
  953 
  954                 /* Is this a deleted file? */
  955                 if (fid->file_char & UDF_FILE_CHAR_DEL)
  956                         continue;
  957 
  958                 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
  959                         if (flags & ISDOTDOT) {
  960                                 id = udf_getid(&fid->icb);
  961                                 break;
  962                         }
  963                 } else {
  964                         if (!(udf_cmpname(&fid->data[fid->l_iu],
  965                             nameptr, fid->l_fi, namelen, udfmp))) {
  966                                 id = udf_getid(&fid->icb);
  967                                 break;
  968                         }
  969                 }
  970         }
  971 
  972         if (!error)
  973                 error = ds->error;
  974 
  975         /* XXX Bail out here? */
  976         if (error) {
  977                 udf_closedir(ds);
  978                 return (error);
  979         }
  980 
  981         /* Did we have a match? */
  982         if (id) {
  983                 error = udf_vget(udfmp->im_mountp, id, LK_EXCLUSIVE, &tdp);
  984                 if (!error) {
  985                         /*
  986                          * Remember where this entry was if it's the final
  987                          * component.
  988                          */
  989                         if ((flags & ISLASTCN) && nameiop == LOOKUP)
  990                                 node->diroff = ds->offset + ds->off;
  991                         if (numdirpasses == 2)
  992                                 nchstats.ncs_pass2++;
  993                         if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) {
  994                                 a->a_cnp->cn_flags |= PDIRUNLOCK;
  995                                 VOP_UNLOCK(dvp, 0, td);
  996                         }
  997 
  998                         *vpp = tdp;
  999 
 1000                         /* Put this entry in the cache */
 1001                         if (flags & MAKEENTRY)
 1002                                 cache_enter(dvp, *vpp, a->a_cnp);
 1003                 }
 1004         } else {
 1005                 /* Name wasn't found on this pass.  Do another pass? */
 1006                 if (numdirpasses == 2) {
 1007                         numdirpasses--;
 1008                         offset = 0;
 1009                         udf_closedir(ds);
 1010                         goto lookloop;
 1011                 }
 1012 
 1013                 /* Enter name into cache as non-existant */
 1014                 if (flags & MAKEENTRY)
 1015                         cache_enter(dvp, *vpp, a->a_cnp);
 1016 
 1017                 if ((flags & ISLASTCN) &&
 1018                     (nameiop == CREATE || nameiop == RENAME)) {
 1019                         error = EROFS;
 1020                 } else {
 1021                         error = ENOENT;
 1022                 }
 1023         }
 1024 
 1025         udf_closedir(ds);
 1026         return (error);
 1027 }
 1028 
 1029 static int
 1030 udf_reclaim(struct vop_reclaim_args *a)
 1031 {
 1032         struct vnode *vp;
 1033         struct udf_node *unode;
 1034 
 1035         vp = a->a_vp;
 1036         unode = VTON(vp);
 1037 
 1038         if (unode != NULL) {
 1039                 udf_hashrem(unode);
 1040                 if (unode->i_devvp) {
 1041                         vrele(unode->i_devvp);
 1042                         unode->i_devvp = 0;
 1043                 }
 1044 
 1045                 if (unode->fentry != NULL)
 1046                         FREE(unode->fentry, M_UDFFENTRY);
 1047                 uma_zfree(udf_zone_node, unode);
 1048                 vp->v_data = NULL;
 1049         }
 1050 
 1051         return (0);
 1052 }
 1053 
 1054 /*
 1055  * Read the block and then set the data pointer to correspond with the
 1056  * offset passed in.  Only read in at most 'size' bytes, and then set 'size'
 1057  * to the number of bytes pointed to.  If 'size' is zero, try to read in a
 1058  * whole extent.
 1059  *
 1060  * Note that *bp may be assigned error or not.
 1061  *
 1062  */
 1063 static int
 1064 udf_readatoffset(struct udf_node *node, int *size, int offset, struct buf **bp, uint8_t **data)
 1065 {
 1066         struct udf_mnt *udfmp;
 1067         struct file_entry *fentry = NULL;
 1068         struct buf *bp1;
 1069         uint32_t max_size;
 1070         daddr_t sector;
 1071         int error;
 1072 
 1073         udfmp = node->udfmp;
 1074 
 1075         *bp = NULL;
 1076         error = udf_bmap_internal(node, offset, &sector, &max_size);
 1077         if (error == UDF_INVALID_BMAP) {
 1078                 /*
 1079                  * This error means that the file *data* is stored in the
 1080                  * allocation descriptor field of the file entry.
 1081                  */
 1082                 fentry = node->fentry;
 1083                 *data = &fentry->data[le32toh(fentry->l_ea)];
 1084                 *size = le32toh(fentry->l_ad);
 1085                 return (0);
 1086         } else if (error != 0) {
 1087                 return (error);
 1088         }
 1089 
 1090         /* Adjust the size so that it is within range */
 1091         if (*size == 0 || *size > max_size)
 1092                 *size = max_size;
 1093         *size = min(*size, MAXBSIZE);
 1094 
 1095         if ((error = udf_readlblks(udfmp, sector, *size + (offset & udfmp->bmask), bp))) {
 1096                 printf("warning: udf_readlblks returned error %d\n", error);
 1097                 /* note: *bp may be non-NULL */
 1098                 return (error);
 1099         }
 1100 
 1101         bp1 = *bp;
 1102         *data = (uint8_t *)&bp1->b_data[offset & udfmp->bmask];
 1103         return (0);
 1104 }
 1105 
 1106 /*
 1107  * Translate a file offset into a logical block and then into a physical
 1108  * block.
 1109  * max_size - maximum number of bytes that can be read starting from given
 1110  * offset, rather than beginning of calculated sector number
 1111  */
 1112 static int
 1113 udf_bmap_internal(struct udf_node *node, uint32_t offset, daddr_t *sector, uint32_t *max_size)
 1114 {
 1115         struct udf_mnt *udfmp;
 1116         struct file_entry *fentry;
 1117         void *icb;
 1118         struct icb_tag *tag;
 1119         uint32_t icblen = 0;
 1120         daddr_t lsector;
 1121         int ad_offset, ad_num = 0;
 1122         int i, p_offset;
 1123 
 1124         udfmp = node->udfmp;
 1125         fentry = node->fentry;
 1126         tag = &fentry->icbtag;
 1127 
 1128         switch (le16toh(tag->strat_type)) {
 1129         case 4:
 1130                 break;
 1131 
 1132         case 4096:
 1133                 printf("Cannot deal with strategy4096 yet!\n");
 1134                 return (ENODEV);
 1135 
 1136         default:
 1137                 printf("Unknown strategy type %d\n", tag->strat_type);
 1138                 return (ENODEV);
 1139         }
 1140 
 1141         switch (le16toh(tag->flags) & 0x7) {
 1142         case 0:
 1143                 /*
 1144                  * The allocation descriptor field is filled with short_ad's.
 1145                  * If the offset is beyond the current extent, look for the
 1146                  * next extent.
 1147                  */
 1148                 do {
 1149                         offset -= icblen;
 1150                         ad_offset = sizeof(struct short_ad) * ad_num;
 1151                         if (ad_offset > le32toh(fentry->l_ad)) {
 1152                                 printf("File offset out of bounds\n");
 1153                                 return (EINVAL);
 1154                         }
 1155                         icb = GETICB(long_ad, fentry,
 1156                             le32toh(fentry->l_ea) + ad_offset);
 1157                         icblen = GETICBLEN(short_ad, icb);
 1158                         ad_num++;
 1159                 } while(offset >= icblen);
 1160 
 1161                 lsector = (offset  >> udfmp->bshift) +
 1162                     ((struct short_ad *)(icb))->pos;
 1163 
 1164                 *max_size = icblen - offset;
 1165 
 1166                 break;
 1167         case 1:
 1168                 /*
 1169                  * The allocation descriptor field is filled with long_ad's
 1170                  * If the offset is beyond the current extent, look for the
 1171                  * next extent.
 1172                  */
 1173                 do {
 1174                         offset -= icblen;
 1175                         ad_offset = sizeof(struct long_ad) * ad_num;
 1176                         if (ad_offset > le32toh(fentry->l_ad)) {
 1177                                 printf("File offset out of bounds\n");
 1178                                 return (EINVAL);
 1179                         }
 1180                         icb = GETICB(long_ad, fentry,
 1181                             le32toh(fentry->l_ea) + ad_offset);
 1182                         icblen = GETICBLEN(long_ad, icb);
 1183                         ad_num++;
 1184                 } while(offset >= icblen);
 1185 
 1186                 lsector = (offset >> udfmp->bshift) +
 1187                     le32toh(((struct long_ad *)(icb))->loc.lb_num);
 1188 
 1189                 *max_size = icblen - offset;
 1190 
 1191                 break;
 1192         case 3:
 1193                 /*
 1194                  * This type means that the file *data* is stored in the
 1195                  * allocation descriptor field of the file entry.
 1196                  */
 1197                 *max_size = 0;
 1198                 *sector = node->hash_id + udfmp->part_start;
 1199 
 1200                 return (UDF_INVALID_BMAP);
 1201         case 2:
 1202                 /* DirectCD does not use extended_ad's */
 1203         default:
 1204                 printf("Unsupported allocation descriptor %d\n",
 1205                        tag->flags & 0x7);
 1206                 return (ENODEV);
 1207         }
 1208 
 1209         *sector = lsector + udfmp->part_start;
 1210 
 1211         /*
 1212          * Check the sparing table.  Each entry represents the beginning of
 1213          * a packet.
 1214          */
 1215         if (udfmp->s_table != NULL) {
 1216                 for (i = 0; i< udfmp->s_table_entries; i++) {
 1217                         p_offset =
 1218                             lsector - le32toh(udfmp->s_table->entries[i].org);
 1219                         if ((p_offset < udfmp->p_sectors) && (p_offset >= 0)) {
 1220                                 *sector =
 1221                                    le32toh(udfmp->s_table->entries[i].map) +
 1222                                     p_offset;
 1223                                 break;
 1224                         }
 1225                 }
 1226         }
 1227 
 1228         return (0);
 1229 }

Cache object: ff7e593ede637e5263f68b46c0164628


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