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

Cache object: 6f11cdd25c7ee3f0712e1f0c676a7e9d


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