+// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA 94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ * Copyright (c) 2000-2002,2004-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
*/
-#include <libxfs.h>
+#include "libxfs.h"
#include "globals.h"
#include "err_protos.h"
#include "attr_repair.h"
-#include "dir.h"
#include "dinode.h"
#include "bmap.h"
+#include "protos.h"
+#include "dir2.h"
+#include "da_util.h"
-static int xfs_acl_valid(xfs_acl_t *aclp);
+static int xfs_acl_valid(struct xfs_mount *mp, struct xfs_acl *daclp);
static int xfs_mac_valid(xfs_mac_label_t *lp);
+/*
+ * da node check/verify functions that the attribute tree relies on are first in
+ * the file before the actual attribute code. This used to be shared with the
+ * dir v1 code, but that format is no longer supported yb the userspace
+ * utilities and hence is now specific to the attribute tree implementation.
+ */
+
+typedef unsigned char da_freemap_t;
+
+/*
+ * Allocate a freespace map for directory or attr leaf blocks (1 bit per byte)
+ * 1 == used, 0 == free.
+ */
+static da_freemap_t *
+alloc_da_freemap(struct xfs_mount *mp)
+{
+ return calloc(1, mp->m_sb.sb_blocksize / NBBY);
+}
+
+/*
+ * Set the he range [start, stop) in the directory freemap.
+ *
+ * Returns 1 if there is a conflict or 0 if everything's good.
+ *
+ * Within a char, the lowest bit of the char represents the byte with
+ * the smallest address
+ */
+static int
+set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop)
+{
+ const da_freemap_t mask = 0x1;
+ int i;
+
+ if (start > stop) {
+ /*
+ * allow == relation since [x, x) claims 1 byte
+ */
+ do_warn(_("bad range claimed [%d, %d) in da block\n"),
+ start, stop);
+ return(1);
+ }
+
+ if (stop > mp->m_sb.sb_blocksize) {
+ do_warn(
+ _("byte range end [%d %d) in da block larger than blocksize %d\n"),
+ start, stop, mp->m_sb.sb_blocksize);
+ return(1);
+ }
+
+ for (i = start; i < stop; i ++) {
+ if (map[i / NBBY] & (mask << i % NBBY)) {
+ do_warn(_("multiply claimed byte %d in da block\n"), i);
+ return(1);
+ }
+ map[i / NBBY] |= (mask << i % NBBY);
+ }
+
+ return(0);
+}
/*
- * For attribute repair, there are 3 formats to worry about. First, is
+ * For attribute repair, there are 3 formats to worry about. First, is
* shortform attributes which reside in the inode. Second is the leaf
* form, and lastly the btree. Much of this models after the directory
- * structure so code resembles the directory repair cases.
+ * structure so code resembles the directory repair cases.
* For shortform case, if an attribute looks corrupt, it is removed.
- * If that leaves the shortform down to 0 attributes, it's okay and
+ * If that leaves the shortform down to 0 attributes, it's okay and
* will appear to just have a null attribute fork. Some checks are done
* for validity of the value field based on what the security needs are.
* Calls will be made to xfs_mac_valid or xfs_acl_valid routines if the
* requirements, but may in the future.
*
* For leaf block attributes, it requires more processing. One sticky
- * point is that the attributes can be local (within the leaf) or
+ * point is that the attributes can be local (within the leaf) or
* remote (outside the leaf in other blocks). Thinking of local only
- * if you get a bad attribute, and want to delete just one, its a-okay
+ * if you get a bad attribute, and want to delete just one, it's a-okay
* if it remains large enough to still be a leaf block attribute. Otherwise,
* it may have to be converted to shortform. How to convert this and when
* is an issue. This call is happening in Phase3. Phase5 will capture empty
- * blocks, but Phase6 allows you to use the simulation library which knows
+ * blocks, but Phase6 allows you to use the libxfs library which knows
* how to handle attributes in the kernel for converting formats. What we
* could do is mark an attribute to be cleared now, but in phase6 somehow
* have it cleared for real and then the format changed to shortform if
* attribute in the leaf block will make the entire attribute fork be
* cleared. The simplest way to do that is to ignore the leaf format, and
* call clear_dinode_attr to just make a shortform attribute fork with
- * zero entries.
+ * zero entries.
*
* Another issue with handling repair on leaf attributes is the remote
* blocks. To make sure that they look good and are not used multiple times
* fork being emptied and put in shortform format.
*/
+static int
+attr_namecheck(
+ uint8_t *name,
+ int length)
+{
+ return namecheck((char *)name, length, false);
+}
+
/*
* This routine just checks what security needs are for attribute values
* only called when root flag is set, otherwise these names could exist in
* in user attribute land without a conflict.
* If value is non-zero, then a remote attribute is being passed in
*/
-
-int
-valuecheck(char *namevalue, char *value, int namelen, int valuelen)
+static int
+valuecheck(
+ struct xfs_mount *mp,
+ char *namevalue,
+ char *value,
+ int namelen,
+ int valuelen)
{
- /* for proper alignment issues, get the structs and bcopy the values */
+ /* for proper alignment issues, get the structs and memmove the values */
xfs_mac_label_t macl;
- xfs_acl_t thisacl;
void *valuep;
int clearit = 0;
- if ((strncmp(namevalue, SGI_ACL_FILE, SGI_ACL_FILE_SIZE) == 0) ||
- (strncmp(namevalue, SGI_ACL_DEFAULT,
- SGI_ACL_DEFAULT_SIZE) == 0)) {
- if (value == NULL) {
- bzero(&thisacl, sizeof(xfs_acl_t));
- bcopy(namevalue+namelen, &thisacl, valuelen);
- valuep = &thisacl;
+ if ((namelen == SGI_ACL_FILE_SIZE &&
+ strncmp(namevalue, SGI_ACL_FILE, SGI_ACL_FILE_SIZE) == 0) ||
+ (namelen == SGI_ACL_DEFAULT_SIZE &&
+ strncmp(namevalue, SGI_ACL_DEFAULT, SGI_ACL_DEFAULT_SIZE) == 0)) {
+ if (value == NULL) {
+ valuep = malloc(valuelen);
+ if (!valuep)
+ do_error(_("No memory for ACL check!\n"));
+ memcpy(valuep, namevalue + namelen, valuelen);
} else
valuep = value;
- if (xfs_acl_valid((xfs_acl_t *) valuep) != 0) { /* 0 is valid */
+ if (xfs_acl_valid(mp, valuep) != 0) {
clearit = 1;
- do_warn("entry contains illegal value in attribute named SGI_ACL_FILE or SGI_ACL_DEFAULT\n");
+ do_warn(
+ _("entry contains illegal value in attribute named SGI_ACL_FILE "
+ "or SGI_ACL_DEFAULT\n"));
}
+
+ if (valuep != value)
+ free(valuep);
+
} else if (strncmp(namevalue, SGI_MAC_FILE, SGI_MAC_FILE_SIZE) == 0) {
if (value == NULL) {
- bzero(&macl, sizeof(xfs_mac_label_t));
- bcopy(namevalue+namelen, &macl, valuelen);
+ memset(&macl, 0, sizeof(xfs_mac_label_t));
+ memmove(&macl, namevalue+namelen, valuelen);
valuep = &macl;
- } else
+ } else
valuep = value;
if (xfs_mac_valid((xfs_mac_label_t *)valuep) != 1) { /* 1 is valid */
/*
- *if sysconf says MAC enabled,
+ * if sysconf says MAC enabled,
* temp = mac_from_text("msenhigh/mintlow", NULL)
* copy it to value, update valuelen, totsize
* This causes pushing up or down of all following
* else clearit = 1;
*/
clearit = 1;
- do_warn("entry contains illegal value in attribute named SGI_MAC_LABEL\n");
+ do_warn(
+ _("entry contains illegal value in attribute named SGI_MAC_LABEL\n"));
}
} else if (strncmp(namevalue, SGI_CAP_FILE, SGI_CAP_FILE_SIZE) == 0) {
if ( valuelen != sizeof(xfs_cap_set_t)) {
clearit = 1;
- do_warn("entry contains illegal value in attribute named SGI_CAP_FILE\n");
+ do_warn(
+ _("entry contains illegal value in attribute named SGI_CAP_FILE\n"));
}
}
* if you cannot modify the structures. repair is set to 1, if anything
* was fixed.
*/
-int
+static int
process_shortform_attr(
+ struct xfs_mount *mp,
xfs_ino_t ino,
xfs_dinode_t *dip,
- int *repair)
+ int *repair)
{
xfs_attr_shortform_t *asf;
xfs_attr_sf_entry_t *currententry, *nextentry, *tempentry;
int i, junkit;
int currentsize, remainingspace;
-
+
*repair = 0;
- asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT);
+ asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR(dip);
/* Assumption: hdr.totsize is less than a leaf block and was checked
- * by lclinode for valid sizes. Check the count though.
+ * by lclinode for valid sizes. Check the count though.
*/
- if (INT_GET(asf->hdr.count, ARCH_CONVERT) == 0)
+ if (asf->hdr.count == 0)
/* then the total size should just be the header length */
- if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) != sizeof(xfs_attr_sf_hdr_t)) {
+ if (be16_to_cpu(asf->hdr.totsize) != sizeof(xfs_attr_sf_hdr_t)) {
/* whoops there's a discrepancy. Clear the hdr */
if (!no_modify) {
- do_warn("there are no attributes in the fork for inode %llu \n", ino);
- INT_SET(asf->hdr.totsize, ARCH_CONVERT,
- sizeof(xfs_attr_sf_hdr_t));
+ do_warn(
+ _("there are no attributes in the fork for inode %" PRIu64 "\n"),
+ ino);
+ asf->hdr.totsize =
+ cpu_to_be16(sizeof(xfs_attr_sf_hdr_t));
*repair = 1;
- return(1);
+ return(1);
} else {
- do_warn("would junk the attribute fork since the count is 0 for inode %llu\n",ino);
+ do_warn(
+ _("would junk the attribute fork since count is 0 for inode %" PRIu64 "\n"),
+ ino);
return(1);
}
- }
-
- currentsize = sizeof(xfs_attr_sf_hdr_t);
- remainingspace = INT_GET(asf->hdr.totsize, ARCH_CONVERT) - currentsize;
+ }
+
+ currentsize = sizeof(xfs_attr_sf_hdr_t);
+ remainingspace = be16_to_cpu(asf->hdr.totsize) - currentsize;
nextentry = &asf->list[0];
- for (i = 0; i < INT_GET(asf->hdr.count, ARCH_CONVERT); i++) {
+ for (i = 0; i < asf->hdr.count; i++) {
currententry = nextentry;
junkit = 0;
/* don't go off the end if the hdr.count was off */
- if ((currentsize + (sizeof(xfs_attr_sf_entry_t) - 1)) >
- INT_GET(asf->hdr.totsize, ARCH_CONVERT))
+ if ((currentsize + (sizeof(xfs_attr_sf_entry_t) - 1)) >
+ be16_to_cpu(asf->hdr.totsize))
break; /* get out and reset count and totSize */
/* if the namelen is 0, can't get to the rest of the entries */
- if (INT_GET(currententry->namelen, ARCH_CONVERT) == 0) {
- do_warn("zero length name entry in attribute fork, ");
+ if (currententry->namelen == 0) {
+ do_warn(_("zero length name entry in attribute fork,"));
if (!no_modify) {
- do_warn("truncating attributes for inode %llu to %d \n", ino, i);
+ do_warn(
+ _(" truncating attributes for inode %" PRIu64 " to %d\n"), ino, i);
*repair = 1;
- break; /* and then update hdr fields */
+ break; /* and then update hdr fields */
} else {
- do_warn("would truncate attributes for inode %llu to %d \n", ino, i);
+ do_warn(
+ _(" would truncate attributes for inode %" PRIu64 " to %d\n"), ino, i);
break;
}
} else {
* rough check to make sure we haven't gone outside of
* totsize.
*/
- if ((remainingspace < INT_GET(currententry->namelen, ARCH_CONVERT)) ||
- ((remainingspace - INT_GET(currententry->namelen, ARCH_CONVERT))
- < INT_GET(currententry->valuelen, ARCH_CONVERT))) {
- do_warn("name or value attribute lengths are too large, \n");
+ if (remainingspace < currententry->namelen ||
+ ((remainingspace - currententry->
+ namelen) < currententry->valuelen)) {
+ do_warn(
+ _("name or value attribute lengths are too large,\n"));
if (!no_modify) {
- do_warn(" truncating attributes for inode %llu to %d \n", ino, i);
- *repair = 1;
+ do_warn(
+ _(" truncating attributes for inode %" PRIu64 " to %d\n"),
+ ino, i);
+ *repair = 1;
break; /* and then update hdr fields */
} else {
- do_warn(" would truncate attributes for inode %llu to %d \n", ino, i);
+ do_warn(
+ _(" would truncate attributes for inode %" PRIu64 " to %d\n"),
+ ino, i);
break;
- }
+ }
}
}
-
- /* namecheck checks for / and null terminated for file names.
- * attributes names currently follow the same rules.
- */
- if (namecheck((char *)¤tentry->nameval[0],
- INT_GET(currententry->namelen, ARCH_CONVERT))) {
- do_warn("entry contains illegal character in shortform attribute name\n");
+
+ /* namecheck checks for null chars in attr names. */
+ if (attr_namecheck(currententry->nameval,
+ currententry->namelen)) {
+ do_warn(
+ _("entry contains illegal character in shortform attribute name\n"));
junkit = 1;
}
- if (INT_GET(currententry->flags, ARCH_CONVERT) & XFS_ATTR_INCOMPLETE) {
- do_warn("entry has INCOMPLETE flag on in shortform attribute\n");
+ if (currententry->flags & XFS_ATTR_INCOMPLETE) {
+ do_warn(
+ _("entry has INCOMPLETE flag on in shortform attribute\n"));
junkit = 1;
}
/* Only check values for root security attributes */
- if (INT_GET(currententry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT)
- junkit = valuecheck((char *)¤tentry->nameval[0], NULL,
- INT_GET(currententry->namelen, ARCH_CONVERT), INT_GET(currententry->valuelen, ARCH_CONVERT));
+ if (currententry->flags & XFS_ATTR_ROOT)
+ junkit |= valuecheck(mp,
+ (char *)¤tentry->nameval[0],
+ NULL, currententry->namelen,
+ currententry->valuelen);
- remainingspace = remainingspace -
- XFS_ATTR_SF_ENTSIZE(currententry);
+ remainingspace = remainingspace -
+ XFS_ATTR_SF_ENTSIZE(currententry);
if (junkit) {
if (!no_modify) {
/* get rid of only this entry */
- do_warn("removing attribute entry %d for inode %llu \n", i, ino);
+ do_warn(
+ _("removing attribute entry %d for inode %" PRIu64 "\n"),
+ i, ino);
tempentry = (xfs_attr_sf_entry_t *)
- ((__psint_t) currententry +
+ ((intptr_t) currententry +
XFS_ATTR_SF_ENTSIZE(currententry));
memmove(currententry,tempentry,remainingspace);
- INT_MOD(asf->hdr.count, ARCH_CONVERT, -1);
+ asf->hdr.count -= 1;
i--; /* no worries, it will wrap back to 0 */
*repair = 1;
continue; /* go back up now */
- } else {
- do_warn("would remove attribute entry %d for inode %llu \n", i, ino);
- }
- }
+ } else {
+ do_warn(
+ _("would remove attribute entry %d for inode %" PRIu64 "\n"),
+ i, ino);
+ }
+ }
/* Let's get ready for the next entry... */
- nextentry = (xfs_attr_sf_entry_t *)
- ((__psint_t) nextentry +
- XFS_ATTR_SF_ENTSIZE(currententry));
+ nextentry = (xfs_attr_sf_entry_t *)((intptr_t) nextentry +
+ XFS_ATTR_SF_ENTSIZE(currententry));
currentsize = currentsize + XFS_ATTR_SF_ENTSIZE(currententry);
-
- } /* end the loop */
-
- if (INT_GET(asf->hdr.count, ARCH_CONVERT) != i) {
+ } /* end the loop */
+
+ if (asf->hdr.count != i) {
if (no_modify) {
- do_warn("would have corrected attribute entry count in inode %llu from %d to %d\n",
- ino, INT_GET(asf->hdr.count, ARCH_CONVERT), i);
+ do_warn(
+ _("would have corrected attribute entry count in inode %" PRIu64 " from %d to %d\n"),
+ ino, asf->hdr.count, i);
} else {
- do_warn("corrected attribute entry count in inode %llu, was %d, now %d\n",
- ino, INT_GET(asf->hdr.count, ARCH_CONVERT), i);
- INT_SET(asf->hdr.count, ARCH_CONVERT, i);
+ do_warn(
+ _("corrected attribute entry count in inode %" PRIu64 ", was %d, now %d\n"),
+ ino, asf->hdr.count, i);
+ asf->hdr.count = i;
*repair = 1;
}
}
-
+
/* ASSUMPTION: currentsize <= totsize */
- if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) != currentsize) {
+ if (be16_to_cpu(asf->hdr.totsize) != currentsize) {
if (no_modify) {
- do_warn("would have corrected attribute totsize in inode %llu from %d to %d\n",
- ino, INT_GET(asf->hdr.totsize, ARCH_CONVERT), currentsize);
+ do_warn(
+ _("would have corrected attribute totsize in inode %" PRIu64 " from %d to %d\n"),
+ ino, be16_to_cpu(asf->hdr.totsize),
+ currentsize);
} else {
- do_warn("corrected attribute entry totsize in inode %llu, was %d, now %d\n",
- ino, INT_GET(asf->hdr.totsize, ARCH_CONVERT), currentsize);
- INT_SET(asf->hdr.totsize, ARCH_CONVERT, currentsize);
+ do_warn(
+ _("corrected attribute entry totsize in inode %" PRIu64 ", was %d, now %d\n"),
+ ino, be16_to_cpu(asf->hdr.totsize),
+ currentsize);
+ asf->hdr.totsize = cpu_to_be16(currentsize);
*repair = 1;
}
}
rmtval_get(xfs_mount_t *mp, xfs_ino_t ino, blkmap_t *blkmap,
xfs_dablk_t blocknum, int valuelen, char* value)
{
- xfs_dfsbno_t bno;
+ xfs_fsblock_t bno;
xfs_buf_t *bp;
int clearit = 0, i = 0, length = 0, amountdone = 0;
-
+ int hdrsize = 0;
+
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ hdrsize = sizeof(struct xfs_attr3_rmt_hdr);
+
/* ASSUMPTION: valuelen is a valid number, so use it for looping */
- /* Note that valuelen is not a multiple of blocksize */
+ /* Note that valuelen is not a multiple of blocksize */
while (amountdone < valuelen) {
bno = blkmap_get(blkmap, blocknum + i);
- if (bno == NULLDFSBNO) {
- do_warn("remote block for attributes of inode %llu"
- " is missing\n", ino);
+ if (bno == NULLFSBLOCK) {
+ do_warn(
+ _("remote block for attributes of inode %" PRIu64 " is missing\n"), ino);
clearit = 1;
break;
}
bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
- XFS_FSB_TO_BB(mp, 1), 0);
+ XFS_FSB_TO_BB(mp, 1), 0,
+ &xfs_attr3_rmt_buf_ops);
if (!bp) {
- do_warn("can't read remote block for attributes"
- " of inode %llu\n", ino);
+ do_warn(
+ _("can't read remote block for attributes of inode %" PRIu64 "\n"), ino);
+ clearit = 1;
+ break;
+ }
+
+ if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) {
+ do_warn(
+ _("Corrupt remote block for attributes of inode %" PRIu64 "\n"), ino);
+ libxfs_putbuf(bp);
clearit = 1;
break;
}
- ASSERT(mp->m_sb.sb_blocksize == XFS_BUF_COUNT(bp));
- length = MIN(XFS_BUF_COUNT(bp), valuelen - amountdone);
- bcopy(XFS_BUF_PTR(bp), value, length);
+
+ ASSERT(mp->m_sb.sb_blocksize == bp->b_bcount);
+
+ length = min(bp->b_bcount - hdrsize, valuelen - amountdone);
+ memmove(value, bp->b_addr + hdrsize, length);
amountdone += length;
value += length;
i++;
return (clearit);
}
-/*
- * freespace map for directory and attribute leaf blocks (1 bit per byte)
- * 1 == used, 0 == free
- */
-static da_freemap_t attr_freemap[DA_BMAP_SIZE];
-
/* The block is read in. The magic number and forward / backward
* links are checked by the caller process_leaf_attr.
* If any problems occur the routine returns with non-zero. In
* this case the next step is to clear the attribute fork, by
* changing it to shortform and zeroing it out. Forkoff need not
- * be changed.
+ * be changed.
*/
-int
+static int
+process_leaf_attr_local(
+ struct xfs_mount *mp,
+ xfs_attr_leafblock_t *leaf,
+ int i,
+ xfs_attr_leaf_entry_t *entry,
+ xfs_dahash_t last_hashval,
+ xfs_dablk_t da_bno,
+ xfs_ino_t ino)
+{
+ xfs_attr_leaf_name_local_t *local;
+
+ local = xfs_attr3_leaf_name_local(leaf, i);
+ if (local->namelen == 0 || attr_namecheck(local->nameval,
+ local->namelen)) {
+ do_warn(
+ _("attribute entry %d in attr block %u, inode %" PRIu64 " has bad name (namelen = %d)\n"),
+ i, da_bno, ino, local->namelen);
+ return -1;
+ }
+
+ /* Check on the hash value. Checking order of values
+ * is not necessary, since one wrong clears the whole
+ * fork. If the ordering's wrong, it's caught here or
+ * the kernel code has a bug with transaction logging
+ * or attributes itself. Being paranoid, let's check
+ * ordering anyway in case both the name value and the
+ * hashvalue were wrong but matched. Unlikely, however.
+ */
+ if (be32_to_cpu(entry->hashval) != libxfs_da_hashname(
+ &local->nameval[0], local->namelen) ||
+ be32_to_cpu(entry->hashval) < last_hashval) {
+ do_warn(
+ _("bad hashvalue for attribute entry %d in attr block %u, inode %" PRIu64 "\n"),
+ i, da_bno, ino);
+ return -1;
+ }
+
+ /* Only check values for root security attributes */
+ if (entry->flags & XFS_ATTR_ROOT) {
+ if (valuecheck(mp, (char *)&local->nameval[0], NULL,
+ local->namelen, be16_to_cpu(local->valuelen))) {
+ do_warn(
+ _("bad security value for attribute entry %d in attr block %u, inode %" PRIu64 "\n"),
+ i, da_bno, ino);
+ return -1;
+ }
+ }
+ return xfs_attr_leaf_entsize_local(local->namelen,
+ be16_to_cpu(local->valuelen));
+}
+
+static int
+process_leaf_attr_remote(
+ xfs_attr_leafblock_t *leaf,
+ int i,
+ xfs_attr_leaf_entry_t *entry,
+ xfs_dahash_t last_hashval,
+ xfs_dablk_t da_bno,
+ xfs_ino_t ino,
+ xfs_mount_t *mp,
+ blkmap_t *blkmap)
+{
+ xfs_attr_leaf_name_remote_t *remotep;
+ char* value;
+
+ remotep = xfs_attr3_leaf_name_remote(leaf, i);
+
+ if (remotep->namelen == 0 || attr_namecheck(remotep->name,
+ remotep->namelen) ||
+ be32_to_cpu(entry->hashval) !=
+ libxfs_da_hashname((unsigned char *)&remotep->name[0],
+ remotep->namelen) ||
+ be32_to_cpu(entry->hashval) < last_hashval ||
+ be32_to_cpu(remotep->valueblk) == 0) {
+ do_warn(
+ _("inconsistent remote attribute entry %d in attr block %u, ino %" PRIu64 "\n"), i, da_bno, ino);
+ return -1;
+ }
+
+ value = malloc(be32_to_cpu(remotep->valuelen));
+ if (value == NULL) {
+ do_warn(
+ _("cannot malloc enough for remotevalue attribute for inode %" PRIu64 "\n"),
+ ino);
+ do_warn(_("SKIPPING this remote attribute\n"));
+ goto out;
+ }
+ if (rmtval_get(mp, ino, blkmap, be32_to_cpu(remotep->valueblk),
+ be32_to_cpu(remotep->valuelen), value)) {
+ do_warn(
+ _("remote attribute get failed for entry %d, inode %" PRIu64 "\n"),
+ i, ino);
+ goto bad_free_out;
+ }
+ if ((entry->flags & XFS_ATTR_ROOT) &&
+ valuecheck(mp, (char *)&remotep->name[0], value, remotep->namelen,
+ be32_to_cpu(remotep->valuelen))) {
+ do_warn(
+ _("remote attribute value check failed for entry %d, inode %" PRIu64 "\n"),
+ i, ino);
+ goto bad_free_out;
+ }
+ free(value);
+out:
+ return xfs_attr_leaf_entsize_remote(remotep->namelen);
+
+bad_free_out:
+ free(value);
+ return -1;
+}
+
+static int
process_leaf_attr_block(
xfs_mount_t *mp,
xfs_attr_leafblock_t *leaf,
blkmap_t *blkmap,
xfs_dahash_t last_hashval,
xfs_dahash_t *current_hashval,
- int *repair)
+ int *repair)
{
xfs_attr_leaf_entry_t *entry;
- xfs_attr_leaf_name_local_t *local;
- xfs_attr_leaf_name_remote_t *remotep;
int i, start, stop, clearit, usedbs, firstb, thissize;
+ da_freemap_t *attr_freemap;
+ struct xfs_attr3_icleaf_hdr leafhdr;
+ xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
clearit = usedbs = 0;
- *repair = 0;
- firstb = mp->m_sb.sb_blocksize;
- stop = sizeof(xfs_attr_leaf_hdr_t);
+ firstb = mp->m_sb.sb_blocksize;
+ stop = xfs_attr3_leaf_hdr_size(leaf);
/* does the count look sorta valid? */
- if (INT_GET(leaf->hdr.count, ARCH_CONVERT)
- * sizeof(xfs_attr_leaf_entry_t)
- + sizeof(xfs_attr_leaf_hdr_t)
- > XFS_LBSIZE(mp)) {
- do_warn("bad attribute count %d in attr block %u, inode %llu\n",
- (int) INT_GET(leaf->hdr.count, ARCH_CONVERT),
- da_bno, ino);
- return (1);
+ if (!leafhdr.count ||
+ leafhdr.count * sizeof(xfs_attr_leaf_entry_t) + stop >
+ mp->m_sb.sb_blocksize) {
+ do_warn(
+ _("bad attribute count %d in attr block %u, inode %" PRIu64 "\n"),
+ leafhdr.count, da_bno, ino);
+ return 1;
}
-
- init_da_freemap(attr_freemap);
+
+ attr_freemap = alloc_da_freemap(mp);
(void) set_da_freemap(mp, attr_freemap, 0, stop);
-
+
/* go thru each entry checking for problems */
- for (i = 0, entry = &leaf->entries[0];
- i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
- i++, entry++) {
-
+ for (i = 0, entry = xfs_attr3_leaf_entryp(leaf);
+ i < leafhdr.count; i++, entry++) {
+
/* check if index is within some boundary. */
- if (INT_GET(entry->nameidx, ARCH_CONVERT) > XFS_LBSIZE(mp)) {
- do_warn("bad attribute nameidx %d in attr block %u, inode %llu\n",
- (int)INT_GET(entry->nameidx, ARCH_CONVERT),
- da_bno,ino);
+ if (be16_to_cpu(entry->nameidx) > mp->m_sb.sb_blocksize) {
+ do_warn(
+ _("bad attribute nameidx %d in attr block %u, inode %" PRIu64 "\n"),
+ be16_to_cpu(entry->nameidx), da_bno, ino);
clearit = 1;
break;
- }
+ }
- if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_INCOMPLETE) {
+ if (entry->flags & XFS_ATTR_INCOMPLETE) {
/* we are inconsistent state. get rid of us */
- do_warn("attribute entry #%d in attr block %u, inode %llu is INCOMPLETE\n",
+ do_warn(
+ _("attribute entry #%d in attr block %u, inode %" PRIu64 " is INCOMPLETE\n"),
i, da_bno, ino);
clearit = 1;
break;
- }
+ }
/* mark the entry used */
- start = (__psint_t)&leaf->entries[i] - (__psint_t)leaf;
+ start = (intptr_t)entry - (intptr_t)leaf;
stop = start + sizeof(xfs_attr_leaf_entry_t);
if (set_da_freemap(mp, attr_freemap, start, stop)) {
- do_warn("attribute entry %d in attr block %u, inode %llu claims already used space\n",
- i,da_bno,ino);
+ do_warn(
+ _("attribute entry %d in attr block %u, inode %" PRIu64 " claims already used space\n"),
+ i, da_bno, ino);
clearit = 1;
break; /* got an overlap */
- }
-
- if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_LOCAL) {
-
- local = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
- if ((INT_GET(local->namelen, ARCH_CONVERT) == 0) ||
- (namecheck((char *)&local->nameval[0],
- INT_GET(local->namelen, ARCH_CONVERT)))) {
- do_warn("attribute entry %d in attr block %u, inode %llu has bad name (namelen = %d)\n",
- i, da_bno, ino, (int) INT_GET(local->namelen, ARCH_CONVERT));
-
- clearit = 1;
- break;
- };
-
- /* Check on the hash value. Checking ordering of hash values
- * is not necessary, since one wrong one clears the whole
- * fork. If the ordering's wrong, it's caught here or
- * the kernel code has a bug with transaction logging
- * or attributes itself. For paranoia reasons, let's check
- * ordering anyway in case both the name value and the
- * hashvalue were wrong but matched. Unlikely, however.
- */
- if (INT_GET(entry->hashval, ARCH_CONVERT) !=
- libxfs_da_hashname((char *)&local->nameval[0],
- INT_GET(local->namelen, ARCH_CONVERT)) ||
- (INT_GET(entry->hashval, ARCH_CONVERT)
- < last_hashval)) {
- do_warn("bad hashvalue for attribute entry %d in attr block %u, inode %llu\n",
- i, da_bno, ino);
- clearit = 1;
- break;
- }
-
- /* Only check values for root security attributes */
- if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT)
- if (valuecheck((char *)&local->nameval[0], NULL,
- INT_GET(local->namelen, ARCH_CONVERT), INT_GET(local->valuelen, ARCH_CONVERT))) {
- do_warn("bad security value for attribute entry %d in attr block %u, inode %llu\n",
- i,da_bno,ino);
- clearit = 1;
- break;
- };
- thissize = XFS_ATTR_LEAF_ENTSIZE_LOCAL(
- INT_GET(local->namelen, ARCH_CONVERT), INT_GET(local->valuelen, ARCH_CONVERT));
+ }
- } else {
- /* do the remote case */
- remotep = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
- thissize = XFS_ATTR_LEAF_ENTSIZE_REMOTE(
- INT_GET(remotep->namelen, ARCH_CONVERT));
-
- if ((INT_GET(remotep->namelen, ARCH_CONVERT) == 0) ||
- (namecheck((char *)&remotep->name[0],
- INT_GET(remotep->namelen, ARCH_CONVERT))) ||
- (INT_GET(entry->hashval, ARCH_CONVERT)
- != libxfs_da_hashname(
- (char *)&remotep->name[0],
- INT_GET(remotep->namelen, ARCH_CONVERT))) ||
- (INT_GET(entry->hashval, ARCH_CONVERT)
- < last_hashval) ||
- (INT_GET(remotep->valueblk, ARCH_CONVERT) == 0)) {
- do_warn("inconsistent remote attribute entry %d in attr block %u, ino %llu\n",
- i, da_bno, ino);
- clearit = 1;
- break;
- };
-
- if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT) {
- char* value;
- if ((value = malloc(INT_GET(remotep->valuelen, ARCH_CONVERT)))==NULL){
- do_warn("cannot malloc enough for remotevalue attribute for inode %llu\n",ino);
- do_warn("SKIPPING this remote attribute\n");
- continue;
- }
- if (rmtval_get(mp, ino, blkmap,
- INT_GET(remotep->valueblk, ARCH_CONVERT),
- INT_GET(remotep->valuelen, ARCH_CONVERT), value)) {
- do_warn("remote attribute get failed for entry %d, inode %llu\n", i,ino);
- clearit = 1;
- free(value);
- break;
- }
- if (valuecheck((char *)&remotep->name[0], value,
- INT_GET(remotep->namelen, ARCH_CONVERT), INT_GET(remotep->valuelen, ARCH_CONVERT))){
- do_warn("remote attribute value check failed for entry %d, inode %llu\n", i, ino);
- clearit = 1;
- free(value);
- break;
- }
- free(value);
- }
+ if (entry->flags & XFS_ATTR_LOCAL)
+ thissize = process_leaf_attr_local(mp, leaf, i, entry,
+ last_hashval, da_bno, ino);
+ else
+ thissize = process_leaf_attr_remote(leaf, i, entry,
+ last_hashval, da_bno, ino,
+ mp, blkmap);
+ if (thissize < 0) {
+ clearit = 1;
+ break;
}
- *current_hashval = last_hashval
- = INT_GET(entry->hashval, ARCH_CONVERT);
+ *current_hashval = last_hashval = be32_to_cpu(entry->hashval);
- if (set_da_freemap(mp, attr_freemap, INT_GET(entry->nameidx, ARCH_CONVERT),
- INT_GET(entry->nameidx, ARCH_CONVERT) + thissize)) {
- do_warn("attribute entry %d in attr block %u, inode %llu claims used space\n",
+ if (set_da_freemap(mp, attr_freemap, be16_to_cpu(entry->nameidx),
+ be16_to_cpu(entry->nameidx) + thissize)) {
+ do_warn(
+ _("attribute entry %d in attr block %u, inode %" PRIu64 " claims used space\n"),
i, da_bno, ino);
clearit = 1;
break; /* got an overlap */
- }
+ }
usedbs += thissize;
- if (INT_GET(entry->nameidx, ARCH_CONVERT) < firstb)
- firstb = INT_GET(entry->nameidx, ARCH_CONVERT);
+ if (be16_to_cpu(entry->nameidx) < firstb)
+ firstb = be16_to_cpu(entry->nameidx);
} /* end the loop */
/* if the holes flag is set, don't reset first_used unless it's
* pointing to used bytes. we're being conservative here
- * since the block will get compacted anyhow by the kernel.
+ * since the block will get compacted anyhow by the kernel.
*/
- if ( (INT_GET(leaf->hdr.holes, ARCH_CONVERT) == 0
- && firstb != INT_GET(leaf->hdr.firstused, ARCH_CONVERT))
- || INT_GET(leaf->hdr.firstused, ARCH_CONVERT) > firstb) {
+ if ((leafhdr.holes == 0 &&
+ firstb != leafhdr.firstused) ||
+ leafhdr.firstused > firstb) {
if (!no_modify) {
- do_warn("- resetting first used heap value from %d to %d in block %u of attribute fork of inode %llu\n",
- (int)INT_GET(leaf->hdr.firstused,
- ARCH_CONVERT), firstb,
- da_bno, ino);
- INT_SET(leaf->hdr.firstused,
- ARCH_CONVERT, firstb);
+ do_warn(
+ _("- resetting first used heap value from %d to %d in "
+ "block %u of attribute fork of inode %" PRIu64 "\n"),
+ leafhdr.firstused,
+ firstb, da_bno, ino);
+ leafhdr.firstused = firstb;
*repair = 1;
} else {
- do_warn("- would reset first used value from %d to %d in block %u of attribute fork of inode %llu\n",
- (int)INT_GET(leaf->hdr.firstused,
- ARCH_CONVERT), firstb,
- da_bno, ino);
+ do_warn(
+ _("- would reset first used value from %d to %d in "
+ "block %u of attribute fork of inode %" PRIu64 "\n"),
+ leafhdr.firstused,
+ firstb, da_bno, ino);
}
}
- if (usedbs != INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT)) {
+ if (usedbs != leafhdr.usedbytes) {
if (!no_modify) {
- do_warn("- resetting usedbytes cnt from %d to %d in block %u of attribute fork of inode %llu\n",
- (int)INT_GET(leaf->hdr.usedbytes,
- ARCH_CONVERT), usedbs, da_bno, ino);
- INT_SET(leaf->hdr.usedbytes,
- ARCH_CONVERT, usedbs);
+ do_warn(
+ _("- resetting usedbytes cnt from %d to %d in "
+ "block %u of attribute fork of inode %" PRIu64 "\n"),
+ leafhdr.usedbytes,
+ usedbs, da_bno, ino);
+ leafhdr.usedbytes = usedbs;
*repair = 1;
} else {
- do_warn("- would reset usedbytes cnt from %d to %d in block %u of attribute fork of %llu\n",
- (int)INT_GET(leaf->hdr.usedbytes,
- ARCH_CONVERT), usedbs,da_bno,ino);
+ do_warn(
+ _("- would reset usedbytes cnt from %d to %d in "
+ "block %u of attribute fork of %" PRIu64 "\n"),
+ leafhdr.usedbytes,
+ usedbs, da_bno, ino);
}
}
* checking for holes and compacting if appropiate. I don't think
* attributes need all that, so let's just leave the holes. If
* we discover later that this is a good place to do compaction
- * we can add it then.
+ * we can add it then.
*/
}
+ /*
+ * If we're just going to zap the block, don't pretend like we
+ * repaired it, because repairing the block stops the clear
+ * operation.
+ */
+ if (clearit)
+ *repair = 0;
+ if (*repair)
+ xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, leaf, &leafhdr);
+
+ free(attr_freemap);
return (clearit); /* and repair */
}
/*
* returns 0 if the attribute fork is ok, 1 if it has to be junked.
*/
-int
+static int
process_leaf_attr_level(xfs_mount_t *mp,
da_bt_cursor_t *da_cursor)
{
xfs_attr_leafblock_t *leaf;
xfs_buf_t *bp;
xfs_ino_t ino;
- xfs_dfsbno_t dev_bno;
+ xfs_fsblock_t dev_bno;
xfs_dablk_t da_bno;
xfs_dablk_t prev_bno;
xfs_dahash_t current_hashval = 0;
xfs_dahash_t greatest_hashval;
+ struct xfs_attr3_icleaf_hdr leafhdr;
da_bno = da_cursor->level[0].bno;
ino = da_cursor->ino;
+ /*
+ * 0 is the root block and no block
+ * pointer can point to the root block of the btree
+ */
+ if (da_bno == 0) {
+ do_warn(
+ _("btree cycle detected in attribute fork for inode %" PRIu64 "\n"),
+ ino);
+ goto error_out;
+ }
+
prev_bno = 0;
do {
repair = 0;
dev_bno = blkmap_get(da_cursor->blkmap, da_bno);
- /*
- * 0 is the root block and no block
- * pointer can point to the root block of the btree
- */
- ASSERT(da_bno != 0);
-
- if (dev_bno == NULLDFSBNO) {
- do_warn("can't map block %u for attribute fork "
- "for inode %llu\n", da_bno, ino);
- goto error_out;
+ if (dev_bno == NULLFSBLOCK) {
+ do_warn(
+ _("can't map block %u for attribute fork for inode %" PRIu64 "\n"),
+ da_bno, ino);
+ goto error_out;
}
bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno),
- XFS_FSB_TO_BB(mp, 1), 0);
+ XFS_FSB_TO_BB(mp, 1), 0,
+ &xfs_attr3_leaf_buf_ops);
if (!bp) {
- do_warn("can't read file block %u (fsbno %llu) for"
- " attribute fork of inode %llu\n",
+ do_warn(
+ _("can't read file block %u (fsbno %" PRIu64 ") for attribute fork of inode %" PRIu64 "\n"),
da_bno, dev_bno, ino);
goto error_out;
}
- leaf = (xfs_attr_leafblock_t *)XFS_BUF_PTR(bp);
+ leaf = bp->b_addr;
+ xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
/* check magic number for leaf directory btree block */
- if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
- != XFS_ATTR_LEAF_MAGIC) {
- do_warn("bad attribute leaf magic %#x for inode %llu\n",
- leaf->hdr.info.magic, ino);
+ if (!(leafhdr.magic == XFS_ATTR_LEAF_MAGIC ||
+ leafhdr.magic == XFS_ATTR3_LEAF_MAGIC)) {
+ do_warn(
+ _("bad attribute leaf magic %#x for inode %" PRIu64 "\n"),
+ leafhdr.magic, ino);
libxfs_putbuf(bp);
goto error_out;
}
/*
- * for each block, process the block, verify it's path,
+ * for each block, process the block, verify its path,
* then get next block. update cursor values along the way
*/
if (process_leaf_attr_block(mp, leaf, da_bno, ino,
da_cursor->level[0].hashval = greatest_hashval;
da_cursor->level[0].bp = bp;
da_cursor->level[0].bno = da_bno;
- da_cursor->level[0].index
- = INT_GET(leaf->hdr.count, ARCH_CONVERT);
- da_cursor->level[0].dirty = repair;
+ da_cursor->level[0].index = leafhdr.count;
+ da_cursor->level[0].dirty = repair;
- if (INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != prev_bno) {
- do_warn("bad sibling back pointer for block %u in "
- "attribute fork for inode %llu\n", da_bno, ino);
+ if (leafhdr.back != prev_bno) {
+ do_warn(
+ _("bad sibling back pointer for block %u in attribute fork for inode %" PRIu64 "\n"),
+ da_bno, ino);
libxfs_putbuf(bp);
goto error_out;
}
prev_bno = da_bno;
- da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
+ da_bno = leafhdr.forw;
- if (da_bno != 0 && verify_da_path(mp, da_cursor, 0)) {
- libxfs_putbuf(bp);
- goto error_out;
+ if (da_bno != 0) {
+ if (verify_da_path(mp, da_cursor, 0, XFS_ATTR_FORK)) {
+ libxfs_putbuf(bp);
+ goto error_out;
+ }
}
current_hashval = greatest_hashval;
+ /*
+ * If block looks ok but CRC didn't match, make sure to
+ * recompute it.
+ */
+ if (!no_modify && bp->b_error == -EFSBADCRC)
+ repair++;
- if (repair && !no_modify) {
+ if (repair && !no_modify)
libxfs_writebuf(bp, 0);
- }
- else {
+ else
libxfs_putbuf(bp);
- }
} while (da_bno != 0);
- if (verify_final_da_path(mp, da_cursor, 0)) {
+ if (verify_final_da_path(mp, da_cursor, 0, XFS_ATTR_FORK)) {
/*
* verify the final path up (right-hand-side) if still ok
*/
- do_warn("bad hash path in attribute fork for inode %llu\n",
+ do_warn(
+ _("bad hash path in attribute fork for inode %" PRIu64 "\n"),
da_cursor->ino);
goto error_out;
}
* has more than just a block) btree.
*
* Note that if we run into any problems, we will trash the attribute fork.
- *
+ *
* returns 0 if things are ok, 1 if bad
- * Note this code has been based off process_node_dir.
+ * Note this code has been based off process_node_dir.
*/
-int
+static int
process_node_attr(
xfs_mount_t *mp,
xfs_ino_t ino,
* the way. Then walk the leaf blocks left-to-right, calling
* a parent-verification routine each time we traverse a block.
*/
- bzero(&da_cursor, sizeof(da_bt_cursor_t));
+ memset(&da_cursor, 0, sizeof(da_bt_cursor_t));
da_cursor.active = 0;
- da_cursor.type = 0;
da_cursor.ino = ino;
da_cursor.dip = dip;
da_cursor.greatest_bno = 0;
* now process interior node. don't have any buffers held in this path.
*/
error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_ATTR_FORK);
- if (error == 0)
+ if (error == 0)
return(1); /* 0 means unsuccessful */
/*
* the leaf dir level routine checks the interior paths
* up to the root including the final right-most path.
*/
-
+
return (process_leaf_attr_level(mp, &da_cursor));
}
+/* check v5 metadata */
+static int
+__check_attr_header(
+ struct xfs_mount *mp,
+ struct xfs_buf *bp,
+ xfs_ino_t ino)
+{
+ struct xfs_da3_blkinfo *info = bp->b_addr;
+
+ if (info->hdr.magic != cpu_to_be16(XFS_ATTR3_LEAF_MAGIC) &&
+ info->hdr.magic != cpu_to_be16(XFS_DA3_NODE_MAGIC))
+ return 0;
+
+ /* verify owner */
+ if (be64_to_cpu(info->owner) != ino) {
+ do_warn(
+_("expected owner inode %" PRIu64 ", got %llu, attr block %" PRIu64 "\n"),
+ ino, (unsigned long long)be64_to_cpu(info->owner),
+ bp->b_bn);
+ return 1;
+ }
+ /* verify block number */
+ if (be64_to_cpu(info->blkno) != bp->b_bn) {
+ do_warn(
+_("expected block %" PRIu64 ", got %llu, inode %" PRIu64 "attr block\n"),
+ bp->b_bn, (unsigned long long)be64_to_cpu(info->blkno),
+ ino);
+ return 1;
+ }
+ /* verify uuid */
+ if (platform_uuid_compare(&info->uuid, &mp->m_sb.sb_meta_uuid) != 0) {
+ do_warn(
+_("wrong FS UUID, inode %" PRIu64 " attr block %" PRIu64 "\n"),
+ ino, bp->b_bn);
+ return 1;
+ }
+
+ return 0;
+}
+
/*
* Start processing for a leaf or fuller btree.
* A leaf directory is one where the attribute fork is too big for
* returns 0 if things are ok, 1 if bad (attributes needs to be junked)
* repair is set, if anything was changed, but attributes can live thru it
*/
-
-int
+static int
process_longform_attr(
xfs_mount_t *mp,
xfs_ino_t ino,
int *repair) /* out - 1 if something was fixed */
{
xfs_attr_leafblock_t *leaf;
- xfs_dfsbno_t bno;
+ xfs_fsblock_t bno;
xfs_buf_t *bp;
xfs_dahash_t next_hashval;
int repairlinks = 0;
+ struct xfs_attr3_icleaf_hdr leafhdr;
+ int error;
*repair = 0;
bno = blkmap_get(blkmap, 0);
- if ( bno == NULLDFSBNO ) {
- if (INT_GET(dip->di_core.di_anextents, ARCH_CONVERT) == 0 &&
- dip->di_core.di_aformat == XFS_DINODE_FMT_EXTENTS )
- /* it's okay the kernel can handle this state */
- return(0);
- else {
- do_warn("block 0 of inode %llu attribute fork"
- " is missing\n", ino);
- return(1);
- }
+ if ( bno == NULLFSBLOCK ) {
+ if (dip->di_aformat == XFS_DINODE_FMT_EXTENTS &&
+ be16_to_cpu(dip->di_anextents) == 0)
+ return(0); /* the kernel can handle this state */
+ do_warn(
+ _("block 0 of inode %" PRIu64 " attribute fork is missing\n"),
+ ino);
+ return(1);
}
/* FIX FOR bug 653709 -- EKN */
if (mp->m_sb.sb_agcount < XFS_FSB_TO_AGNO(mp, bno)) {
- do_warn("agno of attribute fork of inode %llu out of "
- "regular partition\n", ino);
+ do_warn(
+ _("agno of attribute fork of inode %" PRIu64 " out of regular partition\n"), ino);
return(1);
}
bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
- XFS_FSB_TO_BB(mp, 1), 0);
+ XFS_FSB_TO_BB(mp, 1), 0, &xfs_da3_node_buf_ops);
if (!bp) {
- do_warn("can't read block 0 of inode %llu attribute fork\n",
+ do_warn(
+ _("can't read block 0 of inode %" PRIu64 " attribute fork\n"),
ino);
return(1);
}
+ if (bp->b_error == -EFSBADCRC)
+ (*repair)++;
+
+ /* is this block sane? */
+ if (__check_attr_header(mp, bp, ino)) {
+ *repair = 0;
+ libxfs_putbuf(bp);
+ return 1;
+ }
/* verify leaf block */
- leaf = (xfs_attr_leafblock_t *)XFS_BUF_PTR(bp);
+ leaf = bp->b_addr;
+ xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
/* check sibling pointers in leaf block or root block 0 before
* we have to release the btree block
*/
- if ( INT_GET(leaf->hdr.info.forw, ARCH_CONVERT) != 0
- || INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != 0) {
+ if (leafhdr.forw != 0 || leafhdr.back != 0) {
if (!no_modify) {
- do_warn("clearing forw/back pointers in block 0 "
- "for attributes in inode %llu\n", ino);
+ do_warn(
+ _("clearing forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"),
+ ino);
repairlinks = 1;
- INT_SET(leaf->hdr.info.forw, ARCH_CONVERT, 0);
- INT_SET(leaf->hdr.info.back, ARCH_CONVERT, 0);
+ leafhdr.forw = 0;
+ leafhdr.back = 0;
+ xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo,
+ leaf, &leafhdr);
} else {
- do_warn("would clear forw/back pointers in block 0 "
- "for attributes in inode %llu\n", ino);
+ do_warn(
+ _("would clear forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"), ino);
}
}
* it's possible to have a node or leaf attribute in either an
* extent format or btree format attribute fork.
*/
- switch (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)) {
+ switch (leafhdr.magic) {
case XFS_ATTR_LEAF_MAGIC: /* leaf-form attribute */
+ case XFS_ATTR3_LEAF_MAGIC:
if (process_leaf_attr_block(mp, leaf, 0, ino, blkmap,
0, &next_hashval, repair)) {
+ *repair = 0;
/* the block is bad. lose the attribute fork. */
libxfs_putbuf(bp);
- return(1);
+ return(1);
}
- *repair = *repair || repairlinks;
+ *repair = *repair || repairlinks;
break;
case XFS_DA_NODE_MAGIC: /* btree-form attribute */
+ case XFS_DA3_NODE_MAGIC:
/* must do this now, to release block 0 before the traversal */
- if (repairlinks) {
+ if ((*repair || repairlinks) && !no_modify) {
*repair = 1;
libxfs_writebuf(bp, 0);
- } else
- libxfs_putbuf(bp);
- return (process_node_attr(mp, ino, dip, blkmap)); /* + repair */
+ } else
+ libxfs_putbuf(bp);
+ error = process_node_attr(mp, ino, dip, blkmap); /* + repair */
+ if (error)
+ *repair = 0;
+ return error;
default:
- do_warn("bad attribute leaf magic # %#x for dir ino %llu\n",
- INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), ino);
+ do_warn(
+ _("bad attribute leaf magic # %#x for dir ino %" PRIu64 "\n"),
+ be16_to_cpu(leaf->hdr.info.magic), ino);
libxfs_putbuf(bp);
+ *repair = 0;
return(1);
}
- if (*repair && !no_modify)
+ if (*repair && !no_modify)
libxfs_writebuf(bp, 0);
else
libxfs_putbuf(bp);
}
-static void
-xfs_acl_get_endian(xfs_acl_t *aclp)
+static int
+xfs_acl_from_disk(
+ struct xfs_mount *mp,
+ struct xfs_icacl **aclp,
+ struct xfs_acl *dacl)
{
- xfs_acl_entry_t *ace, *end;
-
- INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
- end = &aclp->acl_entry[0]+aclp->acl_cnt;
- for (ace = &aclp->acl_entry[0]; ace < end; ace++) {
- INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag);
- INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id);
- INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm);
+ struct xfs_icacl *acl;
+ struct xfs_icacl_entry *ace;
+ struct xfs_acl_entry *dace;
+ int count;
+ int i;
+
+ count = be32_to_cpu(dacl->acl_cnt);
+ if (count > XFS_ACL_MAX_ENTRIES(mp)) {
+ do_warn(_("Too many ACL entries, count %d\n"), count);
+ *aclp = NULL;
+ return EINVAL;
+ }
+
+
+ acl = malloc(sizeof(struct xfs_icacl) +
+ count * sizeof(struct xfs_icacl_entry));
+ if (!acl) {
+ do_warn(_("cannot malloc enough for ACL attribute\n"));
+ do_warn(_("SKIPPING this ACL\n"));
+ *aclp = NULL;
+ return ENOMEM;
+ }
+
+ acl->acl_cnt = count;
+ for (i = 0; i < count; i++) {
+ ace = &acl->acl_entry[i];
+ dace = &dacl->acl_entry[i];
+
+ ace->ae_tag = be32_to_cpu(dace->ae_tag);
+ ace->ae_id = be32_to_cpu(dace->ae_id);
+ ace->ae_perm = be16_to_cpu(dace->ae_perm);
}
+
+ *aclp = acl;
+ return 0;
}
/*
* returns 1 if attributes got cleared
- * and 0 if things are ok.
+ * and 0 if things are ok.
*/
int
process_attributes(
blkmap_t *blkmap,
int *repair) /* returned if we did repair */
{
- int err;
- xfs_dinode_core_t *dinoc;
- /* REFERENCED */
+ int err;
+ __u8 aformat = dip->di_aformat;
+#ifdef DEBUG
xfs_attr_shortform_t *asf;
- dinoc = &dip->di_core;
- asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT);
+ asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR(dip);
+#endif
- if (dinoc->di_aformat == XFS_DINODE_FMT_LOCAL) {
- ASSERT(INT_GET(asf->hdr.totsize, ARCH_CONVERT) <= XFS_DFORK_ASIZE_ARCH(dip, mp, ARCH_CONVERT));
- err = process_shortform_attr(ino, dip, repair);
- } else if (dinoc->di_aformat == XFS_DINODE_FMT_EXTENTS ||
- dinoc->di_aformat == XFS_DINODE_FMT_BTREE) {
+ if (aformat == XFS_DINODE_FMT_LOCAL) {
+ ASSERT(be16_to_cpu(asf->hdr.totsize) <=
+ XFS_DFORK_ASIZE(dip, mp));
+ err = process_shortform_attr(mp, ino, dip, repair);
+ } else if (aformat == XFS_DINODE_FMT_EXTENTS ||
+ aformat == XFS_DINODE_FMT_BTREE) {
err = process_longform_attr(mp, ino, dip, blkmap,
repair);
/* if err, convert this to shortform and clear it */
/* if repair and no error, it's taken care of */
} else {
- do_warn("illegal attribute format %d, ino %llu\n",
- dinoc->di_aformat, ino);
- err = 1;
+ do_warn(_("illegal attribute format %d, ino %" PRIu64 "\n"),
+ aformat, ino);
+ err = 1;
}
return (err); /* and repair */
}
-/*
+/*
* Validate an ACL
*/
static int
-xfs_acl_valid(xfs_acl_t *aclp)
+xfs_acl_valid(
+ struct xfs_mount *mp,
+ struct xfs_acl *daclp)
{
- xfs_acl_entry_t *entry, *e;
+ struct xfs_icacl *aclp = NULL;
+ struct xfs_icacl_entry *entry, *e;
int user = 0, group = 0, other = 0, mask = 0, mask_required = 0;
int i, j;
- if (aclp == NULL)
+ if (daclp == NULL)
goto acl_invalid;
- xfs_acl_get_endian(aclp);
-
- if (aclp->acl_cnt > XFS_ACL_MAX_ENTRIES)
+ switch (xfs_acl_from_disk(mp, &aclp, daclp)) {
+ case ENOMEM:
+ return 0;
+ case EINVAL:
goto acl_invalid;
+ default:
+ break;
+ }
for (i = 0; i < aclp->acl_cnt; i++) {
entry = &aclp->acl_entry[i];
}
if (!user || !group || !other || (mask_required && !mask))
goto acl_invalid;
- else
- return 0;
+ free(aclp);
+ return 0;
acl_invalid:
+ free(aclp);
errno = EINVAL;
return (-1);
}
/*
* check whether the msentype value is valid, and do they have
- * appropriate level, category association.
- */
+ * appropriate level, category association.
+ */
switch (lp->ml_msen_type) {
- case MSEN_ADMIN_LABEL:
- case MSEN_EQUAL_LABEL:
- case MSEN_HIGH_LABEL:
- case MSEN_MLD_HIGH_LABEL:
- case MSEN_LOW_LABEL:
- case MSEN_MLD_LOW_LABEL:
+ case XFS_MSEN_ADMIN_LABEL:
+ case XFS_MSEN_EQUAL_LABEL:
+ case XFS_MSEN_HIGH_LABEL:
+ case XFS_MSEN_MLD_HIGH_LABEL:
+ case XFS_MSEN_LOW_LABEL:
+ case XFS_MSEN_MLD_LOW_LABEL:
if (lp->ml_level != 0 || lp->ml_catcount > 0 )
return (0);
break;
- case MSEN_TCSEC_LABEL:
- case MSEN_MLD_LABEL:
+ case XFS_MSEN_TCSEC_LABEL:
+ case XFS_MSEN_MLD_LABEL:
if (lp->ml_catcount > 0 &&
__check_setvalue(lp->ml_list,
lp->ml_catcount) == -1)
return (0);
break;
- case MSEN_UNKNOWN_LABEL:
+ case XFS_MSEN_UNKNOWN_LABEL:
default:
return (0);
}
* appropriate grade, division association.
*/
switch (lp->ml_mint_type) {
- case MINT_BIBA_LABEL:
+ case XFS_MINT_BIBA_LABEL:
if (lp->ml_divcount > 0 &&
__check_setvalue(lp->ml_list + lp->ml_catcount,
lp->ml_divcount) == -1)
return(0);
break;
- case MINT_EQUAL_LABEL:
- case MINT_HIGH_LABEL:
- case MINT_LOW_LABEL:
+ case XFS_MINT_EQUAL_LABEL:
+ case XFS_MINT_HIGH_LABEL:
+ case XFS_MINT_LOW_LABEL:
if (lp->ml_grade != 0 || lp->ml_divcount > 0 )
return(0);
break;