aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2021-05-11 21:51:06 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2021-05-18 20:26:00 +0000
commite2a49768a4ad938c4dc0b9ce11298b409832a9ab (patch)
tree135ffff50873121c0d5ab3a2adcaa7652c663d65
parent2b8399210bb00c868b4cce86d86fc68a5a0a9121 (diff)
downloadsrc-e2a49768a4ad938c4dc0b9ce11298b409832a9ab.tar.gz
src-e2a49768a4ad938c4dc0b9ce11298b409832a9ab.zip
Ensure that files with no allocated blocks are trimmed to zero length.
(cherry picked from commit a3628327e7b62c955e7bad9e43044cdb01984d80)
-rw-r--r--sbin/fsck_ffs/pass1.c38
1 files changed, 25 insertions, 13 deletions
diff --git a/sbin/fsck_ffs/pass1.c b/sbin/fsck_ffs/pass1.c
index c1f1b1ec04f5..319a324cc070 100644
--- a/sbin/fsck_ffs/pass1.c
+++ b/sbin/fsck_ffs/pass1.c
@@ -248,7 +248,7 @@ checkinode(ino_t inumber, struct inodesc *idesc, int rebuildcg)
off_t kernmaxfilesize;
ufs2_daddr_t ndb;
mode_t mode;
- uintmax_t fixsize;
+ intmax_t size, fixsize;
int j, ret, offset;
if ((dp = getnextinode(inumber, rebuildcg)) == NULL)
@@ -429,25 +429,37 @@ checkinode(ino_t inumber, struct inodesc *idesc, int rebuildcg)
}
}
/*
+ * UFS does not allow files to end with a hole; it requires that
+ * the last block of a file be allocated. The last allocated block
+ * in a file is tracked in id_lballoc. Here, we check for a size
+ * past the last allocated block of the file and if that is found,
+ * shorten the file to reference the last allocated block to avoid
+ * having it reference a hole at its end.
+ *
* Soft updates will always ensure that the file size is correct
* for files that contain only direct block pointers. However
* soft updates does not roll back sizes for files with indirect
* blocks that it has set to unallocated because their contents
* have not yet been written to disk. Hence, the file can appear
* to have a hole at its end because the block pointer has been
- * rolled back to zero. Thus, id_lballoc tracks the last allocated
- * block in the file. Here, for files that extend into indirect
- * blocks, we check for a size past the last allocated block of
- * the file and if that is found, shorten the file to reference
- * the last allocated block to avoid having it reference a hole
- * at its end.
+ * rolled back to zero. Thus finding a hole at the end of a file
+ * that is located in an indirect block receives only a warning
+ * while finding a hole at the end of a file in a direct block
+ * receives a fatal error message.
*/
- if (DIP(dp, di_size) > UFS_NDADDR * sblock.fs_bsize &&
- idesc->id_lballoc < lblkno(&sblock, DIP(dp, di_size) - 1)) {
- fixsize = lblktosize(&sblock, idesc->id_lballoc + 1);
- pwarn("INODE %lu: FILE SIZE %ju BEYOND END OF ALLOCATED FILE, "
- "SIZE SHOULD BE %ju", (u_long)inumber,
- (uintmax_t)DIP(dp, di_size), fixsize);
+ size = DIP(dp, di_size);
+ if (idesc->id_lballoc < lblkno(&sblock, size - 1) &&
+ /* exclude embedded symbolic links */
+ ((mode != IFLNK) || size >= sblock.fs_maxsymlinklen)) {
+ fixsize = lblktosize(&sblock, idesc->id_lballoc + 1);
+ if (size > UFS_NDADDR * sblock.fs_bsize)
+ pwarn("INODE %lu: FILE SIZE %ju BEYOND END OF "
+ "ALLOCATED FILE, SIZE SHOULD BE %ju",
+ (u_long)inumber, size, fixsize);
+ else
+ pfatal("INODE %lu: FILE SIZE %ju BEYOND END OF "
+ "ALLOCATED FILE, SIZE SHOULD BE %ju",
+ (u_long)inumber, size, fixsize);
if (preen)
printf(" (ADJUSTED)\n");
else if (reply("ADJUST") == 0)