]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/attr_repair.c
xfs_repair: allow '/' in attribute names
[thirdparty/xfsprogs-dev.git] / repair / attr_repair.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
2bd0ea18 2/*
da23017d
NS
3 * Copyright (c) 2000-2002,2004-2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
2bd0ea18
NS
5 */
6
6b803e5a 7#include "libxfs.h"
2bd0ea18
NS
8#include "globals.h"
9#include "err_protos.h"
fc49813f 10#include "attr_repair.h"
2bd0ea18
NS
11#include "dinode.h"
12#include "bmap.h"
2814f3d6 13#include "protos.h"
9a048535 14#include "dir2.h"
360f4a2e 15#include "da_util.h"
2bd0ea18 16
b5f5c2d1 17static int xfs_acl_valid(struct xfs_mount *mp, struct xfs_acl *daclp);
14290264 18static int xfs_mac_valid(xfs_mac_label_t *lp);
2bd0ea18 19
9a048535
DC
20/*
21 * da node check/verify functions that the attribute tree relies on are first in
22 * the file before the actual attribute code. This used to be shared with the
23 * dir v1 code, but that format is no longer supported yb the userspace
24 * utilities and hence is now specific to the attribute tree implementation.
25 */
9a048535
DC
26
27typedef unsigned char da_freemap_t;
28
9a048535
DC
29/*
30 * Allocate a freespace map for directory or attr leaf blocks (1 bit per byte)
31 * 1 == used, 0 == free.
32 */
33static da_freemap_t *
34alloc_da_freemap(struct xfs_mount *mp)
35{
36 return calloc(1, mp->m_sb.sb_blocksize / NBBY);
37}
38
39/*
40 * Set the he range [start, stop) in the directory freemap.
41 *
42 * Returns 1 if there is a conflict or 0 if everything's good.
43 *
44 * Within a char, the lowest bit of the char represents the byte with
45 * the smallest address
46 */
47static int
48set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop)
49{
50 const da_freemap_t mask = 0x1;
51 int i;
52
53 if (start > stop) {
54 /*
55 * allow == relation since [x, x) claims 1 byte
56 */
57 do_warn(_("bad range claimed [%d, %d) in da block\n"),
58 start, stop);
59 return(1);
60 }
61
62 if (stop > mp->m_sb.sb_blocksize) {
63 do_warn(
64 _("byte range end [%d %d) in da block larger than blocksize %d\n"),
65 start, stop, mp->m_sb.sb_blocksize);
66 return(1);
67 }
68
69 for (i = start; i < stop; i ++) {
70 if (map[i / NBBY] & (mask << i % NBBY)) {
71 do_warn(_("multiply claimed byte %d in da block\n"), i);
72 return(1);
73 }
74 map[i / NBBY] |= (mask << i % NBBY);
75 }
76
77 return(0);
78}
79
2bd0ea18 80/*
dfc130f3 81 * For attribute repair, there are 3 formats to worry about. First, is
2bd0ea18
NS
82 * shortform attributes which reside in the inode. Second is the leaf
83 * form, and lastly the btree. Much of this models after the directory
dfc130f3 84 * structure so code resembles the directory repair cases.
2bd0ea18 85 * For shortform case, if an attribute looks corrupt, it is removed.
dfc130f3 86 * If that leaves the shortform down to 0 attributes, it's okay and
2bd0ea18
NS
87 * will appear to just have a null attribute fork. Some checks are done
88 * for validity of the value field based on what the security needs are.
43533211
NS
89 * Calls will be made to xfs_mac_valid or xfs_acl_valid routines if the
90 * security attributes exist. They will be cleared if invalid.
91 * No other values will be checked. The DMF folks do not have current
2bd0ea18
NS
92 * requirements, but may in the future.
93 *
94 * For leaf block attributes, it requires more processing. One sticky
dfc130f3 95 * point is that the attributes can be local (within the leaf) or
2bd0ea18 96 * remote (outside the leaf in other blocks). Thinking of local only
ff1f79a7 97 * if you get a bad attribute, and want to delete just one, it's a-okay
2bd0ea18
NS
98 * if it remains large enough to still be a leaf block attribute. Otherwise,
99 * it may have to be converted to shortform. How to convert this and when
100 * is an issue. This call is happening in Phase3. Phase5 will capture empty
5e656dbb 101 * blocks, but Phase6 allows you to use the libxfs library which knows
2bd0ea18
NS
102 * how to handle attributes in the kernel for converting formats. What we
103 * could do is mark an attribute to be cleared now, but in phase6 somehow
104 * have it cleared for real and then the format changed to shortform if
105 * applicable. Since this requires more work than I anticipate can be
106 * accomplished for the next release, we will instead just say any bad
107 * attribute in the leaf block will make the entire attribute fork be
108 * cleared. The simplest way to do that is to ignore the leaf format, and
109 * call clear_dinode_attr to just make a shortform attribute fork with
dfc130f3 110 * zero entries.
2bd0ea18
NS
111 *
112 * Another issue with handling repair on leaf attributes is the remote
113 * blocks. To make sure that they look good and are not used multiple times
114 * by the attribute fork, some mechanism to keep track of all them is necessary.
115 * Do this in the future, time permitting. For now, note that there is no
116 * check for remote blocks and their allocations.
117 *
118 * For btree formatted attributes, the model can follow directories. That
119 * would mean go down the tree to the leftmost leaf. From there moving down
120 * the links and processing each. They would call back up the tree, to verify
121 * that the tree structure is okay. Any problems will result in the attribute
122 * fork being emptied and put in shortform format.
123 */
124
45571fd5
ES
125static int
126attr_namecheck(
127 uint8_t *name,
128 int length)
129{
130 return namecheck((char *)name, length, false);
131}
132
2bd0ea18
NS
133/*
134 * This routine just checks what security needs are for attribute values
135 * only called when root flag is set, otherwise these names could exist in
136 * in user attribute land without a conflict.
137 * If value is non-zero, then a remote attribute is being passed in
138 */
8b8a6b02 139static int
b5f5c2d1
DC
140valuecheck(
141 struct xfs_mount *mp,
142 char *namevalue,
143 char *value,
144 int namelen,
145 int valuelen)
2bd0ea18 146{
dab9b8d6 147 /* for proper alignment issues, get the structs and memmove the values */
14290264 148 xfs_mac_label_t macl;
2bd0ea18
NS
149 void *valuep;
150 int clearit = 0;
151
d6cfd5ae
ES
152 if ((namelen == SGI_ACL_FILE_SIZE &&
153 strncmp(namevalue, SGI_ACL_FILE, SGI_ACL_FILE_SIZE) == 0) ||
154 (namelen == SGI_ACL_DEFAULT_SIZE &&
155 strncmp(namevalue, SGI_ACL_DEFAULT, SGI_ACL_DEFAULT_SIZE) == 0)) {
dfc130f3 156 if (value == NULL) {
b5f5c2d1
DC
157 valuep = malloc(valuelen);
158 if (!valuep)
159 do_error(_("No memory for ACL check!\n"));
160 memcpy(valuep, namevalue + namelen, valuelen);
2bd0ea18
NS
161 } else
162 valuep = value;
163
b5f5c2d1 164 if (xfs_acl_valid(mp, valuep) != 0) {
2bd0ea18 165 clearit = 1;
507f4e33
NS
166 do_warn(
167 _("entry contains illegal value in attribute named SGI_ACL_FILE "
168 "or SGI_ACL_DEFAULT\n"));
2bd0ea18 169 }
b5f5c2d1
DC
170
171 if (valuep != value)
172 free(valuep);
173
2bd0ea18
NS
174 } else if (strncmp(namevalue, SGI_MAC_FILE, SGI_MAC_FILE_SIZE) == 0) {
175 if (value == NULL) {
dab9b8d6
BN
176 memset(&macl, 0, sizeof(xfs_mac_label_t));
177 memmove(&macl, namevalue+namelen, valuelen);
2bd0ea18 178 valuep = &macl;
dfc130f3 179 } else
2bd0ea18
NS
180 valuep = value;
181
14290264 182 if (xfs_mac_valid((xfs_mac_label_t *)valuep) != 1) { /* 1 is valid */
2bd0ea18 183 /*
dfc130f3 184 * if sysconf says MAC enabled,
2bd0ea18
NS
185 * temp = mac_from_text("msenhigh/mintlow", NULL)
186 * copy it to value, update valuelen, totsize
187 * This causes pushing up or down of all following
188 * attributes, forcing a attribute format change!!
189 * else clearit = 1;
190 */
191 clearit = 1;
507f4e33
NS
192 do_warn(
193 _("entry contains illegal value in attribute named SGI_MAC_LABEL\n"));
2bd0ea18
NS
194 }
195 } else if (strncmp(namevalue, SGI_CAP_FILE, SGI_CAP_FILE_SIZE) == 0) {
14290264 196 if ( valuelen != sizeof(xfs_cap_set_t)) {
2bd0ea18 197 clearit = 1;
507f4e33
NS
198 do_warn(
199 _("entry contains illegal value in attribute named SGI_CAP_FILE\n"));
2bd0ea18
NS
200 }
201 }
202
203 return(clearit);
204}
205
206
207/*
208 * this routine validates the attributes in shortform format.
209 * a non-zero return repair value means certain attributes are bogus
210 * and were cleared if possible. Warnings do not generate error conditions
211 * if you cannot modify the structures. repair is set to 1, if anything
212 * was fixed.
213 */
8b8a6b02 214static int
2bd0ea18 215process_shortform_attr(
b5f5c2d1 216 struct xfs_mount *mp,
2bd0ea18
NS
217 xfs_ino_t ino,
218 xfs_dinode_t *dip,
dfc130f3 219 int *repair)
2bd0ea18
NS
220{
221 xfs_attr_shortform_t *asf;
222 xfs_attr_sf_entry_t *currententry, *nextentry, *tempentry;
223 int i, junkit;
224 int currentsize, remainingspace;
dfc130f3 225
2bd0ea18
NS
226 *repair = 0;
227
46eca962 228 asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR(dip);
2bd0ea18
NS
229
230 /* Assumption: hdr.totsize is less than a leaf block and was checked
dfc130f3 231 * by lclinode for valid sizes. Check the count though.
2bd0ea18 232 */
5e656dbb 233 if (asf->hdr.count == 0)
2bd0ea18 234 /* then the total size should just be the header length */
5e656dbb 235 if (be16_to_cpu(asf->hdr.totsize) != sizeof(xfs_attr_sf_hdr_t)) {
2bd0ea18
NS
236 /* whoops there's a discrepancy. Clear the hdr */
237 if (!no_modify) {
507f4e33 238 do_warn(
5d1b7f0f 239 _("there are no attributes in the fork for inode %" PRIu64 "\n"),
507f4e33 240 ino);
f8149110 241 asf->hdr.totsize =
5e656dbb 242 cpu_to_be16(sizeof(xfs_attr_sf_hdr_t));
2bd0ea18 243 *repair = 1;
dfc130f3 244 return(1);
2bd0ea18 245 } else {
507f4e33 246 do_warn(
5d1b7f0f 247 _("would junk the attribute fork since count is 0 for inode %" PRIu64 "\n"),
507f4e33 248 ino);
2bd0ea18
NS
249 return(1);
250 }
dfc130f3
RC
251 }
252
253 currentsize = sizeof(xfs_attr_sf_hdr_t);
5e656dbb 254 remainingspace = be16_to_cpu(asf->hdr.totsize) - currentsize;
2bd0ea18 255 nextentry = &asf->list[0];
5e656dbb 256 for (i = 0; i < asf->hdr.count; i++) {
2bd0ea18
NS
257 currententry = nextentry;
258 junkit = 0;
259
260 /* don't go off the end if the hdr.count was off */
dfc130f3 261 if ((currentsize + (sizeof(xfs_attr_sf_entry_t) - 1)) >
5e656dbb 262 be16_to_cpu(asf->hdr.totsize))
2bd0ea18
NS
263 break; /* get out and reset count and totSize */
264
265 /* if the namelen is 0, can't get to the rest of the entries */
5e656dbb 266 if (currententry->namelen == 0) {
507f4e33 267 do_warn(_("zero length name entry in attribute fork,"));
2bd0ea18 268 if (!no_modify) {
507f4e33 269 do_warn(
5d1b7f0f 270 _(" truncating attributes for inode %" PRIu64 " to %d\n"), ino, i);
2bd0ea18 271 *repair = 1;
dfc130f3 272 break; /* and then update hdr fields */
2bd0ea18 273 } else {
507f4e33 274 do_warn(
5d1b7f0f 275 _(" would truncate attributes for inode %" PRIu64 " to %d\n"), ino, i);
2bd0ea18
NS
276 break;
277 }
278 } else {
279 /* It's okay to have a 0 length valuelen, but do a
280 * rough check to make sure we haven't gone outside of
281 * totsize.
282 */
5e656dbb
BN
283 if (remainingspace < currententry->namelen ||
284 ((remainingspace - currententry->
285 namelen) < currententry->valuelen)) {
507f4e33 286 do_warn(
5d1b7f0f 287 _("name or value attribute lengths are too large,\n"));
2bd0ea18 288 if (!no_modify) {
507f4e33 289 do_warn(
5d1b7f0f 290 _(" truncating attributes for inode %" PRIu64 " to %d\n"),
507f4e33 291 ino, i);
dfc130f3 292 *repair = 1;
2bd0ea18
NS
293 break; /* and then update hdr fields */
294 } else {
507f4e33 295 do_warn(
5d1b7f0f 296 _(" would truncate attributes for inode %" PRIu64 " to %d\n"),
dfc130f3 297 ino, i);
2bd0ea18 298 break;
dfc130f3 299 }
2bd0ea18
NS
300 }
301 }
dfc130f3 302
45571fd5
ES
303 /* namecheck checks for null chars in attr names. */
304 if (attr_namecheck(currententry->nameval,
305 currententry->namelen)) {
507f4e33
NS
306 do_warn(
307 _("entry contains illegal character in shortform attribute name\n"));
2bd0ea18
NS
308 junkit = 1;
309 }
310
5e656dbb 311 if (currententry->flags & XFS_ATTR_INCOMPLETE) {
507f4e33
NS
312 do_warn(
313 _("entry has INCOMPLETE flag on in shortform attribute\n"));
2bd0ea18
NS
314 junkit = 1;
315 }
316
317 /* Only check values for root security attributes */
5e656dbb 318 if (currententry->flags & XFS_ATTR_ROOT)
50aeb09d
ES
319 junkit |= valuecheck(mp,
320 (char *)&currententry->nameval[0],
f8149110 321 NULL, currententry->namelen,
5e656dbb 322 currententry->valuelen);
2bd0ea18 323
dfc130f3 324 remainingspace = remainingspace -
5e656dbb 325 XFS_ATTR_SF_ENTSIZE(currententry);
2bd0ea18
NS
326
327 if (junkit) {
328 if (!no_modify) {
329 /* get rid of only this entry */
507f4e33 330 do_warn(
5d1b7f0f 331 _("removing attribute entry %d for inode %" PRIu64 "\n"),
507f4e33 332 i, ino);
2bd0ea18 333 tempentry = (xfs_attr_sf_entry_t *)
ee6cd73e 334 ((intptr_t) currententry +
2bd0ea18
NS
335 XFS_ATTR_SF_ENTSIZE(currententry));
336 memmove(currententry,tempentry,remainingspace);
5e656dbb 337 asf->hdr.count -= 1;
2bd0ea18
NS
338 i--; /* no worries, it will wrap back to 0 */
339 *repair = 1;
340 continue; /* go back up now */
dfc130f3 341 } else {
507f4e33 342 do_warn(
5d1b7f0f 343 _("would remove attribute entry %d for inode %" PRIu64 "\n"),
507f4e33 344 i, ino);
dfc130f3
RC
345 }
346 }
2bd0ea18
NS
347
348 /* Let's get ready for the next entry... */
ee6cd73e 349 nextentry = (xfs_attr_sf_entry_t *)((intptr_t) nextentry +
5e656dbb 350 XFS_ATTR_SF_ENTSIZE(currententry));
2bd0ea18 351 currentsize = currentsize + XFS_ATTR_SF_ENTSIZE(currententry);
dfc130f3 352
507f4e33 353 } /* end the loop */
2bd0ea18 354
5e656dbb 355 if (asf->hdr.count != i) {
2bd0ea18 356 if (no_modify) {
5d1b7f0f
CH
357 do_warn(
358 _("would have corrected attribute entry count in inode %" PRIu64 " from %d to %d\n"),
5e656dbb 359 ino, asf->hdr.count, i);
2bd0ea18 360 } else {
5d1b7f0f
CH
361 do_warn(
362 _("corrected attribute entry count in inode %" PRIu64 ", was %d, now %d\n"),
5e656dbb
BN
363 ino, asf->hdr.count, i);
364 asf->hdr.count = i;
2bd0ea18
NS
365 *repair = 1;
366 }
367 }
dfc130f3 368
2bd0ea18 369 /* ASSUMPTION: currentsize <= totsize */
5e656dbb 370 if (be16_to_cpu(asf->hdr.totsize) != currentsize) {
2bd0ea18 371 if (no_modify) {
5d1b7f0f
CH
372 do_warn(
373 _("would have corrected attribute totsize in inode %" PRIu64 " from %d to %d\n"),
5e656dbb 374 ino, be16_to_cpu(asf->hdr.totsize),
507f4e33 375 currentsize);
2bd0ea18 376 } else {
5d1b7f0f
CH
377 do_warn(
378 _("corrected attribute entry totsize in inode %" PRIu64 ", was %d, now %d\n"),
5e656dbb 379 ino, be16_to_cpu(asf->hdr.totsize),
507f4e33 380 currentsize);
5e656dbb 381 asf->hdr.totsize = cpu_to_be16(currentsize);
2bd0ea18
NS
382 *repair = 1;
383 }
384 }
385
386 return(*repair);
387}
388
389/* This routine brings in blocks from disk one by one and assembles them
390 * in the value buffer. If get_bmapi gets smarter later to return an extent
391 * or list of extents, that would be great. For now, we don't expect too
392 * many blocks per remote value, so one by one is sufficient.
393 */
394static int
395rmtval_get(xfs_mount_t *mp, xfs_ino_t ino, blkmap_t *blkmap,
396 xfs_dablk_t blocknum, int valuelen, char* value)
397{
5a35bf2c 398 xfs_fsblock_t bno;
2bd0ea18
NS
399 xfs_buf_t *bp;
400 int clearit = 0, i = 0, length = 0, amountdone = 0;
3a1d34e2
DC
401 int hdrsize = 0;
402
403 if (xfs_sb_version_hascrc(&mp->m_sb))
404 hdrsize = sizeof(struct xfs_attr3_rmt_hdr);
dfc130f3 405
2bd0ea18 406 /* ASSUMPTION: valuelen is a valid number, so use it for looping */
dfc130f3 407 /* Note that valuelen is not a multiple of blocksize */
2bd0ea18
NS
408 while (amountdone < valuelen) {
409 bno = blkmap_get(blkmap, blocknum + i);
5a35bf2c 410 if (bno == NULLFSBLOCK) {
5d1b7f0f
CH
411 do_warn(
412 _("remote block for attributes of inode %" PRIu64 " is missing\n"), ino);
2bd0ea18
NS
413 clearit = 1;
414 break;
415 }
416 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
3a1d34e2
DC
417 XFS_FSB_TO_BB(mp, 1), 0,
418 &xfs_attr3_rmt_buf_ops);
2bd0ea18 419 if (!bp) {
5d1b7f0f
CH
420 do_warn(
421 _("can't read remote block for attributes of inode %" PRIu64 "\n"), ino);
2bd0ea18
NS
422 clearit = 1;
423 break;
424 }
3a1d34e2 425
12b53197 426 if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) {
3a1d34e2
DC
427 do_warn(
428 _("Corrupt remote block for attributes of inode %" PRIu64 "\n"), ino);
41b465fa 429 libxfs_putbuf(bp);
3a1d34e2
DC
430 clearit = 1;
431 break;
432 }
433
135e4bfe 434 ASSERT(mp->m_sb.sb_blocksize == bp->b_bcount);
3a1d34e2 435
68d16907 436 length = min(bp->b_bcount - hdrsize, valuelen - amountdone);
259d52fc 437 memmove(value, bp->b_addr + hdrsize, length);
2bd0ea18
NS
438 amountdone += length;
439 value += length;
440 i++;
441 libxfs_putbuf(bp);
442 }
443 return (clearit);
444}
445
2bd0ea18
NS
446/* The block is read in. The magic number and forward / backward
447 * links are checked by the caller process_leaf_attr.
448 * If any problems occur the routine returns with non-zero. In
449 * this case the next step is to clear the attribute fork, by
450 * changing it to shortform and zeroing it out. Forkoff need not
dfc130f3 451 * be changed.
2bd0ea18
NS
452 */
453
5e656dbb
BN
454static int
455process_leaf_attr_local(
b5f5c2d1 456 struct xfs_mount *mp,
5e656dbb
BN
457 xfs_attr_leafblock_t *leaf,
458 int i,
459 xfs_attr_leaf_entry_t *entry,
460 xfs_dahash_t last_hashval,
461 xfs_dablk_t da_bno,
462 xfs_ino_t ino)
463{
464 xfs_attr_leaf_name_local_t *local;
465
a24374f4 466 local = xfs_attr3_leaf_name_local(leaf, i);
45571fd5 467 if (local->namelen == 0 || attr_namecheck(local->nameval,
5e656dbb 468 local->namelen)) {
5d1b7f0f
CH
469 do_warn(
470 _("attribute entry %d in attr block %u, inode %" PRIu64 " has bad name (namelen = %d)\n"),
5e656dbb
BN
471 i, da_bno, ino, local->namelen);
472 return -1;
473 }
474
475 /* Check on the hash value. Checking order of values
476 * is not necessary, since one wrong clears the whole
477 * fork. If the ordering's wrong, it's caught here or
478 * the kernel code has a bug with transaction logging
479 * or attributes itself. Being paranoid, let's check
480 * ordering anyway in case both the name value and the
481 * hashvalue were wrong but matched. Unlikely, however.
482 */
483 if (be32_to_cpu(entry->hashval) != libxfs_da_hashname(
484 &local->nameval[0], local->namelen) ||
485 be32_to_cpu(entry->hashval) < last_hashval) {
5d1b7f0f
CH
486 do_warn(
487 _("bad hashvalue for attribute entry %d in attr block %u, inode %" PRIu64 "\n"),
488 i, da_bno, ino);
5e656dbb
BN
489 return -1;
490 }
491
492 /* Only check values for root security attributes */
493 if (entry->flags & XFS_ATTR_ROOT) {
f8149110 494 if (valuecheck(mp, (char *)&local->nameval[0], NULL,
5e656dbb 495 local->namelen, be16_to_cpu(local->valuelen))) {
5d1b7f0f
CH
496 do_warn(
497 _("bad security value for attribute entry %d in attr block %u, inode %" PRIu64 "\n"),
5e656dbb
BN
498 i, da_bno, ino);
499 return -1;
500 }
501 }
f8149110 502 return xfs_attr_leaf_entsize_local(local->namelen,
5e656dbb
BN
503 be16_to_cpu(local->valuelen));
504}
505
506static int
507process_leaf_attr_remote(
508 xfs_attr_leafblock_t *leaf,
509 int i,
510 xfs_attr_leaf_entry_t *entry,
511 xfs_dahash_t last_hashval,
512 xfs_dablk_t da_bno,
513 xfs_ino_t ino,
514 xfs_mount_t *mp,
515 blkmap_t *blkmap)
516{
517 xfs_attr_leaf_name_remote_t *remotep;
518 char* value;
519
a24374f4 520 remotep = xfs_attr3_leaf_name_remote(leaf, i);
5e656dbb 521
45571fd5 522 if (remotep->namelen == 0 || attr_namecheck(remotep->name,
f8149110
JT
523 remotep->namelen) ||
524 be32_to_cpu(entry->hashval) !=
525 libxfs_da_hashname((unsigned char *)&remotep->name[0],
5e656dbb
BN
526 remotep->namelen) ||
527 be32_to_cpu(entry->hashval) < last_hashval ||
528 be32_to_cpu(remotep->valueblk) == 0) {
5d1b7f0f
CH
529 do_warn(
530 _("inconsistent remote attribute entry %d in attr block %u, ino %" PRIu64 "\n"), i, da_bno, ino);
5e656dbb
BN
531 return -1;
532 }
533
5e656dbb
BN
534 value = malloc(be32_to_cpu(remotep->valuelen));
535 if (value == NULL) {
5d1b7f0f
CH
536 do_warn(
537 _("cannot malloc enough for remotevalue attribute for inode %" PRIu64 "\n"),
538 ino);
5e656dbb
BN
539 do_warn(_("SKIPPING this remote attribute\n"));
540 goto out;
541 }
542 if (rmtval_get(mp, ino, blkmap, be32_to_cpu(remotep->valueblk),
543 be32_to_cpu(remotep->valuelen), value)) {
5d1b7f0f
CH
544 do_warn(
545 _("remote attribute get failed for entry %d, inode %" PRIu64 "\n"),
546 i, ino);
5e656dbb
BN
547 goto bad_free_out;
548 }
930af869
DW
549 if ((entry->flags & XFS_ATTR_ROOT) &&
550 valuecheck(mp, (char *)&remotep->name[0], value, remotep->namelen,
5e656dbb 551 be32_to_cpu(remotep->valuelen))) {
5d1b7f0f
CH
552 do_warn(
553 _("remote attribute value check failed for entry %d, inode %" PRIu64 "\n"),
554 i, ino);
5e656dbb
BN
555 goto bad_free_out;
556 }
557 free(value);
558out:
56b2de80 559 return xfs_attr_leaf_entsize_remote(remotep->namelen);
5e656dbb
BN
560
561bad_free_out:
562 free(value);
563 return -1;
564}
565
8b8a6b02 566static int
2bd0ea18
NS
567process_leaf_attr_block(
568 xfs_mount_t *mp,
569 xfs_attr_leafblock_t *leaf,
570 xfs_dablk_t da_bno,
571 xfs_ino_t ino,
572 blkmap_t *blkmap,
573 xfs_dahash_t last_hashval,
574 xfs_dahash_t *current_hashval,
dfc130f3 575 int *repair)
2bd0ea18
NS
576{
577 xfs_attr_leaf_entry_t *entry;
2bd0ea18 578 int i, start, stop, clearit, usedbs, firstb, thissize;
356357a4 579 da_freemap_t *attr_freemap;
658ac3e3 580 struct xfs_attr3_icleaf_hdr leafhdr;
2bd0ea18 581
19ebedcf 582 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
2bd0ea18 583 clearit = usedbs = 0;
dfc130f3 584 firstb = mp->m_sb.sb_blocksize;
658ac3e3 585 stop = xfs_attr3_leaf_hdr_size(leaf);
2bd0ea18
NS
586
587 /* does the count look sorta valid? */
f7140161
ES
588 if (!leafhdr.count ||
589 leafhdr.count * sizeof(xfs_attr_leaf_entry_t) + stop >
ff105f75 590 mp->m_sb.sb_blocksize) {
507f4e33 591 do_warn(
5d1b7f0f 592 _("bad attribute count %d in attr block %u, inode %" PRIu64 "\n"),
658ac3e3
DC
593 leafhdr.count, da_bno, ino);
594 return 1;
2bd0ea18 595 }
dfc130f3 596
356357a4 597 attr_freemap = alloc_da_freemap(mp);
2bd0ea18 598 (void) set_da_freemap(mp, attr_freemap, 0, stop);
dfc130f3 599
2bd0ea18 600 /* go thru each entry checking for problems */
658ac3e3
DC
601 for (i = 0, entry = xfs_attr3_leaf_entryp(leaf);
602 i < leafhdr.count; i++, entry++) {
dfc130f3 603
2bd0ea18 604 /* check if index is within some boundary. */
ff105f75 605 if (be16_to_cpu(entry->nameidx) > mp->m_sb.sb_blocksize) {
507f4e33 606 do_warn(
5d1b7f0f 607 _("bad attribute nameidx %d in attr block %u, inode %" PRIu64 "\n"),
5e656dbb 608 be16_to_cpu(entry->nameidx), da_bno, ino);
2bd0ea18
NS
609 clearit = 1;
610 break;
507f4e33 611 }
2bd0ea18 612
5e656dbb 613 if (entry->flags & XFS_ATTR_INCOMPLETE) {
2bd0ea18 614 /* we are inconsistent state. get rid of us */
507f4e33 615 do_warn(
5d1b7f0f 616 _("attribute entry #%d in attr block %u, inode %" PRIu64 " is INCOMPLETE\n"),
2bd0ea18
NS
617 i, da_bno, ino);
618 clearit = 1;
619 break;
507f4e33 620 }
2bd0ea18
NS
621
622 /* mark the entry used */
ee6cd73e 623 start = (intptr_t)entry - (intptr_t)leaf;
2bd0ea18
NS
624 stop = start + sizeof(xfs_attr_leaf_entry_t);
625 if (set_da_freemap(mp, attr_freemap, start, stop)) {
507f4e33 626 do_warn(
5d1b7f0f 627 _("attribute entry %d in attr block %u, inode %" PRIu64 " claims already used space\n"),
507f4e33 628 i, da_bno, ino);
2bd0ea18
NS
629 clearit = 1;
630 break; /* got an overlap */
507f4e33 631 }
2bd0ea18 632
b5f5c2d1
DC
633 if (entry->flags & XFS_ATTR_LOCAL)
634 thissize = process_leaf_attr_local(mp, leaf, i, entry,
5e656dbb
BN
635 last_hashval, da_bno, ino);
636 else
637 thissize = process_leaf_attr_remote(leaf, i, entry,
638 last_hashval, da_bno, ino,
639 mp, blkmap);
640 if (thissize < 0) {
b5f5c2d1 641 clearit = 1;
5e656dbb 642 break;
2bd0ea18
NS
643 }
644
5e656dbb 645 *current_hashval = last_hashval = be32_to_cpu(entry->hashval);
2bd0ea18 646
5e656dbb
BN
647 if (set_da_freemap(mp, attr_freemap, be16_to_cpu(entry->nameidx),
648 be16_to_cpu(entry->nameidx) + thissize)) {
5d1b7f0f
CH
649 do_warn(
650 _("attribute entry %d in attr block %u, inode %" PRIu64 " claims used space\n"),
2bd0ea18
NS
651 i, da_bno, ino);
652 clearit = 1;
653 break; /* got an overlap */
dfc130f3 654 }
2bd0ea18 655 usedbs += thissize;
5e656dbb
BN
656 if (be16_to_cpu(entry->nameidx) < firstb)
657 firstb = be16_to_cpu(entry->nameidx);
2bd0ea18
NS
658
659 } /* end the loop */
660
661 if (!clearit) {
662 /* verify the header information is correct */
663
664 /* if the holes flag is set, don't reset first_used unless it's
665 * pointing to used bytes. we're being conservative here
dfc130f3 666 * since the block will get compacted anyhow by the kernel.
2bd0ea18
NS
667 */
668
f8149110 669 if ((leafhdr.holes == 0 &&
658ac3e3
DC
670 firstb != leafhdr.firstused) ||
671 leafhdr.firstused > firstb) {
2bd0ea18 672 if (!no_modify) {
507f4e33
NS
673 do_warn(
674 _("- resetting first used heap value from %d to %d in "
5d1b7f0f 675 "block %u of attribute fork of inode %" PRIu64 "\n"),
f8149110 676 leafhdr.firstused,
5e656dbb 677 firstb, da_bno, ino);
658ac3e3 678 leafhdr.firstused = firstb;
2bd0ea18
NS
679 *repair = 1;
680 } else {
507f4e33
NS
681 do_warn(
682 _("- would reset first used value from %d to %d in "
5d1b7f0f 683 "block %u of attribute fork of inode %" PRIu64 "\n"),
f8149110 684 leafhdr.firstused,
5e656dbb 685 firstb, da_bno, ino);
2bd0ea18
NS
686 }
687 }
688
658ac3e3 689 if (usedbs != leafhdr.usedbytes) {
2bd0ea18 690 if (!no_modify) {
507f4e33
NS
691 do_warn(
692 _("- resetting usedbytes cnt from %d to %d in "
5d1b7f0f 693 "block %u of attribute fork of inode %" PRIu64 "\n"),
f8149110 694 leafhdr.usedbytes,
5e656dbb 695 usedbs, da_bno, ino);
658ac3e3 696 leafhdr.usedbytes = usedbs;
2bd0ea18
NS
697 *repair = 1;
698 } else {
507f4e33
NS
699 do_warn(
700 _("- would reset usedbytes cnt from %d to %d in "
5d1b7f0f 701 "block %u of attribute fork of %" PRIu64 "\n"),
f8149110 702 leafhdr.usedbytes,
5e656dbb 703 usedbs, da_bno, ino);
2bd0ea18
NS
704 }
705 }
706
707 /* there's a lot of work in process_leaf_dir_block to go thru
708 * checking for holes and compacting if appropiate. I don't think
709 * attributes need all that, so let's just leave the holes. If
710 * we discover later that this is a good place to do compaction
dfc130f3 711 * we can add it then.
2bd0ea18
NS
712 */
713 }
aedb9c17
DW
714 /*
715 * If we're just going to zap the block, don't pretend like we
716 * repaired it, because repairing the block stops the clear
717 * operation.
718 */
719 if (clearit)
720 *repair = 0;
658ac3e3 721 if (*repair)
19ebedcf 722 xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, leaf, &leafhdr);
356357a4
CH
723
724 free(attr_freemap);
2bd0ea18
NS
725 return (clearit); /* and repair */
726}
727
728
729/*
730 * returns 0 if the attribute fork is ok, 1 if it has to be junked.
731 */
8b8a6b02 732static int
2bd0ea18
NS
733process_leaf_attr_level(xfs_mount_t *mp,
734 da_bt_cursor_t *da_cursor)
735{
736 int repair;
737 xfs_attr_leafblock_t *leaf;
738 xfs_buf_t *bp;
739 xfs_ino_t ino;
5a35bf2c 740 xfs_fsblock_t dev_bno;
2bd0ea18
NS
741 xfs_dablk_t da_bno;
742 xfs_dablk_t prev_bno;
743 xfs_dahash_t current_hashval = 0;
744 xfs_dahash_t greatest_hashval;
658ac3e3 745 struct xfs_attr3_icleaf_hdr leafhdr;
2bd0ea18
NS
746
747 da_bno = da_cursor->level[0].bno;
3eafb268 748 ino = da_cursor->ino;
ce746a29
DW
749 /*
750 * 0 is the root block and no block
751 * pointer can point to the root block of the btree
752 */
753 if (da_bno == 0) {
754 do_warn(
755 _("btree cycle detected in attribute fork for inode %" PRIu64 "\n"),
756 ino);
757 goto error_out;
758 }
759
2bd0ea18
NS
760 prev_bno = 0;
761
762 do {
763 repair = 0;
764 dev_bno = blkmap_get(da_cursor->blkmap, da_bno);
5a35bf2c 765 if (dev_bno == NULLFSBLOCK) {
5d1b7f0f
CH
766 do_warn(
767 _("can't map block %u for attribute fork for inode %" PRIu64 "\n"),
768 da_bno, ino);
dfc130f3 769 goto error_out;
2bd0ea18
NS
770 }
771
772 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno),
3a1d34e2
DC
773 XFS_FSB_TO_BB(mp, 1), 0,
774 &xfs_attr3_leaf_buf_ops);
2bd0ea18 775 if (!bp) {
5d1b7f0f
CH
776 do_warn(
777 _("can't read file block %u (fsbno %" PRIu64 ") for attribute fork of inode %" PRIu64 "\n"),
2bd0ea18
NS
778 da_bno, dev_bno, ino);
779 goto error_out;
780 }
781
658ac3e3 782 leaf = bp->b_addr;
19ebedcf 783 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
2bd0ea18
NS
784
785 /* check magic number for leaf directory btree block */
658ac3e3
DC
786 if (!(leafhdr.magic == XFS_ATTR_LEAF_MAGIC ||
787 leafhdr.magic == XFS_ATTR3_LEAF_MAGIC)) {
5d1b7f0f
CH
788 do_warn(
789 _("bad attribute leaf magic %#x for inode %" PRIu64 "\n"),
658ac3e3 790 leafhdr.magic, ino);
2bd0ea18
NS
791 libxfs_putbuf(bp);
792 goto error_out;
793 }
794
795 /*
ff1f79a7 796 * for each block, process the block, verify its path,
2bd0ea18
NS
797 * then get next block. update cursor values along the way
798 */
799 if (process_leaf_attr_block(mp, leaf, da_bno, ino,
800 da_cursor->blkmap, current_hashval,
801 &greatest_hashval, &repair)) {
802 libxfs_putbuf(bp);
803 goto error_out;
804 }
805
806 /*
807 * index can be set to hdr.count so match the
808 * indexes of the interior blocks -- which at the
809 * end of the block will point to 1 after the final
810 * real entry in the block
811 */
812 da_cursor->level[0].hashval = greatest_hashval;
813 da_cursor->level[0].bp = bp;
814 da_cursor->level[0].bno = da_bno;
658ac3e3 815 da_cursor->level[0].index = leafhdr.count;
dfc130f3 816 da_cursor->level[0].dirty = repair;
2bd0ea18 817
658ac3e3 818 if (leafhdr.back != prev_bno) {
5d1b7f0f
CH
819 do_warn(
820 _("bad sibling back pointer for block %u in attribute fork for inode %" PRIu64 "\n"),
507f4e33 821 da_bno, ino);
2bd0ea18
NS
822 libxfs_putbuf(bp);
823 goto error_out;
824 }
825
826 prev_bno = da_bno;
658ac3e3 827 da_bno = leafhdr.forw;
2bd0ea18 828
360f4a2e
ES
829 if (da_bno != 0) {
830 if (verify_da_path(mp, da_cursor, 0, XFS_ATTR_FORK)) {
831 libxfs_putbuf(bp);
832 goto error_out;
833 }
2bd0ea18
NS
834 }
835
836 current_hashval = greatest_hashval;
e41dd632
ES
837 /*
838 * If block looks ok but CRC didn't match, make sure to
839 * recompute it.
840 */
841 if (!no_modify && bp->b_error == -EFSBADCRC)
842 repair++;
2bd0ea18 843
3a1d34e2 844 if (repair && !no_modify)
2bd0ea18 845 libxfs_writebuf(bp, 0);
3a1d34e2 846 else
2bd0ea18 847 libxfs_putbuf(bp);
2bd0ea18
NS
848 } while (da_bno != 0);
849
5cd3b070 850 if (verify_final_da_path(mp, da_cursor, 0, XFS_ATTR_FORK)) {
2bd0ea18
NS
851 /*
852 * verify the final path up (right-hand-side) if still ok
853 */
5d1b7f0f
CH
854 do_warn(
855 _("bad hash path in attribute fork for inode %" PRIu64 "\n"),
2bd0ea18
NS
856 da_cursor->ino);
857 goto error_out;
858 }
859
860 /* releases all buffers holding interior btree blocks */
861 release_da_cursor(mp, da_cursor, 0);
862 return(0);
863
864error_out:
865 /* release all buffers holding interior btree blocks */
866 err_release_da_cursor(mp, da_cursor, 0);
867 return(1);
868}
869
870
871/*
872 * a node directory is a true btree -- where the attribute fork
873 * has gotten big enough that it is represented as a non-trivial (e.g.
874 * has more than just a block) btree.
875 *
876 * Note that if we run into any problems, we will trash the attribute fork.
dfc130f3 877 *
2bd0ea18 878 * returns 0 if things are ok, 1 if bad
dfc130f3 879 * Note this code has been based off process_node_dir.
2bd0ea18 880 */
8b8a6b02 881static int
2bd0ea18
NS
882process_node_attr(
883 xfs_mount_t *mp,
884 xfs_ino_t ino,
885 xfs_dinode_t *dip,
886 blkmap_t *blkmap)
887{
888 xfs_dablk_t bno;
889 int error = 0;
890 da_bt_cursor_t da_cursor;
891
892 /*
893 * try again -- traverse down left-side of tree until we hit
894 * the left-most leaf block setting up the btree cursor along
895 * the way. Then walk the leaf blocks left-to-right, calling
896 * a parent-verification routine each time we traverse a block.
897 */
dab9b8d6 898 memset(&da_cursor, 0, sizeof(da_bt_cursor_t));
2bd0ea18 899 da_cursor.active = 0;
2bd0ea18
NS
900 da_cursor.ino = ino;
901 da_cursor.dip = dip;
902 da_cursor.greatest_bno = 0;
903 da_cursor.blkmap = blkmap;
904
905 /*
906 * now process interior node. don't have any buffers held in this path.
907 */
908 error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_ATTR_FORK);
dfc130f3 909 if (error == 0)
2bd0ea18
NS
910 return(1); /* 0 means unsuccessful */
911
912 /*
913 * now pass cursor and bno into leaf-block processing routine
914 * the leaf dir level routine checks the interior paths
915 * up to the root including the final right-most path.
916 */
dfc130f3 917
2bd0ea18
NS
918 return (process_leaf_attr_level(mp, &da_cursor));
919}
920
1c8e2f03
DW
921/* check v5 metadata */
922static int
923__check_attr_header(
924 struct xfs_mount *mp,
925 struct xfs_buf *bp,
926 xfs_ino_t ino)
927{
928 struct xfs_da3_blkinfo *info = bp->b_addr;
929
930 if (info->hdr.magic != cpu_to_be16(XFS_ATTR3_LEAF_MAGIC) &&
931 info->hdr.magic != cpu_to_be16(XFS_DA3_NODE_MAGIC))
932 return 0;
933
934 /* verify owner */
935 if (be64_to_cpu(info->owner) != ino) {
936 do_warn(
937_("expected owner inode %" PRIu64 ", got %llu, attr block %" PRIu64 "\n"),
51073f86
DW
938 ino, (unsigned long long)be64_to_cpu(info->owner),
939 bp->b_bn);
1c8e2f03
DW
940 return 1;
941 }
942 /* verify block number */
943 if (be64_to_cpu(info->blkno) != bp->b_bn) {
944 do_warn(
945_("expected block %" PRIu64 ", got %llu, inode %" PRIu64 "attr block\n"),
51073f86
DW
946 bp->b_bn, (unsigned long long)be64_to_cpu(info->blkno),
947 ino);
1c8e2f03
DW
948 return 1;
949 }
950 /* verify uuid */
951 if (platform_uuid_compare(&info->uuid, &mp->m_sb.sb_meta_uuid) != 0) {
952 do_warn(
953_("wrong FS UUID, inode %" PRIu64 " attr block %" PRIu64 "\n"),
954 ino, bp->b_bn);
955 return 1;
956 }
957
958 return 0;
959}
960
2bd0ea18
NS
961/*
962 * Start processing for a leaf or fuller btree.
963 * A leaf directory is one where the attribute fork is too big for
964 * the inode but is small enough to fit into one btree block
965 * outside the inode. This code is modelled after process_leaf_dir_block.
966 *
967 * returns 0 if things are ok, 1 if bad (attributes needs to be junked)
968 * repair is set, if anything was changed, but attributes can live thru it
969 */
8b8a6b02 970static int
2bd0ea18
NS
971process_longform_attr(
972 xfs_mount_t *mp,
973 xfs_ino_t ino,
974 xfs_dinode_t *dip,
975 blkmap_t *blkmap,
976 int *repair) /* out - 1 if something was fixed */
977{
978 xfs_attr_leafblock_t *leaf;
5a35bf2c 979 xfs_fsblock_t bno;
2bd0ea18
NS
980 xfs_buf_t *bp;
981 xfs_dahash_t next_hashval;
982 int repairlinks = 0;
658ac3e3 983 struct xfs_attr3_icleaf_hdr leafhdr;
aedb9c17 984 int error;
2bd0ea18
NS
985
986 *repair = 0;
987
988 bno = blkmap_get(blkmap, 0);
989
5a35bf2c 990 if ( bno == NULLFSBLOCK ) {
f8149110 991 if (dip->di_aformat == XFS_DINODE_FMT_EXTENTS &&
56b2de80 992 be16_to_cpu(dip->di_anextents) == 0)
5e656dbb 993 return(0); /* the kernel can handle this state */
5d1b7f0f
CH
994 do_warn(
995 _("block 0 of inode %" PRIu64 " attribute fork is missing\n"),
5e656dbb
BN
996 ino);
997 return(1);
2bd0ea18
NS
998 }
999 /* FIX FOR bug 653709 -- EKN */
1000 if (mp->m_sb.sb_agcount < XFS_FSB_TO_AGNO(mp, bno)) {
5d1b7f0f
CH
1001 do_warn(
1002 _("agno of attribute fork of inode %" PRIu64 " out of regular partition\n"), ino);
2bd0ea18
NS
1003 return(1);
1004 }
1005
1006 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
658ac3e3 1007 XFS_FSB_TO_BB(mp, 1), 0, &xfs_da3_node_buf_ops);
2bd0ea18 1008 if (!bp) {
5d1b7f0f
CH
1009 do_warn(
1010 _("can't read block 0 of inode %" PRIu64 " attribute fork\n"),
2bd0ea18
NS
1011 ino);
1012 return(1);
1013 }
12b53197 1014 if (bp->b_error == -EFSBADCRC)
3a1d34e2 1015 (*repair)++;
2bd0ea18 1016
1c8e2f03
DW
1017 /* is this block sane? */
1018 if (__check_attr_header(mp, bp, ino)) {
1019 *repair = 0;
1020 libxfs_putbuf(bp);
1021 return 1;
1022 }
1023
2bd0ea18 1024 /* verify leaf block */
259d52fc 1025 leaf = bp->b_addr;
19ebedcf 1026 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
2bd0ea18
NS
1027
1028 /* check sibling pointers in leaf block or root block 0 before
1029 * we have to release the btree block
1030 */
658ac3e3 1031 if (leafhdr.forw != 0 || leafhdr.back != 0) {
2bd0ea18 1032 if (!no_modify) {
5d1b7f0f
CH
1033 do_warn(
1034 _("clearing forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"),
1035 ino);
2bd0ea18 1036 repairlinks = 1;
658ac3e3
DC
1037 leafhdr.forw = 0;
1038 leafhdr.back = 0;
19ebedcf
DC
1039 xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo,
1040 leaf, &leafhdr);
2bd0ea18 1041 } else {
5d1b7f0f
CH
1042 do_warn(
1043 _("would clear forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"), ino);
2bd0ea18
NS
1044 }
1045 }
1046
1047 /*
1048 * use magic number to tell us what type of attribute this is.
1049 * it's possible to have a node or leaf attribute in either an
1050 * extent format or btree format attribute fork.
1051 */
658ac3e3 1052 switch (leafhdr.magic) {
2bd0ea18 1053 case XFS_ATTR_LEAF_MAGIC: /* leaf-form attribute */
658ac3e3 1054 case XFS_ATTR3_LEAF_MAGIC:
2bd0ea18
NS
1055 if (process_leaf_attr_block(mp, leaf, 0, ino, blkmap,
1056 0, &next_hashval, repair)) {
aedb9c17 1057 *repair = 0;
2bd0ea18
NS
1058 /* the block is bad. lose the attribute fork. */
1059 libxfs_putbuf(bp);
dfc130f3 1060 return(1);
2bd0ea18 1061 }
dfc130f3 1062 *repair = *repair || repairlinks;
2bd0ea18
NS
1063 break;
1064
1065 case XFS_DA_NODE_MAGIC: /* btree-form attribute */
658ac3e3 1066 case XFS_DA3_NODE_MAGIC:
2bd0ea18 1067 /* must do this now, to release block 0 before the traversal */
3a1d34e2 1068 if ((*repair || repairlinks) && !no_modify) {
2bd0ea18
NS
1069 *repair = 1;
1070 libxfs_writebuf(bp, 0);
dfc130f3
RC
1071 } else
1072 libxfs_putbuf(bp);
aedb9c17
DW
1073 error = process_node_attr(mp, ino, dip, blkmap); /* + repair */
1074 if (error)
1075 *repair = 0;
1076 return error;
2bd0ea18 1077 default:
5d1b7f0f
CH
1078 do_warn(
1079 _("bad attribute leaf magic # %#x for dir ino %" PRIu64 "\n"),
5e656dbb 1080 be16_to_cpu(leaf->hdr.info.magic), ino);
2bd0ea18 1081 libxfs_putbuf(bp);
aedb9c17 1082 *repair = 0;
2bd0ea18
NS
1083 return(1);
1084 }
1085
dfc130f3 1086 if (*repair && !no_modify)
2bd0ea18
NS
1087 libxfs_writebuf(bp, 0);
1088 else
1089 libxfs_putbuf(bp);
1090
1091 return(0); /* repair may be set */
1092}
1093
1094
7675c153 1095static int
b5f5c2d1
DC
1096xfs_acl_from_disk(
1097 struct xfs_mount *mp,
1098 struct xfs_icacl **aclp,
1099 struct xfs_acl *dacl)
061313d4 1100{
b5f5c2d1
DC
1101 struct xfs_icacl *acl;
1102 struct xfs_icacl_entry *ace;
1103 struct xfs_acl_entry *dace;
5e656dbb 1104 int count;
b5f5c2d1 1105 int i;
5e656dbb
BN
1106
1107 count = be32_to_cpu(dacl->acl_cnt);
b5f5c2d1 1108 if (count > XFS_ACL_MAX_ENTRIES(mp)) {
7675c153
CH
1109 do_warn(_("Too many ACL entries, count %d\n"), count);
1110 *aclp = NULL;
1111 return EINVAL;
1112 }
1113
1114
b5f5c2d1
DC
1115 acl = malloc(sizeof(struct xfs_icacl) +
1116 count * sizeof(struct xfs_icacl_entry));
7675c153
CH
1117 if (!acl) {
1118 do_warn(_("cannot malloc enough for ACL attribute\n"));
1119 do_warn(_("SKIPPING this ACL\n"));
1120 *aclp = NULL;
1121 return ENOMEM;
1122 }
1123
5e656dbb 1124 acl->acl_cnt = count;
b5f5c2d1
DC
1125 for (i = 0; i < count; i++) {
1126 ace = &acl->acl_entry[i];
1127 dace = &dacl->acl_entry[i];
1128
5e656dbb
BN
1129 ace->ae_tag = be32_to_cpu(dace->ae_tag);
1130 ace->ae_id = be32_to_cpu(dace->ae_id);
1131 ace->ae_perm = be16_to_cpu(dace->ae_perm);
43533211 1132 }
7675c153
CH
1133
1134 *aclp = acl;
1135 return 0;
061313d4
AG
1136}
1137
2bd0ea18
NS
1138/*
1139 * returns 1 if attributes got cleared
dfc130f3 1140 * and 0 if things are ok.
2bd0ea18
NS
1141 */
1142int
1143process_attributes(
1144 xfs_mount_t *mp,
1145 xfs_ino_t ino,
1146 xfs_dinode_t *dip,
1147 blkmap_t *blkmap,
1148 int *repair) /* returned if we did repair */
1149{
5e656dbb 1150 int err;
56b2de80 1151 __u8 aformat = dip->di_aformat;
6bddecbc 1152#ifdef DEBUG
2bd0ea18
NS
1153 xfs_attr_shortform_t *asf;
1154
46eca962 1155 asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR(dip);
6bddecbc 1156#endif
2bd0ea18 1157
5e656dbb
BN
1158 if (aformat == XFS_DINODE_FMT_LOCAL) {
1159 ASSERT(be16_to_cpu(asf->hdr.totsize) <=
46eca962 1160 XFS_DFORK_ASIZE(dip, mp));
b5f5c2d1 1161 err = process_shortform_attr(mp, ino, dip, repair);
5e656dbb
BN
1162 } else if (aformat == XFS_DINODE_FMT_EXTENTS ||
1163 aformat == XFS_DINODE_FMT_BTREE) {
2bd0ea18
NS
1164 err = process_longform_attr(mp, ino, dip, blkmap,
1165 repair);
1166 /* if err, convert this to shortform and clear it */
1167 /* if repair and no error, it's taken care of */
1168 } else {
5d1b7f0f 1169 do_warn(_("illegal attribute format %d, ino %" PRIu64 "\n"),
5e656dbb 1170 aformat, ino);
dfc130f3 1171 err = 1;
2bd0ea18
NS
1172 }
1173 return (err); /* and repair */
1174}
1175
dfc130f3 1176/*
2bd0ea18
NS
1177 * Validate an ACL
1178 */
1179static int
b5f5c2d1
DC
1180xfs_acl_valid(
1181 struct xfs_mount *mp,
1182 struct xfs_acl *daclp)
2bd0ea18 1183{
b5f5c2d1
DC
1184 struct xfs_icacl *aclp = NULL;
1185 struct xfs_icacl_entry *entry, *e;
2bd0ea18
NS
1186 int user = 0, group = 0, other = 0, mask = 0, mask_required = 0;
1187 int i, j;
1188
5e656dbb 1189 if (daclp == NULL)
2bd0ea18
NS
1190 goto acl_invalid;
1191
b5f5c2d1 1192 switch (xfs_acl_from_disk(mp, &aclp, daclp)) {
7675c153 1193 case ENOMEM:
5e656dbb 1194 return 0;
7675c153 1195 case EINVAL:
2bd0ea18 1196 goto acl_invalid;
7675c153
CH
1197 default:
1198 break;
1199 }
2bd0ea18 1200
43533211 1201 for (i = 0; i < aclp->acl_cnt; i++) {
2bd0ea18 1202 entry = &aclp->acl_entry[i];
e80ad1c7
NS
1203 if (entry->ae_perm & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE))
1204 goto acl_invalid;
43533211 1205 switch (entry->ae_tag) {
2bd0ea18
NS
1206 case ACL_USER_OBJ:
1207 if (user++)
1208 goto acl_invalid;
1209 break;
1210 case ACL_GROUP_OBJ:
1211 if (group++)
1212 goto acl_invalid;
1213 break;
43533211 1214 case ACL_OTHER:
2bd0ea18
NS
1215 if (other++)
1216 goto acl_invalid;
1217 break;
1218 case ACL_USER:
1219 case ACL_GROUP:
43533211 1220 for (j = i + 1; j < aclp->acl_cnt; j++) {
2bd0ea18 1221 e = &aclp->acl_entry[j];
43533211
NS
1222 if (e->ae_id == entry->ae_id &&
1223 e->ae_tag == entry->ae_tag)
2bd0ea18
NS
1224 goto acl_invalid;
1225 }
1226 mask_required++;
1227 break;
1228 case ACL_MASK:
1229 if (mask++)
1230 goto acl_invalid;
1231 break;
1232 default:
1233 goto acl_invalid;
1234 }
1235 }
1236 if (!user || !group || !other || (mask_required && !mask))
1237 goto acl_invalid;
5e656dbb
BN
1238 free(aclp);
1239 return 0;
2bd0ea18 1240acl_invalid:
5e656dbb 1241 free(aclp);
2bd0ea18
NS
1242 errno = EINVAL;
1243 return (-1);
1244}
1245
1246/*
1247 * Check a category or division set to ensure that all values are in
1248 * ascending order and each division or category appears only once.
1249 */
1250static int
1251__check_setvalue(const unsigned short *list, unsigned short count)
1252{
43533211 1253 unsigned short i;
2bd0ea18 1254
43533211
NS
1255 for (i = 1; i < count ; i++)
1256 if (list[i] <= list[i-1])
1257 return -1;
1258 return 0;
2bd0ea18
NS
1259}
1260
2bd0ea18 1261/*
43533211 1262 * xfs_mac_valid(lp)
14290264 1263 * Check the validity of a MAC label.
2bd0ea18
NS
1264 */
1265static int
14290264 1266xfs_mac_valid(xfs_mac_label_t *lp)
2bd0ea18
NS
1267{
1268 if (lp == NULL)
1269 return (0);
1270
1271 /*
1272 * if the total category set and division set is greater than 250
1273 * report error
1274 */
14290264 1275 if ((lp->ml_catcount + lp->ml_divcount) > XFS_MAC_MAX_SETS)
2bd0ea18
NS
1276 return(0);
1277
1278 /*
1279 * check whether the msentype value is valid, and do they have
dfc130f3
RC
1280 * appropriate level, category association.
1281 */
2bd0ea18 1282 switch (lp->ml_msen_type) {
e49e365f
NS
1283 case XFS_MSEN_ADMIN_LABEL:
1284 case XFS_MSEN_EQUAL_LABEL:
1285 case XFS_MSEN_HIGH_LABEL:
1286 case XFS_MSEN_MLD_HIGH_LABEL:
1287 case XFS_MSEN_LOW_LABEL:
1288 case XFS_MSEN_MLD_LOW_LABEL:
2bd0ea18
NS
1289 if (lp->ml_level != 0 || lp->ml_catcount > 0 )
1290 return (0);
1291 break;
e49e365f
NS
1292 case XFS_MSEN_TCSEC_LABEL:
1293 case XFS_MSEN_MLD_LABEL:
2bd0ea18
NS
1294 if (lp->ml_catcount > 0 &&
1295 __check_setvalue(lp->ml_list,
1296 lp->ml_catcount) == -1)
1297 return (0);
1298 break;
e49e365f 1299 case XFS_MSEN_UNKNOWN_LABEL:
2bd0ea18
NS
1300 default:
1301 return (0);
1302 }
1303
1304 /*
1305 * check whether the minttype value is valid, and do they have
1306 * appropriate grade, division association.
1307 */
1308 switch (lp->ml_mint_type) {
e49e365f 1309 case XFS_MINT_BIBA_LABEL:
2bd0ea18
NS
1310 if (lp->ml_divcount > 0 &&
1311 __check_setvalue(lp->ml_list + lp->ml_catcount,
1312 lp->ml_divcount) == -1)
1313 return(0);
1314 break;
e49e365f
NS
1315 case XFS_MINT_EQUAL_LABEL:
1316 case XFS_MINT_HIGH_LABEL:
1317 case XFS_MINT_LOW_LABEL:
2bd0ea18
NS
1318 if (lp->ml_grade != 0 || lp->ml_divcount > 0 )
1319 return(0);
1320 break;
1321 default:
1322 return(0);
1323 }
1324
1325 return (1);
1326}