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/ext2fs/ext2_extattr.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2017, Fedor Uporov
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  * $FreeBSD$
   29  */
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/types.h>
   34 #include <sys/kernel.h>
   35 #include <sys/malloc.h>
   36 #include <sys/vnode.h>
   37 #include <sys/bio.h>
   38 #include <sys/buf.h>
   39 #include <sys/endian.h>
   40 #include <sys/conf.h>
   41 #include <sys/extattr.h>
   42 #include <sys/sdt.h>
   43 
   44 #include <fs/ext2fs/fs.h>
   45 #include <fs/ext2fs/ext2fs.h>
   46 #include <fs/ext2fs/inode.h>
   47 #include <fs/ext2fs/ext2_dinode.h>
   48 #include <fs/ext2fs/ext2_mount.h>
   49 #include <fs/ext2fs/ext2_extattr.h>
   50 #include <fs/ext2fs/ext2_extern.h>
   51 
   52 SDT_PROVIDER_DECLARE(ext2fs);
   53 /*
   54  * ext2fs trace probe:
   55  * arg0: verbosity. Higher numbers give more verbose messages
   56  * arg1: Textual message
   57  */
   58 SDT_PROBE_DEFINE2(ext2fs, , trace, extattr, "int", "char*");
   59 
   60 static int
   61 ext2_extattr_attrnamespace_to_bsd(int attrnamespace)
   62 {
   63 
   64         switch (attrnamespace) {
   65         case EXT4_XATTR_INDEX_SYSTEM:
   66                 return (EXTATTR_NAMESPACE_SYSTEM);
   67 
   68         case EXT4_XATTR_INDEX_USER:
   69                 return (EXTATTR_NAMESPACE_USER);
   70 
   71         case EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT:
   72                 return (POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE);
   73 
   74         case EXT4_XATTR_INDEX_POSIX_ACL_ACCESS:
   75                 return (POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE);
   76         }
   77 
   78         return (EXTATTR_NAMESPACE_EMPTY);
   79 }
   80 
   81 static const char *
   82 ext2_extattr_name_to_bsd(int attrnamespace, const char *name, int* name_len)
   83 {
   84 
   85         if (attrnamespace == EXT4_XATTR_INDEX_SYSTEM)
   86                 return (name);
   87         else if (attrnamespace == EXT4_XATTR_INDEX_USER)
   88                 return (name);
   89         else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT) {
   90                 *name_len = strlen(POSIX1E_ACL_DEFAULT_EXTATTR_NAME);
   91                 return (POSIX1E_ACL_DEFAULT_EXTATTR_NAME);
   92         } else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_ACCESS) {
   93                 *name_len = strlen(POSIX1E_ACL_ACCESS_EXTATTR_NAME);
   94                 return (POSIX1E_ACL_ACCESS_EXTATTR_NAME);
   95         }
   96 
   97         /*
   98          * XXX: Not all linux namespaces are mapped to bsd for now,
   99          * return NULL, which will be converted to ENOTSUP on upper layer.
  100          */
  101         SDT_PROBE2(ext2fs, , trace, extattr, 1,
  102             "can not convert ext2fs name to bsd namespace");
  103 
  104         return (NULL);
  105 }
  106 
  107 static int
  108 ext2_extattr_attrnamespace_to_linux(int attrnamespace, const char *name)
  109 {
  110 
  111         if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE &&
  112             !strcmp(name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME))
  113                 return (EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT);
  114 
  115         if (attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE &&
  116             !strcmp(name, POSIX1E_ACL_ACCESS_EXTATTR_NAME))
  117                 return (EXT4_XATTR_INDEX_POSIX_ACL_ACCESS);
  118 
  119         switch (attrnamespace) {
  120         case EXTATTR_NAMESPACE_SYSTEM:
  121                 return (EXT4_XATTR_INDEX_SYSTEM);
  122 
  123         case EXTATTR_NAMESPACE_USER:
  124                 return (EXT4_XATTR_INDEX_USER);
  125         }
  126 
  127         /*
  128          * In this case namespace conversion should be unique,
  129          * so this point is unreachable.
  130          */
  131         return (-1);
  132 }
  133 
  134 static const char *
  135 ext2_extattr_name_to_linux(int attrnamespace, const char *name)
  136 {
  137 
  138         if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE ||
  139             attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE)
  140                 return ("");
  141         else
  142                 return (name);
  143 }
  144 
  145 int
  146 ext2_extattr_valid_attrname(int attrnamespace, const char *attrname)
  147 {
  148         if (attrnamespace == EXTATTR_NAMESPACE_EMPTY)
  149                 return (EINVAL);
  150 
  151         if (strlen(attrname) == 0)
  152                 return (EINVAL);
  153 
  154         if (strlen(attrname) + 1 > EXT2_EXTATTR_NAMELEN_MAX)
  155                 return (ENAMETOOLONG);
  156 
  157         return (0);
  158 }
  159 
  160 static int
  161 ext2_extattr_check(struct ext2fs_extattr_entry *entry, char *end)
  162 {
  163         struct ext2fs_extattr_entry *next;
  164 
  165         while (!EXT2_IS_LAST_ENTRY(entry)) {
  166                 next = EXT2_EXTATTR_NEXT(entry);
  167                 if ((char *)next >= end)
  168                         return (EIO);
  169 
  170                 entry = next;
  171         }
  172 
  173         return (0);
  174 }
  175 
  176 static int
  177 ext2_extattr_block_check(struct inode *ip, struct buf *bp)
  178 {
  179         struct ext2fs_extattr_header *header;
  180         int error;
  181 
  182         header = (struct ext2fs_extattr_header *)bp->b_data;
  183 
  184         error = ext2_extattr_check(EXT2_IFIRST(header),
  185             bp->b_data + bp->b_bufsize);
  186         if (error)
  187                 return (error);
  188 
  189         return (ext2_extattr_blk_csum_verify(ip, bp));
  190 }
  191 
  192 int
  193 ext2_extattr_inode_list(struct inode *ip, int attrnamespace,
  194     struct uio *uio, size_t *size)
  195 {
  196         struct m_ext2fs *fs;
  197         struct buf *bp;
  198         struct ext2fs_extattr_dinode_header *header;
  199         struct ext2fs_extattr_entry *entry;
  200         const char *attr_name;
  201         int name_len;
  202         int error;
  203 
  204         fs = ip->i_e2fs;
  205 
  206         if ((error = bread(ip->i_devvp,
  207             fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
  208             (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
  209                 brelse(bp);
  210                 return (error);
  211         }
  212 
  213         struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
  214             ((char *)bp->b_data +
  215             EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
  216 
  217         /* Check attributes magic value */
  218         header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
  219             E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize);
  220 
  221         if (header->h_magic != EXTATTR_MAGIC) {
  222                 brelse(bp);
  223                 return (0);
  224         }
  225 
  226         error = ext2_extattr_check(EXT2_IFIRST(header),
  227             (char *)dinode + EXT2_INODE_SIZE(fs));
  228         if (error) {
  229                 brelse(bp);
  230                 return (error);
  231         }
  232 
  233         for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
  234             entry = EXT2_EXTATTR_NEXT(entry)) {
  235                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  236                     attrnamespace)
  237                         continue;
  238 
  239                 name_len = entry->e_name_len;
  240                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  241                     entry->e_name, &name_len);
  242                 if (!attr_name) {
  243                         brelse(bp);
  244                         return (ENOTSUP);
  245                 }
  246 
  247                 if (size != NULL)
  248                         *size += name_len + 1;
  249 
  250                 if (uio != NULL) {
  251                         char *name = malloc(name_len + 1, M_TEMP, M_WAITOK);
  252                         name[0] = name_len;
  253                         memcpy(&name[1], attr_name, name_len);
  254                         error = uiomove(name, name_len + 1, uio);
  255                         free(name, M_TEMP);
  256                         if (error)
  257                                 break;
  258                 }
  259         }
  260 
  261         brelse(bp);
  262 
  263         return (error);
  264 }
  265 
  266 int
  267 ext2_extattr_block_list(struct inode *ip, int attrnamespace,
  268     struct uio *uio, size_t *size)
  269 {
  270         struct m_ext2fs *fs;
  271         struct buf *bp;
  272         struct ext2fs_extattr_header *header;
  273         struct ext2fs_extattr_entry *entry;
  274         const char *attr_name;
  275         int name_len;
  276         int error;
  277 
  278         fs = ip->i_e2fs;
  279 
  280         error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
  281             fs->e2fs_bsize, NOCRED, &bp);
  282         if (error) {
  283                 brelse(bp);
  284                 return (error);
  285         }
  286 
  287         /* Check attributes magic value */
  288         header = EXT2_HDR(bp);
  289         if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
  290                 brelse(bp);
  291                 return (EINVAL);
  292         }
  293 
  294         error = ext2_extattr_block_check(ip, bp);
  295         if (error) {
  296                 brelse(bp);
  297                 return (error);
  298         }
  299 
  300         for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
  301             entry = EXT2_EXTATTR_NEXT(entry)) {
  302                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  303                     attrnamespace)
  304                         continue;
  305 
  306                 name_len = entry->e_name_len;
  307                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  308                     entry->e_name, &name_len);
  309                 if (!attr_name) {
  310                         brelse(bp);
  311                         return (ENOTSUP);
  312                 }
  313 
  314                 if (size != NULL)
  315                         *size += name_len + 1;
  316 
  317                 if (uio != NULL) {
  318                         char *name = malloc(name_len + 1, M_TEMP, M_WAITOK);
  319                         name[0] = name_len;
  320                         memcpy(&name[1], attr_name, name_len);
  321                         error = uiomove(name, name_len + 1, uio);
  322                         free(name, M_TEMP);
  323                         if (error)
  324                                 break;
  325                 }
  326         }
  327 
  328         brelse(bp);
  329 
  330         return (error);
  331 }
  332 
  333 int
  334 ext2_extattr_inode_get(struct inode *ip, int attrnamespace,
  335     const char *name, struct uio *uio, size_t *size)
  336 {
  337         struct m_ext2fs *fs;
  338         struct buf *bp;
  339         struct ext2fs_extattr_dinode_header *header;
  340         struct ext2fs_extattr_entry *entry;
  341         const char *attr_name;
  342         int name_len;
  343         int error;
  344 
  345         fs = ip->i_e2fs;
  346 
  347         if ((error = bread(ip->i_devvp,
  348             fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
  349             (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
  350                 brelse(bp);
  351                 return (error);
  352         }
  353 
  354         struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
  355             ((char *)bp->b_data +
  356             EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
  357 
  358         /* Check attributes magic value */
  359         header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
  360             E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize);
  361 
  362         if (header->h_magic != EXTATTR_MAGIC) {
  363                 brelse(bp);
  364                 return (ENOATTR);
  365         }
  366 
  367         error = ext2_extattr_check(EXT2_IFIRST(header),
  368             (char *)dinode + EXT2_INODE_SIZE(fs));
  369         if (error) {
  370                 brelse(bp);
  371                 return (error);
  372         }
  373 
  374         for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
  375             entry = EXT2_EXTATTR_NEXT(entry)) {
  376                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  377                     attrnamespace)
  378                         continue;
  379 
  380                 name_len = entry->e_name_len;
  381                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  382                     entry->e_name, &name_len);
  383                 if (!attr_name) {
  384                         brelse(bp);
  385                         return (ENOTSUP);
  386                 }
  387 
  388                 if (strlen(name) == name_len &&
  389                     0 == strncmp(attr_name, name, name_len)) {
  390                         if (size != NULL)
  391                                 *size += entry->e_value_size;
  392 
  393                         if (uio != NULL)
  394                                 error = uiomove(((char *)EXT2_IFIRST(header)) +
  395                                     entry->e_value_offs, entry->e_value_size, uio);
  396 
  397                         brelse(bp);
  398                         return (error);
  399                 }
  400          }
  401 
  402         brelse(bp);
  403 
  404         return (ENOATTR);
  405 }
  406 
  407 int
  408 ext2_extattr_block_get(struct inode *ip, int attrnamespace,
  409     const char *name, struct uio *uio, size_t *size)
  410 {
  411         struct m_ext2fs *fs;
  412         struct buf *bp;
  413         struct ext2fs_extattr_header *header;
  414         struct ext2fs_extattr_entry *entry;
  415         const char *attr_name;
  416         int name_len;
  417         int error;
  418 
  419         fs = ip->i_e2fs;
  420 
  421         error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
  422             fs->e2fs_bsize, NOCRED, &bp);
  423         if (error) {
  424                 brelse(bp);
  425                 return (error);
  426         }
  427 
  428         /* Check attributes magic value */
  429         header = EXT2_HDR(bp);
  430         if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
  431                 brelse(bp);
  432                 return (EINVAL);
  433         }
  434 
  435         error = ext2_extattr_block_check(ip, bp);
  436         if (error) {
  437                 brelse(bp);
  438                 return (error);
  439         }
  440 
  441         for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
  442             entry = EXT2_EXTATTR_NEXT(entry)) {
  443                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  444                     attrnamespace)
  445                         continue;
  446 
  447                 name_len = entry->e_name_len;
  448                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  449                     entry->e_name, &name_len);
  450                 if (!attr_name) {
  451                         brelse(bp);
  452                         return (ENOTSUP);
  453                 }
  454 
  455                 if (strlen(name) == name_len &&
  456                     0 == strncmp(attr_name, name, name_len)) {
  457                         if (size != NULL)
  458                                 *size += entry->e_value_size;
  459 
  460                         if (uio != NULL)
  461                                 error = uiomove(bp->b_data + entry->e_value_offs,
  462                                     entry->e_value_size, uio);
  463 
  464                         brelse(bp);
  465                         return (error);
  466                 }
  467          }
  468 
  469         brelse(bp);
  470 
  471         return (ENOATTR);
  472 }
  473 
  474 static uint16_t
  475 ext2_extattr_delete_value(char *off,
  476     struct ext2fs_extattr_entry *first_entry,
  477     struct ext2fs_extattr_entry *entry, char *end)
  478 {
  479         uint16_t min_offs;
  480         struct ext2fs_extattr_entry *next;
  481 
  482         min_offs = end - off;
  483         next = first_entry;
  484         while (!EXT2_IS_LAST_ENTRY(next)) {
  485                 if (min_offs > next->e_value_offs && next->e_value_offs > 0)
  486                         min_offs = next->e_value_offs;
  487 
  488                 next = EXT2_EXTATTR_NEXT(next);
  489         }
  490 
  491         if (entry->e_value_size == 0)
  492                 return (min_offs);
  493 
  494         memmove(off + min_offs + EXT2_EXTATTR_SIZE(entry->e_value_size),
  495             off + min_offs, entry->e_value_offs - min_offs);
  496 
  497         /* Adjust all value offsets */
  498         next = first_entry;
  499         while (!EXT2_IS_LAST_ENTRY(next))
  500         {
  501                 if (next->e_value_offs > 0 &&
  502                     next->e_value_offs < entry->e_value_offs)
  503                         next->e_value_offs +=
  504                             EXT2_EXTATTR_SIZE(entry->e_value_size);
  505 
  506                 next = EXT2_EXTATTR_NEXT(next);
  507         }
  508 
  509         min_offs += EXT2_EXTATTR_SIZE(entry->e_value_size);
  510 
  511         return (min_offs);
  512 }
  513 
  514 static void
  515 ext2_extattr_delete_entry(char *off,
  516     struct ext2fs_extattr_entry *first_entry,
  517     struct ext2fs_extattr_entry *entry, char *end)
  518 {
  519         char *pad;
  520         struct ext2fs_extattr_entry *next;
  521 
  522         /* Clean entry value */
  523         ext2_extattr_delete_value(off, first_entry, entry, end);
  524 
  525         /* Clean the entry */
  526         next = first_entry;
  527         while (!EXT2_IS_LAST_ENTRY(next))
  528                 next = EXT2_EXTATTR_NEXT(next);
  529 
  530         pad = (char*)next + sizeof(uint32_t);
  531 
  532         memmove(entry, (char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len),
  533             pad - ((char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len)));
  534 }
  535 
  536 int
  537 ext2_extattr_inode_delete(struct inode *ip, int attrnamespace, const char *name)
  538 {
  539         struct m_ext2fs *fs;
  540         struct buf *bp;
  541         struct ext2fs_extattr_dinode_header *header;
  542         struct ext2fs_extattr_entry *entry;
  543         const char *attr_name;
  544         int name_len;
  545         int error;
  546 
  547         fs = ip->i_e2fs;
  548 
  549         if ((error = bread(ip->i_devvp,
  550             fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
  551             (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
  552                 brelse(bp);
  553                 return (error);
  554         }
  555 
  556         struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
  557             ((char *)bp->b_data +
  558             EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
  559 
  560         /* Check attributes magic value */
  561         header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
  562             E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize);
  563 
  564         if (header->h_magic != EXTATTR_MAGIC) {
  565                 brelse(bp);
  566                 return (ENOATTR);
  567         }
  568 
  569         error = ext2_extattr_check(EXT2_IFIRST(header),
  570             (char *)dinode + EXT2_INODE_SIZE(fs));
  571         if (error) {
  572                 brelse(bp);
  573                 return (error);
  574         }
  575 
  576         /* If I am last entry, just make magic zero */
  577         entry = EXT2_IFIRST(header);
  578         if ((EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry))) &&
  579             (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) ==
  580             attrnamespace)) {
  581 
  582                 name_len = entry->e_name_len;
  583                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  584                     entry->e_name, &name_len);
  585                 if (!attr_name) {
  586                         brelse(bp);
  587                         return (ENOTSUP);
  588                 }
  589 
  590                 if (strlen(name) == name_len &&
  591                     0 == strncmp(attr_name, name, name_len)) {
  592                         memset(header, 0, sizeof(struct ext2fs_extattr_dinode_header));
  593 
  594                         return (bwrite(bp));
  595                 }
  596         }
  597 
  598         for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
  599             entry = EXT2_EXTATTR_NEXT(entry)) {
  600                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  601                     attrnamespace)
  602                         continue;
  603 
  604                 name_len = entry->e_name_len;
  605                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  606                     entry->e_name, &name_len);
  607                 if (!attr_name) {
  608                         brelse(bp);
  609                         return (ENOTSUP);
  610                 }
  611 
  612                 if (strlen(name) == name_len &&
  613                     0 == strncmp(attr_name, name, name_len)) {
  614                         ext2_extattr_delete_entry((char *)EXT2_IFIRST(header),
  615                             EXT2_IFIRST(header), entry,
  616                             (char *)dinode + EXT2_INODE_SIZE(fs));
  617 
  618                         return (bwrite(bp));
  619                 }
  620         }
  621 
  622         brelse(bp);
  623 
  624         return (ENOATTR);
  625 }
  626 
  627 static int
  628 ext2_extattr_block_clone(struct inode *ip, struct buf **bpp)
  629 {
  630         struct m_ext2fs *fs;
  631         struct buf *sbp;
  632         struct buf *cbp;
  633         struct ext2fs_extattr_header *header;
  634         uint64_t facl;
  635 
  636         fs = ip->i_e2fs;
  637         sbp = *bpp;
  638 
  639         header = EXT2_HDR(sbp);
  640         if (header->h_magic != EXTATTR_MAGIC || header->h_refcount == 1)
  641                 return (EINVAL);
  642 
  643         facl = ext2_alloc_meta(ip);
  644         if (!facl)
  645                 return (ENOSPC);
  646 
  647         cbp = getblk(ip->i_devvp, fsbtodb(fs, facl), fs->e2fs_bsize, 0, 0, 0);
  648         if (!cbp) {
  649                 ext2_blkfree(ip, facl, fs->e2fs_bsize);
  650                 return (EIO);
  651         }
  652 
  653         memcpy(cbp->b_data, sbp->b_data, fs->e2fs_bsize);
  654         header->h_refcount--;
  655         bwrite(sbp);
  656 
  657         ip->i_facl = facl;
  658         ext2_update(ip->i_vnode, 1);
  659 
  660         header = EXT2_HDR(cbp);
  661         header->h_refcount = 1;
  662 
  663         *bpp = cbp;
  664 
  665         return (0);
  666 }
  667 
  668 int
  669 ext2_extattr_block_delete(struct inode *ip, int attrnamespace, const char *name)
  670 {
  671         struct m_ext2fs *fs;
  672         struct buf *bp;
  673         struct ext2fs_extattr_header *header;
  674         struct ext2fs_extattr_entry *entry;
  675         const char *attr_name;
  676         int name_len;
  677         int error;
  678 
  679         fs = ip->i_e2fs;
  680 
  681         error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
  682             fs->e2fs_bsize, NOCRED, &bp);
  683         if (error) {
  684                 brelse(bp);
  685                 return (error);
  686         }
  687 
  688         /* Check attributes magic value */
  689         header = EXT2_HDR(bp);
  690         if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
  691                 brelse(bp);
  692                 return (EINVAL);
  693         }
  694 
  695         error = ext2_extattr_block_check(ip, bp);
  696         if (error) {
  697                 brelse(bp);
  698                 return (error);
  699         }
  700 
  701         if (header->h_refcount > 1) {
  702                 error = ext2_extattr_block_clone(ip, &bp);
  703                 if (error) {
  704                         brelse(bp);
  705                         return (error);
  706                 }
  707         }
  708 
  709         /* If I am last entry, clean me and free the block */
  710         entry = EXT2_FIRST_ENTRY(bp);
  711         if (EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry)) &&
  712             (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) ==
  713             attrnamespace)) {
  714 
  715                 name_len = entry->e_name_len;
  716                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  717                     entry->e_name, &name_len);
  718                 if (!attr_name) {
  719                         brelse(bp);
  720                         return (ENOTSUP);
  721                 }
  722 
  723                 if (strlen(name) == name_len &&
  724                     0 == strncmp(attr_name, name, name_len)) {
  725                         ip->i_blocks -= btodb(fs->e2fs_bsize);
  726                         ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize);
  727                         ip->i_facl = 0;
  728                         error = ext2_update(ip->i_vnode, 1);
  729 
  730                         brelse(bp);
  731                         return (error);
  732                 }
  733         }
  734 
  735         for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
  736             entry = EXT2_EXTATTR_NEXT(entry)) {
  737                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  738                     attrnamespace)
  739                         continue;
  740 
  741                 name_len = entry->e_name_len;
  742                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  743                     entry->e_name, &name_len);
  744                 if (!attr_name) {
  745                         brelse(bp);
  746                         return (ENOTSUP);
  747                 }
  748 
  749                 if (strlen(name) == name_len &&
  750                     0 == strncmp(attr_name, name, name_len)) {
  751                         ext2_extattr_delete_entry(bp->b_data,
  752                             EXT2_FIRST_ENTRY(bp), entry,
  753                             bp->b_data + bp->b_bufsize);
  754 
  755                         return (bwrite(bp));
  756                 }
  757         }
  758 
  759         brelse(bp);
  760 
  761         return (ENOATTR);
  762 }
  763 
  764 static struct ext2fs_extattr_entry *
  765 allocate_entry(const char *name, int attrnamespace, uint16_t offs,
  766     uint32_t size, uint32_t hash)
  767 {
  768         const char *attr_name;
  769         int name_len;
  770         struct ext2fs_extattr_entry *entry;
  771 
  772         attr_name = ext2_extattr_name_to_linux(attrnamespace, name);
  773         name_len = strlen(attr_name);
  774 
  775         entry = malloc(sizeof(struct ext2fs_extattr_entry) + name_len,
  776             M_TEMP, M_WAITOK);
  777 
  778         entry->e_name_len = name_len;
  779         entry->e_name_index = ext2_extattr_attrnamespace_to_linux(attrnamespace, name);
  780         entry->e_value_offs = offs;
  781         entry->e_value_block = 0;
  782         entry->e_value_size = size;
  783         entry->e_hash = hash;
  784         memcpy(entry->e_name, name, name_len);
  785 
  786         return (entry);
  787 }
  788 
  789 static void
  790 free_entry(struct ext2fs_extattr_entry *entry)
  791 {
  792 
  793         free(entry, M_TEMP);
  794 }
  795 
  796 static int
  797 ext2_extattr_get_size(struct ext2fs_extattr_entry *first_entry,
  798     struct ext2fs_extattr_entry *exist_entry, int header_size,
  799     int name_len, int new_size)
  800 {
  801         struct ext2fs_extattr_entry *entry;
  802         int size;
  803 
  804         size = header_size;
  805         size += sizeof(uint32_t);
  806 
  807         if (NULL == exist_entry) {
  808                 size += EXT2_EXTATTR_LEN(name_len);
  809                 size += EXT2_EXTATTR_SIZE(new_size);
  810         }
  811 
  812         if (first_entry)
  813                 for (entry = first_entry; !EXT2_IS_LAST_ENTRY(entry);
  814                     entry = EXT2_EXTATTR_NEXT(entry)) {
  815                         if (entry != exist_entry)
  816                                 size += EXT2_EXTATTR_LEN(entry->e_name_len) +
  817                                     EXT2_EXTATTR_SIZE(entry->e_value_size);
  818                         else
  819                                 size += EXT2_EXTATTR_LEN(entry->e_name_len) +
  820                                     EXT2_EXTATTR_SIZE(new_size);
  821                 }
  822 
  823         return (size);
  824 }
  825 
  826 static void
  827 ext2_extattr_set_exist_entry(char *off,
  828     struct ext2fs_extattr_entry *first_entry,
  829     struct ext2fs_extattr_entry *entry,
  830     char *end, struct uio *uio)
  831 {
  832         uint16_t min_offs;
  833 
  834         min_offs = ext2_extattr_delete_value(off, first_entry, entry, end);
  835 
  836         entry->e_value_size = uio->uio_resid;
  837         if (entry->e_value_size)
  838                 entry->e_value_offs = min_offs -
  839                     EXT2_EXTATTR_SIZE(uio->uio_resid);
  840         else
  841                 entry->e_value_offs = 0;
  842 
  843         uiomove(off + entry->e_value_offs, entry->e_value_size, uio);
  844 }
  845 
  846 static struct ext2fs_extattr_entry *
  847 ext2_extattr_set_new_entry(char *off, struct ext2fs_extattr_entry *first_entry,
  848     const char *name, int attrnamespace, char *end, struct uio *uio)
  849 {
  850         int name_len;
  851         char *pad;
  852         uint16_t min_offs;
  853         struct ext2fs_extattr_entry *entry;
  854         struct ext2fs_extattr_entry *new_entry;
  855 
  856         /* Find pad's */
  857         min_offs = end - off;
  858         entry = first_entry;
  859         while (!EXT2_IS_LAST_ENTRY(entry)) {
  860                 if (min_offs > entry->e_value_offs && entry->e_value_offs > 0)
  861                         min_offs = entry->e_value_offs;
  862 
  863                 entry = EXT2_EXTATTR_NEXT(entry);
  864         }
  865 
  866         pad = (char*)entry + sizeof(uint32_t);
  867 
  868         /* Find entry insert position */
  869         name_len = strlen(name);
  870         entry = first_entry;
  871         while (!EXT2_IS_LAST_ENTRY(entry)) {
  872                 if (!(attrnamespace - entry->e_name_index) &&
  873                     !(name_len - entry->e_name_len))
  874                         if (memcmp(name, entry->e_name, name_len) <= 0)
  875                                 break;
  876 
  877                 entry = EXT2_EXTATTR_NEXT(entry);
  878         }
  879 
  880         /* Create new entry and insert it */
  881         new_entry = allocate_entry(name, attrnamespace, 0, uio->uio_resid, 0);
  882         memmove((char *)entry + EXT2_EXTATTR_LEN(new_entry->e_name_len), entry,
  883             pad - (char*)entry);
  884 
  885         memcpy(entry, new_entry, EXT2_EXTATTR_LEN(new_entry->e_name_len));
  886         free_entry(new_entry);
  887 
  888         new_entry = entry;
  889         if (new_entry->e_value_size > 0)
  890                 new_entry->e_value_offs = min_offs -
  891                     EXT2_EXTATTR_SIZE(new_entry->e_value_size);
  892 
  893         uiomove(off + new_entry->e_value_offs, new_entry->e_value_size, uio);
  894 
  895         return (new_entry);
  896 }
  897 
  898 int
  899 ext2_extattr_inode_set(struct inode *ip, int attrnamespace,
  900     const char *name, struct uio *uio)
  901 {
  902         struct m_ext2fs *fs;
  903         struct buf *bp;
  904         struct ext2fs_extattr_dinode_header *header;
  905         struct ext2fs_extattr_entry *entry;
  906         const char *attr_name;
  907         int name_len;
  908         size_t size = 0, max_size;
  909         int error;
  910 
  911         fs = ip->i_e2fs;
  912 
  913         if ((error = bread(ip->i_devvp,
  914             fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
  915             (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
  916                 brelse(bp);
  917                 return (error);
  918         }
  919 
  920         struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
  921             ((char *)bp->b_data +
  922             EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
  923 
  924         /* Check attributes magic value */
  925         header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
  926             E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize);
  927 
  928         if (header->h_magic != EXTATTR_MAGIC) {
  929                 brelse(bp);
  930                 return (ENOSPC);
  931         }
  932 
  933         error = ext2_extattr_check(EXT2_IFIRST(header), (char *)dinode +
  934             EXT2_INODE_SIZE(fs));
  935         if (error) {
  936                 brelse(bp);
  937                 return (error);
  938         }
  939 
  940         /* Find if entry exist */
  941         for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
  942             entry = EXT2_EXTATTR_NEXT(entry)) {
  943                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  944                     attrnamespace)
  945                         continue;
  946 
  947                 name_len = entry->e_name_len;
  948                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  949                     entry->e_name, &name_len);
  950                 if (!attr_name) {
  951                         brelse(bp);
  952                         return (ENOTSUP);
  953                 }
  954 
  955                 if (strlen(name) == name_len &&
  956                     0 == strncmp(attr_name, name, name_len))
  957                         break;
  958         }
  959 
  960         max_size = EXT2_INODE_SIZE(fs) - E2FS_REV0_INODE_SIZE -
  961             dinode->e2di_extra_isize;
  962 
  963         if (!EXT2_IS_LAST_ENTRY(entry)) {
  964                 size = ext2_extattr_get_size(EXT2_IFIRST(header), entry,
  965                     sizeof(struct ext2fs_extattr_dinode_header),
  966                     entry->e_name_len, uio->uio_resid);
  967                 if (size > max_size) {
  968                         brelse(bp);
  969                         return (ENOSPC);
  970                 }
  971 
  972                 ext2_extattr_set_exist_entry((char *)EXT2_IFIRST(header),
  973                     EXT2_IFIRST(header), entry, (char *)header + max_size, uio);
  974         } else {
  975                 /* Ensure that the same entry does not exist in the block */
  976                 if (ip->i_facl) {
  977                         error = ext2_extattr_block_get(ip, attrnamespace, name,
  978                             NULL, &size);
  979                         if (error != ENOATTR || size > 0) {
  980                                 brelse(bp);
  981                                 if (size > 0)
  982                                         error = ENOSPC;
  983 
  984                                 return (error);
  985                         }
  986                 }
  987 
  988                 size = ext2_extattr_get_size(EXT2_IFIRST(header), NULL,
  989                     sizeof(struct ext2fs_extattr_dinode_header),
  990                     entry->e_name_len, uio->uio_resid);
  991                 if (size > max_size) {
  992                         brelse(bp);
  993                         return (ENOSPC);
  994                 }
  995 
  996                 ext2_extattr_set_new_entry((char *)EXT2_IFIRST(header),
  997                     EXT2_IFIRST(header), name, attrnamespace,
  998                     (char *)header + max_size, uio);
  999         }
 1000 
 1001         return (bwrite(bp));
 1002 }
 1003 
 1004 static void
 1005 ext2_extattr_hash_entry(struct ext2fs_extattr_header *header,
 1006     struct ext2fs_extattr_entry *entry)
 1007 {
 1008         uint32_t hash = 0;
 1009         char *name = entry->e_name;
 1010         int n;
 1011 
 1012         for (n=0; n < entry->e_name_len; n++) {
 1013                 hash = (hash << EXT2_EXTATTR_NAME_HASH_SHIFT) ^
 1014                     (hash >> (8*sizeof(hash) - EXT2_EXTATTR_NAME_HASH_SHIFT)) ^
 1015                     (*name++);
 1016         }
 1017 
 1018         if (entry->e_value_block == 0 && entry->e_value_size != 0) {
 1019                 uint32_t *value = (uint32_t *)((char *)header + entry->e_value_offs);
 1020                 for (n = (entry->e_value_size +
 1021                     EXT2_EXTATTR_ROUND) >> EXT2_EXTATTR_PAD_BITS; n; n--) {
 1022                         hash = (hash << EXT2_EXTATTR_VALUE_HASH_SHIFT) ^
 1023                             (hash >> (8*sizeof(hash) - EXT2_EXTATTR_VALUE_HASH_SHIFT)) ^
 1024                             (*value++);
 1025                 }
 1026         }
 1027 
 1028         entry->e_hash = hash;
 1029 }
 1030 
 1031 static void
 1032 ext2_extattr_rehash(struct ext2fs_extattr_header *header,
 1033     struct ext2fs_extattr_entry *entry)
 1034 {
 1035         struct ext2fs_extattr_entry *here;
 1036         uint32_t hash = 0;
 1037 
 1038         ext2_extattr_hash_entry(header, entry);
 1039 
 1040         here = EXT2_ENTRY(header+1);
 1041         while (!EXT2_IS_LAST_ENTRY(here)) {
 1042                 if (!here->e_hash) {
 1043                         /* Block is not shared if an entry's hash value == 0 */
 1044                         hash = 0;
 1045                         break;
 1046                 }
 1047 
 1048                 hash = (hash << EXT2_EXTATTR_BLOCK_HASH_SHIFT) ^
 1049                     (hash >> (8*sizeof(hash) - EXT2_EXTATTR_BLOCK_HASH_SHIFT)) ^
 1050                     here->e_hash;
 1051 
 1052                 here = EXT2_EXTATTR_NEXT(here);
 1053         }
 1054 
 1055         header->h_hash = hash;
 1056 }
 1057 
 1058 int
 1059 ext2_extattr_block_set(struct inode *ip, int attrnamespace,
 1060     const char *name, struct uio *uio)
 1061 {
 1062         struct m_ext2fs *fs;
 1063         struct buf *bp;
 1064         struct ext2fs_extattr_header *header;
 1065         struct ext2fs_extattr_entry *entry;
 1066         const char *attr_name;
 1067         int name_len;
 1068         size_t size;
 1069         int error;
 1070 
 1071         fs = ip->i_e2fs;
 1072 
 1073         if (ip->i_facl) {
 1074                 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
 1075                     fs->e2fs_bsize, NOCRED, &bp);
 1076                 if (error) {
 1077                         brelse(bp);
 1078                         return (error);
 1079                 }
 1080 
 1081                 /* Check attributes magic value */
 1082                 header = EXT2_HDR(bp);
 1083                 if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
 1084                         brelse(bp);
 1085                         return (EINVAL);
 1086                 }
 1087 
 1088                 error = ext2_extattr_block_check(ip, bp);
 1089                 if (error) {
 1090                         brelse(bp);
 1091                         return (error);
 1092                 }
 1093 
 1094                 if (header->h_refcount > 1) {
 1095                         error = ext2_extattr_block_clone(ip, &bp);
 1096                         if (error) {
 1097                                 brelse(bp);
 1098                                 return (error);
 1099                         }
 1100 
 1101                         header = EXT2_HDR(bp);
 1102                 }
 1103 
 1104                 /* Find if entry exist */
 1105                 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
 1106                     entry = EXT2_EXTATTR_NEXT(entry)) {
 1107                         if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
 1108                             attrnamespace)
 1109                                 continue;
 1110 
 1111                         name_len = entry->e_name_len;
 1112                         attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
 1113                             entry->e_name, &name_len);
 1114                         if (!attr_name) {
 1115                                 brelse(bp);
 1116                                 return (ENOTSUP);
 1117                         }
 1118 
 1119                         if (strlen(name) == name_len &&
 1120                             0 == strncmp(attr_name, name, name_len))
 1121                                 break;
 1122                 }
 1123 
 1124                 if (!EXT2_IS_LAST_ENTRY(entry)) {
 1125                         size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), entry,
 1126                             sizeof(struct ext2fs_extattr_header),
 1127                             entry->e_name_len, uio->uio_resid);
 1128                         if (size > bp->b_bufsize) {
 1129                                 brelse(bp);
 1130                                 return (ENOSPC);
 1131                         }
 1132 
 1133                         ext2_extattr_set_exist_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
 1134                             entry, bp->b_data + bp->b_bufsize, uio);
 1135                 } else {
 1136                         size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), NULL,
 1137                             sizeof(struct ext2fs_extattr_header),
 1138                             strlen(name), uio->uio_resid);
 1139                         if (size > bp->b_bufsize) {
 1140                                 brelse(bp);
 1141                                 return (ENOSPC);
 1142                         }
 1143 
 1144                         entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
 1145                             name, attrnamespace, bp->b_data + bp->b_bufsize, uio);
 1146 
 1147                         /* Clean the same entry in the inode */
 1148                         error = ext2_extattr_inode_delete(ip, attrnamespace, name);
 1149                         if (error && error != ENOATTR) {
 1150                                 brelse(bp);
 1151                                 return (error);
 1152                         }
 1153                 }
 1154 
 1155                 ext2_extattr_rehash(header, entry);
 1156                 ext2_extattr_blk_csum_set(ip, bp);
 1157 
 1158                 return (bwrite(bp));
 1159         }
 1160 
 1161         size = ext2_extattr_get_size(NULL, NULL,
 1162             sizeof(struct ext2fs_extattr_header),
 1163             strlen(ext2_extattr_name_to_linux(attrnamespace, name)), uio->uio_resid);
 1164         if (size > fs->e2fs_bsize)
 1165                 return (ENOSPC);
 1166 
 1167         /* Allocate block, fill EA header and insert entry */
 1168         ip->i_facl = ext2_alloc_meta(ip);
 1169         if (0 == ip->i_facl)
 1170                 return (ENOSPC);
 1171 
 1172         ip->i_blocks += btodb(fs->e2fs_bsize);
 1173         ext2_update(ip->i_vnode, 1);
 1174 
 1175         bp = getblk(ip->i_devvp, fsbtodb(fs, ip->i_facl), fs->e2fs_bsize, 0, 0, 0);
 1176         if (!bp) {
 1177                 ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize);
 1178                 ip->i_blocks -= btodb(fs->e2fs_bsize);
 1179                 ip->i_facl = 0;
 1180                 ext2_update(ip->i_vnode, 1);
 1181                 return (EIO);
 1182         }
 1183 
 1184         header = EXT2_HDR(bp);
 1185         header->h_magic = EXTATTR_MAGIC;
 1186         header->h_refcount = 1;
 1187         header->h_blocks = 1;
 1188         header->h_hash = 0;
 1189         memset(header->h_reserved, 0, sizeof(header->h_reserved));
 1190         memcpy(bp->b_data, header, sizeof(struct ext2fs_extattr_header));
 1191         memset(EXT2_FIRST_ENTRY(bp), 0, sizeof(uint32_t));
 1192 
 1193         entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
 1194             name, attrnamespace, bp->b_data + bp->b_bufsize, uio);
 1195 
 1196         /* Clean the same entry in the inode */
 1197         error = ext2_extattr_inode_delete(ip, attrnamespace, name);
 1198         if (error && error != ENOATTR) {
 1199                 brelse(bp);
 1200                 return (error);
 1201         }
 1202 
 1203         ext2_extattr_rehash(header, entry);
 1204         ext2_extattr_blk_csum_set(ip, bp);
 1205 
 1206         return (bwrite(bp));
 1207 }
 1208 
 1209 int ext2_extattr_free(struct inode *ip)
 1210 {
 1211         struct m_ext2fs *fs;
 1212         struct buf *bp;
 1213         struct ext2fs_extattr_header *header;
 1214         int error;
 1215 
 1216         fs = ip->i_e2fs;
 1217 
 1218         if (!ip->i_facl)
 1219                 return (0);
 1220 
 1221         error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
 1222             fs->e2fs_bsize, NOCRED, &bp);
 1223         if (error) {
 1224                 brelse(bp);
 1225                 return (error);
 1226         }
 1227 
 1228         /* Check attributes magic value */
 1229         header = EXT2_HDR(bp);
 1230         if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
 1231                 brelse(bp);
 1232                 return (EINVAL);
 1233         }
 1234 
 1235         error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp),
 1236             bp->b_data + bp->b_bufsize);
 1237         if (error) {
 1238                 brelse(bp);
 1239                 return (error);
 1240         }
 1241 
 1242         if (header->h_refcount > 1) {
 1243                 header->h_refcount--;
 1244                 bwrite(bp);
 1245         } else {
 1246                 ext2_blkfree(ip, ip->i_facl, ip->i_e2fs->e2fs_bsize);
 1247                 brelse(bp);
 1248         }
 1249 
 1250         ip->i_blocks -= btodb(ip->i_e2fs->e2fs_bsize);
 1251         ip->i_facl = 0;
 1252         ext2_update(ip->i_vnode, 1);
 1253 
 1254         return (0);
 1255 }

Cache object: 4b8f63a6a156ddf1a7fdbf2371d4c593


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