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 + le16toh(dinode->e2di_extra_isize));
  220 
  221         if (le32toh(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                 return (error);
  284         }
  285 
  286         /* Check attributes magic value */
  287         header = EXT2_HDR(bp);
  288         if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
  289             le32toh(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 + le16toh(dinode->e2di_extra_isize));
  361 
  362         if (le32toh(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 += le32toh(entry->e_value_size);
  392 
  393                         if (uio != NULL)
  394                                 error = uiomove(((char *)EXT2_IFIRST(header)) +
  395                                     le16toh(entry->e_value_offs),
  396                                     le32toh(entry->e_value_size), uio);
  397 
  398                         brelse(bp);
  399                         return (error);
  400                 }
  401          }
  402 
  403         brelse(bp);
  404 
  405         return (ENOATTR);
  406 }
  407 
  408 int
  409 ext2_extattr_block_get(struct inode *ip, int attrnamespace,
  410     const char *name, struct uio *uio, size_t *size)
  411 {
  412         struct m_ext2fs *fs;
  413         struct buf *bp;
  414         struct ext2fs_extattr_header *header;
  415         struct ext2fs_extattr_entry *entry;
  416         const char *attr_name;
  417         int name_len;
  418         int error;
  419 
  420         fs = ip->i_e2fs;
  421 
  422         error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
  423             fs->e2fs_bsize, NOCRED, &bp);
  424         if (error) {
  425                 return (error);
  426         }
  427 
  428         /* Check attributes magic value */
  429         header = EXT2_HDR(bp);
  430         if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
  431             le32toh(header->h_blocks) != 1) {
  432                 brelse(bp);
  433                 return (EINVAL);
  434         }
  435 
  436         error = ext2_extattr_block_check(ip, bp);
  437         if (error) {
  438                 brelse(bp);
  439                 return (error);
  440         }
  441 
  442         for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
  443             entry = EXT2_EXTATTR_NEXT(entry)) {
  444                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  445                     attrnamespace)
  446                         continue;
  447 
  448                 name_len = entry->e_name_len;
  449                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  450                     entry->e_name, &name_len);
  451                 if (!attr_name) {
  452                         brelse(bp);
  453                         return (ENOTSUP);
  454                 }
  455 
  456                 if (strlen(name) == name_len &&
  457                     0 == strncmp(attr_name, name, name_len)) {
  458                         if (size != NULL)
  459                                 *size += le32toh(entry->e_value_size);
  460 
  461                         if (uio != NULL)
  462                                 error = uiomove(bp->b_data +
  463                                     le16toh(entry->e_value_offs),
  464                                     le32toh(entry->e_value_size), uio);
  465 
  466                         brelse(bp);
  467                         return (error);
  468                 }
  469          }
  470 
  471         brelse(bp);
  472 
  473         return (ENOATTR);
  474 }
  475 
  476 static uint16_t
  477 ext2_extattr_delete_value(char *off,
  478     struct ext2fs_extattr_entry *first_entry,
  479     struct ext2fs_extattr_entry *entry, char *end)
  480 {
  481         uint16_t min_offs;
  482         struct ext2fs_extattr_entry *next;
  483 
  484         min_offs = end - off;
  485         next = first_entry;
  486         while (!EXT2_IS_LAST_ENTRY(next)) {
  487                 if (min_offs > le16toh(next->e_value_offs) &&
  488                     le16toh(next->e_value_offs) > 0)
  489                         min_offs = le16toh(next->e_value_offs);
  490 
  491                 next = EXT2_EXTATTR_NEXT(next);
  492         }
  493 
  494         if (entry->e_value_size == 0)
  495                 return (min_offs);
  496 
  497         memmove(off + min_offs + EXT2_EXTATTR_SIZE(le32toh(entry->e_value_size)),
  498             off + min_offs, le16toh(entry->e_value_offs) - min_offs);
  499 
  500         /* Adjust all value offsets */
  501         next = first_entry;
  502         while (!EXT2_IS_LAST_ENTRY(next))
  503         {
  504                 if (le16toh(next->e_value_offs) > 0 &&
  505                     le16toh(next->e_value_offs) < le16toh(entry->e_value_offs))
  506                         next->e_value_offs = htole16(le16toh(next->e_value_offs) +
  507                             EXT2_EXTATTR_SIZE(le32toh(entry->e_value_size)));
  508 
  509                 next = EXT2_EXTATTR_NEXT(next);
  510         }
  511 
  512         min_offs += EXT2_EXTATTR_SIZE(le32toh(entry->e_value_size));
  513 
  514         return (min_offs);
  515 }
  516 
  517 static void
  518 ext2_extattr_delete_entry(char *off,
  519     struct ext2fs_extattr_entry *first_entry,
  520     struct ext2fs_extattr_entry *entry, char *end)
  521 {
  522         char *pad;
  523         struct ext2fs_extattr_entry *next;
  524 
  525         /* Clean entry value */
  526         ext2_extattr_delete_value(off, first_entry, entry, end);
  527 
  528         /* Clean the entry */
  529         next = first_entry;
  530         while (!EXT2_IS_LAST_ENTRY(next))
  531                 next = EXT2_EXTATTR_NEXT(next);
  532 
  533         pad = (char*)next + sizeof(uint32_t);
  534 
  535         memmove(entry, (char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len),
  536             pad - ((char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len)));
  537 }
  538 
  539 int
  540 ext2_extattr_inode_delete(struct inode *ip, int attrnamespace, const char *name)
  541 {
  542         struct m_ext2fs *fs;
  543         struct buf *bp;
  544         struct ext2fs_extattr_dinode_header *header;
  545         struct ext2fs_extattr_entry *entry;
  546         const char *attr_name;
  547         int name_len;
  548         int error;
  549 
  550         fs = ip->i_e2fs;
  551 
  552         if ((error = bread(ip->i_devvp,
  553             fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
  554             (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
  555                 brelse(bp);
  556                 return (error);
  557         }
  558 
  559         struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
  560             ((char *)bp->b_data +
  561             EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
  562 
  563         /* Check attributes magic value */
  564         header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
  565             E2FS_REV0_INODE_SIZE + le16toh(dinode->e2di_extra_isize));
  566 
  567         if (le32toh(header->h_magic) != EXTATTR_MAGIC) {
  568                 brelse(bp);
  569                 return (ENOATTR);
  570         }
  571 
  572         error = ext2_extattr_check(EXT2_IFIRST(header),
  573             (char *)dinode + EXT2_INODE_SIZE(fs));
  574         if (error) {
  575                 brelse(bp);
  576                 return (error);
  577         }
  578 
  579         /* If I am last entry, just make magic zero */
  580         entry = EXT2_IFIRST(header);
  581         if ((EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry))) &&
  582             (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) ==
  583             attrnamespace)) {
  584                 name_len = entry->e_name_len;
  585                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  586                     entry->e_name, &name_len);
  587                 if (!attr_name) {
  588                         brelse(bp);
  589                         return (ENOTSUP);
  590                 }
  591 
  592                 if (strlen(name) == name_len &&
  593                     0 == strncmp(attr_name, name, name_len)) {
  594                         memset(header, 0, sizeof(struct ext2fs_extattr_dinode_header));
  595 
  596                         return (bwrite(bp));
  597                 }
  598         }
  599 
  600         for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
  601             entry = EXT2_EXTATTR_NEXT(entry)) {
  602                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  603                     attrnamespace)
  604                         continue;
  605 
  606                 name_len = entry->e_name_len;
  607                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  608                     entry->e_name, &name_len);
  609                 if (!attr_name) {
  610                         brelse(bp);
  611                         return (ENOTSUP);
  612                 }
  613 
  614                 if (strlen(name) == name_len &&
  615                     0 == strncmp(attr_name, name, name_len)) {
  616                         ext2_extattr_delete_entry((char *)EXT2_IFIRST(header),
  617                             EXT2_IFIRST(header), entry,
  618                             (char *)dinode + EXT2_INODE_SIZE(fs));
  619 
  620                         return (bwrite(bp));
  621                 }
  622         }
  623 
  624         brelse(bp);
  625 
  626         return (ENOATTR);
  627 }
  628 
  629 static int
  630 ext2_extattr_block_clone(struct inode *ip, struct buf **bpp)
  631 {
  632         struct m_ext2fs *fs;
  633         struct buf *sbp;
  634         struct buf *cbp;
  635         struct ext2fs_extattr_header *header;
  636         uint64_t facl;
  637 
  638         fs = ip->i_e2fs;
  639         sbp = *bpp;
  640 
  641         header = EXT2_HDR(sbp);
  642         if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
  643             le32toh(header->h_refcount) == 1)
  644                 return (EINVAL);
  645 
  646         facl = ext2_alloc_meta(ip);
  647         if (!facl)
  648                 return (ENOSPC);
  649 
  650         cbp = getblk(ip->i_devvp, fsbtodb(fs, facl), fs->e2fs_bsize, 0, 0, 0);
  651         if (!cbp) {
  652                 ext2_blkfree(ip, facl, fs->e2fs_bsize);
  653                 return (EIO);
  654         }
  655 
  656         memcpy(cbp->b_data, sbp->b_data, fs->e2fs_bsize);
  657         header->h_refcount = htole32(le32toh(header->h_refcount) - 1);
  658         bwrite(sbp);
  659 
  660         ip->i_facl = facl;
  661         ext2_update(ip->i_vnode, 1);
  662 
  663         header = EXT2_HDR(cbp);
  664         header->h_refcount = htole32(1);
  665 
  666         *bpp = cbp;
  667 
  668         return (0);
  669 }
  670 
  671 int
  672 ext2_extattr_block_delete(struct inode *ip, int attrnamespace, const char *name)
  673 {
  674         struct m_ext2fs *fs;
  675         struct buf *bp;
  676         struct ext2fs_extattr_header *header;
  677         struct ext2fs_extattr_entry *entry;
  678         const char *attr_name;
  679         int name_len;
  680         int error;
  681 
  682         fs = ip->i_e2fs;
  683 
  684         error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
  685             fs->e2fs_bsize, NOCRED, &bp);
  686         if (error) {
  687                 return (error);
  688         }
  689 
  690         /* Check attributes magic value */
  691         header = EXT2_HDR(bp);
  692         if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
  693             le32toh(header->h_blocks) != 1) {
  694                 brelse(bp);
  695                 return (EINVAL);
  696         }
  697 
  698         error = ext2_extattr_block_check(ip, bp);
  699         if (error) {
  700                 brelse(bp);
  701                 return (error);
  702         }
  703 
  704         if (le32toh(header->h_refcount) > 1) {
  705                 error = ext2_extattr_block_clone(ip, &bp);
  706                 if (error) {
  707                         brelse(bp);
  708                         return (error);
  709                 }
  710         }
  711 
  712         /* If I am last entry, clean me and free the block */
  713         entry = EXT2_FIRST_ENTRY(bp);
  714         if (EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry)) &&
  715             (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) ==
  716             attrnamespace)) {
  717                 name_len = entry->e_name_len;
  718                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  719                     entry->e_name, &name_len);
  720                 if (!attr_name) {
  721                         brelse(bp);
  722                         return (ENOTSUP);
  723                 }
  724 
  725                 if (strlen(name) == name_len &&
  726                     0 == strncmp(attr_name, name, name_len)) {
  727                         ip->i_blocks -= btodb(fs->e2fs_bsize);
  728                         ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize);
  729                         ip->i_facl = 0;
  730                         error = ext2_update(ip->i_vnode, 1);
  731 
  732                         brelse(bp);
  733                         return (error);
  734                 }
  735         }
  736 
  737         for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
  738             entry = EXT2_EXTATTR_NEXT(entry)) {
  739                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  740                     attrnamespace)
  741                         continue;
  742 
  743                 name_len = entry->e_name_len;
  744                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  745                     entry->e_name, &name_len);
  746                 if (!attr_name) {
  747                         brelse(bp);
  748                         return (ENOTSUP);
  749                 }
  750 
  751                 if (strlen(name) == name_len &&
  752                     0 == strncmp(attr_name, name, name_len)) {
  753                         ext2_extattr_delete_entry(bp->b_data,
  754                             EXT2_FIRST_ENTRY(bp), entry,
  755                             bp->b_data + bp->b_bufsize);
  756 
  757                         return (bwrite(bp));
  758                 }
  759         }
  760 
  761         brelse(bp);
  762 
  763         return (ENOATTR);
  764 }
  765 
  766 static struct ext2fs_extattr_entry *
  767 allocate_entry(const char *name, int attrnamespace, uint16_t offs,
  768     uint32_t size, uint32_t hash)
  769 {
  770         const char *attr_name;
  771         int name_len;
  772         struct ext2fs_extattr_entry *entry;
  773 
  774         attr_name = ext2_extattr_name_to_linux(attrnamespace, name);
  775         name_len = strlen(attr_name);
  776 
  777         entry = malloc(sizeof(struct ext2fs_extattr_entry) + name_len,
  778             M_TEMP, M_WAITOK);
  779 
  780         entry->e_name_len = name_len;
  781         entry->e_name_index = ext2_extattr_attrnamespace_to_linux(attrnamespace, name);
  782         entry->e_value_offs = htole16(offs);
  783         entry->e_value_block = 0;
  784         entry->e_value_size = htole32(size);
  785         entry->e_hash = htole32(hash);
  786         memcpy(entry->e_name, name, name_len);
  787 
  788         return (entry);
  789 }
  790 
  791 static void
  792 free_entry(struct ext2fs_extattr_entry *entry)
  793 {
  794 
  795         free(entry, M_TEMP);
  796 }
  797 
  798 static int
  799 ext2_extattr_get_size(struct ext2fs_extattr_entry *first_entry,
  800     struct ext2fs_extattr_entry *exist_entry, int header_size,
  801     int name_len, int new_size)
  802 {
  803         struct ext2fs_extattr_entry *entry;
  804         int size;
  805 
  806         size = header_size;
  807         size += sizeof(uint32_t);
  808 
  809         if (NULL == exist_entry) {
  810                 size += EXT2_EXTATTR_LEN(name_len);
  811                 size += EXT2_EXTATTR_SIZE(new_size);
  812         }
  813 
  814         if (first_entry)
  815                 for (entry = first_entry; !EXT2_IS_LAST_ENTRY(entry);
  816                     entry = EXT2_EXTATTR_NEXT(entry)) {
  817                         if (entry != exist_entry)
  818                                 size += EXT2_EXTATTR_LEN(entry->e_name_len) +
  819                                     EXT2_EXTATTR_SIZE(le32toh(entry->e_value_size));
  820                         else
  821                                 size += EXT2_EXTATTR_LEN(entry->e_name_len) +
  822                                     EXT2_EXTATTR_SIZE(new_size);
  823                 }
  824 
  825         return (size);
  826 }
  827 
  828 static void
  829 ext2_extattr_set_exist_entry(char *off,
  830     struct ext2fs_extattr_entry *first_entry,
  831     struct ext2fs_extattr_entry *entry,
  832     char *end, struct uio *uio)
  833 {
  834         uint16_t min_offs;
  835 
  836         min_offs = ext2_extattr_delete_value(off, first_entry, entry, end);
  837 
  838         entry->e_value_size = htole32(uio->uio_resid);
  839         if (le32toh(entry->e_value_size))
  840                 entry->e_value_offs = htole16(min_offs -
  841                     EXT2_EXTATTR_SIZE(uio->uio_resid));
  842         else
  843                 entry->e_value_offs = 0;
  844 
  845         uiomove(off + le16toh(entry->e_value_offs),
  846             le32toh(entry->e_value_size), uio);
  847 }
  848 
  849 static struct ext2fs_extattr_entry *
  850 ext2_extattr_set_new_entry(char *off, struct ext2fs_extattr_entry *first_entry,
  851     const char *name, int attrnamespace, char *end, struct uio *uio)
  852 {
  853         int name_len;
  854         char *pad;
  855         uint16_t min_offs;
  856         struct ext2fs_extattr_entry *entry;
  857         struct ext2fs_extattr_entry *new_entry;
  858 
  859         /* Find pad's */
  860         min_offs = end - off;
  861         entry = first_entry;
  862         while (!EXT2_IS_LAST_ENTRY(entry)) {
  863                 if (min_offs > le16toh(entry->e_value_offs) &&
  864                     le16toh(entry->e_value_offs) > 0)
  865                         min_offs = le16toh(entry->e_value_offs);
  866 
  867                 entry = EXT2_EXTATTR_NEXT(entry);
  868         }
  869 
  870         pad = (char*)entry + sizeof(uint32_t);
  871 
  872         /* Find entry insert position */
  873         name_len = strlen(name);
  874         entry = first_entry;
  875         while (!EXT2_IS_LAST_ENTRY(entry)) {
  876                 if (!(attrnamespace - entry->e_name_index) &&
  877                     !(name_len - entry->e_name_len))
  878                         if (memcmp(name, entry->e_name, name_len) <= 0)
  879                                 break;
  880 
  881                 entry = EXT2_EXTATTR_NEXT(entry);
  882         }
  883 
  884         /* Create new entry and insert it */
  885         new_entry = allocate_entry(name, attrnamespace, 0, uio->uio_resid, 0);
  886         memmove((char *)entry + EXT2_EXTATTR_LEN(new_entry->e_name_len), entry,
  887             pad - (char*)entry);
  888 
  889         memcpy(entry, new_entry, EXT2_EXTATTR_LEN(new_entry->e_name_len));
  890         free_entry(new_entry);
  891 
  892         new_entry = entry;
  893         if (le32toh(new_entry->e_value_size) > 0)
  894                 new_entry->e_value_offs = htole16(min_offs -
  895                     EXT2_EXTATTR_SIZE(le32toh(new_entry->e_value_size)));
  896 
  897         uiomove(off + le16toh(new_entry->e_value_offs),
  898             le32toh(new_entry->e_value_size), uio);
  899 
  900         return (new_entry);
  901 }
  902 
  903 int
  904 ext2_extattr_inode_set(struct inode *ip, int attrnamespace,
  905     const char *name, struct uio *uio)
  906 {
  907         struct m_ext2fs *fs;
  908         struct buf *bp;
  909         struct ext2fs_extattr_dinode_header *header;
  910         struct ext2fs_extattr_entry *entry;
  911         const char *attr_name;
  912         int name_len;
  913         size_t size = 0, max_size;
  914         int error;
  915 
  916         fs = ip->i_e2fs;
  917 
  918         if ((error = bread(ip->i_devvp,
  919             fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
  920             (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
  921                 brelse(bp);
  922                 return (error);
  923         }
  924 
  925         struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
  926             ((char *)bp->b_data +
  927             EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
  928 
  929         /* Check attributes magic value */
  930         header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
  931             E2FS_REV0_INODE_SIZE + le16toh(dinode->e2di_extra_isize));
  932 
  933         if (le32toh(header->h_magic) != EXTATTR_MAGIC) {
  934                 brelse(bp);
  935                 return (ENOSPC);
  936         }
  937 
  938         error = ext2_extattr_check(EXT2_IFIRST(header), (char *)dinode +
  939             EXT2_INODE_SIZE(fs));
  940         if (error) {
  941                 brelse(bp);
  942                 return (error);
  943         }
  944 
  945         /* Find if entry exist */
  946         for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
  947             entry = EXT2_EXTATTR_NEXT(entry)) {
  948                 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
  949                     attrnamespace)
  950                         continue;
  951 
  952                 name_len = entry->e_name_len;
  953                 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
  954                     entry->e_name, &name_len);
  955                 if (!attr_name) {
  956                         brelse(bp);
  957                         return (ENOTSUP);
  958                 }
  959 
  960                 if (strlen(name) == name_len &&
  961                     0 == strncmp(attr_name, name, name_len))
  962                         break;
  963         }
  964 
  965         max_size = EXT2_INODE_SIZE(fs) - E2FS_REV0_INODE_SIZE -
  966             le16toh(dinode->e2di_extra_isize);
  967 
  968         if (!EXT2_IS_LAST_ENTRY(entry)) {
  969                 size = ext2_extattr_get_size(EXT2_IFIRST(header), entry,
  970                     sizeof(struct ext2fs_extattr_dinode_header),
  971                     entry->e_name_len, uio->uio_resid);
  972                 if (size > max_size) {
  973                         brelse(bp);
  974                         return (ENOSPC);
  975                 }
  976 
  977                 ext2_extattr_set_exist_entry((char *)EXT2_IFIRST(header),
  978                     EXT2_IFIRST(header), entry, (char *)header + max_size, uio);
  979         } else {
  980                 /* Ensure that the same entry does not exist in the block */
  981                 if (ip->i_facl) {
  982                         error = ext2_extattr_block_get(ip, attrnamespace, name,
  983                             NULL, &size);
  984                         if (error != ENOATTR || size > 0) {
  985                                 brelse(bp);
  986                                 if (size > 0)
  987                                         error = ENOSPC;
  988 
  989                                 return (error);
  990                         }
  991                 }
  992 
  993                 size = ext2_extattr_get_size(EXT2_IFIRST(header), NULL,
  994                     sizeof(struct ext2fs_extattr_dinode_header),
  995                     entry->e_name_len, uio->uio_resid);
  996                 if (size > max_size) {
  997                         brelse(bp);
  998                         return (ENOSPC);
  999                 }
 1000 
 1001                 ext2_extattr_set_new_entry((char *)EXT2_IFIRST(header),
 1002                     EXT2_IFIRST(header), name, attrnamespace,
 1003                     (char *)header + max_size, uio);
 1004         }
 1005 
 1006         return (bwrite(bp));
 1007 }
 1008 
 1009 static void
 1010 ext2_extattr_hash_entry(struct ext2fs_extattr_header *header,
 1011     struct ext2fs_extattr_entry *entry)
 1012 {
 1013         uint32_t hash = 0;
 1014         char *name = entry->e_name;
 1015         int n;
 1016 
 1017         for (n=0; n < entry->e_name_len; n++) {
 1018                 hash = (hash << EXT2_EXTATTR_NAME_HASH_SHIFT) ^
 1019                     (hash >> (8*sizeof(hash) - EXT2_EXTATTR_NAME_HASH_SHIFT)) ^
 1020                     (*name++);
 1021         }
 1022 
 1023         if (entry->e_value_block == 0 && entry->e_value_size != 0) {
 1024                 uint32_t *value = (uint32_t *)((char *)header +
 1025                     le16toh(entry->e_value_offs));
 1026                 for (n = (le32toh(entry->e_value_size) +
 1027                     EXT2_EXTATTR_ROUND) >> EXT2_EXTATTR_PAD_BITS; n; n--) {
 1028                         hash = (hash << EXT2_EXTATTR_VALUE_HASH_SHIFT) ^
 1029                             (hash >> (8*sizeof(hash) - EXT2_EXTATTR_VALUE_HASH_SHIFT)) ^
 1030                             le32toh(*value++);
 1031                 }
 1032         }
 1033 
 1034         entry->e_hash = htole32(hash);
 1035 }
 1036 
 1037 static void
 1038 ext2_extattr_rehash(struct ext2fs_extattr_header *header,
 1039     struct ext2fs_extattr_entry *entry)
 1040 {
 1041         struct ext2fs_extattr_entry *here;
 1042         uint32_t hash = 0;
 1043 
 1044         ext2_extattr_hash_entry(header, entry);
 1045 
 1046         here = EXT2_ENTRY(header+1);
 1047         while (!EXT2_IS_LAST_ENTRY(here)) {
 1048                 if (here->e_hash == 0) {
 1049                         /* Block is not shared if an entry's hash value == 0 */
 1050                         hash = 0;
 1051                         break;
 1052                 }
 1053 
 1054                 hash = (hash << EXT2_EXTATTR_BLOCK_HASH_SHIFT) ^
 1055                     (hash >> (8*sizeof(hash) - EXT2_EXTATTR_BLOCK_HASH_SHIFT)) ^
 1056                     le32toh(here->e_hash);
 1057 
 1058                 here = EXT2_EXTATTR_NEXT(here);
 1059         }
 1060 
 1061         header->h_hash = htole32(hash);
 1062 }
 1063 
 1064 int
 1065 ext2_extattr_block_set(struct inode *ip, int attrnamespace,
 1066     const char *name, struct uio *uio)
 1067 {
 1068         struct m_ext2fs *fs;
 1069         struct buf *bp;
 1070         struct ext2fs_extattr_header *header;
 1071         struct ext2fs_extattr_entry *entry;
 1072         const char *attr_name;
 1073         int name_len;
 1074         size_t size;
 1075         int error;
 1076 
 1077         fs = ip->i_e2fs;
 1078 
 1079         if (ip->i_facl) {
 1080                 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
 1081                     fs->e2fs_bsize, NOCRED, &bp);
 1082                 if (error) {
 1083                         return (error);
 1084                 }
 1085 
 1086                 /* Check attributes magic value */
 1087                 header = EXT2_HDR(bp);
 1088                 if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
 1089                     le32toh(header->h_blocks) != 1) {
 1090                         brelse(bp);
 1091                         return (EINVAL);
 1092                 }
 1093 
 1094                 error = ext2_extattr_block_check(ip, bp);
 1095                 if (error) {
 1096                         brelse(bp);
 1097                         return (error);
 1098                 }
 1099 
 1100                 if (le32toh(header->h_refcount) > 1) {
 1101                         error = ext2_extattr_block_clone(ip, &bp);
 1102                         if (error) {
 1103                                 brelse(bp);
 1104                                 return (error);
 1105                         }
 1106 
 1107                         header = EXT2_HDR(bp);
 1108                 }
 1109 
 1110                 /* Find if entry exist */
 1111                 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
 1112                     entry = EXT2_EXTATTR_NEXT(entry)) {
 1113                         if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
 1114                             attrnamespace)
 1115                                 continue;
 1116 
 1117                         name_len = entry->e_name_len;
 1118                         attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
 1119                             entry->e_name, &name_len);
 1120                         if (!attr_name) {
 1121                                 brelse(bp);
 1122                                 return (ENOTSUP);
 1123                         }
 1124 
 1125                         if (strlen(name) == name_len &&
 1126                             0 == strncmp(attr_name, name, name_len))
 1127                                 break;
 1128                 }
 1129 
 1130                 if (!EXT2_IS_LAST_ENTRY(entry)) {
 1131                         size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), entry,
 1132                             sizeof(struct ext2fs_extattr_header),
 1133                             entry->e_name_len, uio->uio_resid);
 1134                         if (size > bp->b_bufsize) {
 1135                                 brelse(bp);
 1136                                 return (ENOSPC);
 1137                         }
 1138 
 1139                         ext2_extattr_set_exist_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
 1140                             entry, bp->b_data + bp->b_bufsize, uio);
 1141                 } else {
 1142                         size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), NULL,
 1143                             sizeof(struct ext2fs_extattr_header),
 1144                             strlen(name), uio->uio_resid);
 1145                         if (size > bp->b_bufsize) {
 1146                                 brelse(bp);
 1147                                 return (ENOSPC);
 1148                         }
 1149 
 1150                         entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
 1151                             name, attrnamespace, bp->b_data + bp->b_bufsize, uio);
 1152 
 1153                         /* Clean the same entry in the inode */
 1154                         error = ext2_extattr_inode_delete(ip, attrnamespace, name);
 1155                         if (error && error != ENOATTR) {
 1156                                 brelse(bp);
 1157                                 return (error);
 1158                         }
 1159                 }
 1160 
 1161                 ext2_extattr_rehash(header, entry);
 1162                 ext2_extattr_blk_csum_set(ip, bp);
 1163 
 1164                 return (bwrite(bp));
 1165         }
 1166 
 1167         size = ext2_extattr_get_size(NULL, NULL,
 1168             sizeof(struct ext2fs_extattr_header),
 1169             strlen(ext2_extattr_name_to_linux(attrnamespace, name)), uio->uio_resid);
 1170         if (size > fs->e2fs_bsize)
 1171                 return (ENOSPC);
 1172 
 1173         /* Allocate block, fill EA header and insert entry */
 1174         ip->i_facl = ext2_alloc_meta(ip);
 1175         if (0 == ip->i_facl)
 1176                 return (ENOSPC);
 1177 
 1178         ip->i_blocks += btodb(fs->e2fs_bsize);
 1179         ext2_update(ip->i_vnode, 1);
 1180 
 1181         bp = getblk(ip->i_devvp, fsbtodb(fs, ip->i_facl), fs->e2fs_bsize, 0, 0, 0);
 1182         if (!bp) {
 1183                 ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize);
 1184                 ip->i_blocks -= btodb(fs->e2fs_bsize);
 1185                 ip->i_facl = 0;
 1186                 ext2_update(ip->i_vnode, 1);
 1187                 return (EIO);
 1188         }
 1189 
 1190         header = EXT2_HDR(bp);
 1191         header->h_magic = htole32(EXTATTR_MAGIC);
 1192         header->h_refcount = htole32(1);
 1193         header->h_blocks = htole32(1);
 1194         header->h_hash = 0;
 1195         memset(header->h_reserved, 0, sizeof(header->h_reserved));
 1196         memcpy(bp->b_data, header, sizeof(struct ext2fs_extattr_header));
 1197         memset(EXT2_FIRST_ENTRY(bp), 0, sizeof(uint32_t));
 1198 
 1199         entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
 1200             name, attrnamespace, bp->b_data + bp->b_bufsize, uio);
 1201 
 1202         /* Clean the same entry in the inode */
 1203         error = ext2_extattr_inode_delete(ip, attrnamespace, name);
 1204         if (error && error != ENOATTR) {
 1205                 brelse(bp);
 1206                 return (error);
 1207         }
 1208 
 1209         ext2_extattr_rehash(header, entry);
 1210         ext2_extattr_blk_csum_set(ip, bp);
 1211 
 1212         return (bwrite(bp));
 1213 }
 1214 
 1215 int ext2_extattr_free(struct inode *ip)
 1216 {
 1217         struct m_ext2fs *fs;
 1218         struct buf *bp;
 1219         struct ext2fs_extattr_header *header;
 1220         int error;
 1221 
 1222         fs = ip->i_e2fs;
 1223 
 1224         if (!ip->i_facl)
 1225                 return (0);
 1226 
 1227         error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
 1228             fs->e2fs_bsize, NOCRED, &bp);
 1229         if (error) {
 1230                 return (error);
 1231         }
 1232 
 1233         /* Check attributes magic value */
 1234         header = EXT2_HDR(bp);
 1235         if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
 1236             le32toh(header->h_blocks) != 1) {
 1237                 brelse(bp);
 1238                 return (EINVAL);
 1239         }
 1240 
 1241         error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp),
 1242             bp->b_data + bp->b_bufsize);
 1243         if (error) {
 1244                 brelse(bp);
 1245                 return (error);
 1246         }
 1247 
 1248         if (le32toh(header->h_refcount) > 1) {
 1249                 header->h_refcount = htole32(le32toh(header->h_refcount) - 1);
 1250                 bwrite(bp);
 1251         } else {
 1252                 ext2_blkfree(ip, ip->i_facl, ip->i_e2fs->e2fs_bsize);
 1253                 brelse(bp);
 1254         }
 1255 
 1256         ip->i_blocks -= btodb(ip->i_e2fs->e2fs_bsize);
 1257         ip->i_facl = 0;
 1258         ext2_update(ip->i_vnode, 1);
 1259 
 1260         return (0);
 1261 }

Cache object: ee02945a0bad7e4bbd865a3ea286230e


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