diff options
author | Kirk McKusick <mckusick@FreeBSD.org> | 2021-05-11 21:51:06 +0000 |
---|---|---|
committer | Kirk McKusick <mckusick@FreeBSD.org> | 2021-05-18 20:26:00 +0000 |
commit | e2a49768a4ad938c4dc0b9ce11298b409832a9ab (patch) | |
tree | 135ffff50873121c0d5ab3a2adcaa7652c663d65 | |
parent | 2b8399210bb00c868b4cce86d86fc68a5a0a9121 (diff) | |
download | src-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.c | 38 |
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) |