DF-3159 / trunc.c
/* * DF-3159: ftruncate() a regular file on a 64-KiB-cluster FAT32 volume * past the 32-bit MSDOSFS_FILESIZE_MAX (0xFFFFFFFF) that msdosfs_write * enforces (msdosfs_vnops.c:618) but msdosfs_setattr -> detrunc -> * deextend does not (msdosfs_denode.c:509-511, 618-647). * * de_FileSize becomes 0x100010000 (4 GiB + 64 KiB); DE_EXTERNALIZE * putulong()s the dirent size field to the low 32 bits (0x10000). After * unmount+remount the file has silently shrunk. * * usage: trunc <file> [size-bytes-hex] */ #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> int main(int argc, char **argv) { const char *path; unsigned long long sz = 0x100010000ULL; struct stat st; int fd; if (argc < 2) { fprintf(stderr, "usage: trunc <file> [size]\n"); return 2; } path = argv[1]; if (argc >= 3) sz = strtoull(argv[2], NULL, 0); fd = open(path, O_RDWR); if (fd < 0) { perror("open"); return 2; } if (fstat(fd, &st)) { perror("fstat"); return 2; } printf("before: size %jd\n", (intmax_t)st.st_size); if (ftruncate(fd, (off_t)sz) < 0) { printf("ftruncate(0x%llx) FAILED: errno=%d (%s) <-- EFBIG expected, got this\n", sz, errno, strerror(errno)); close(fd); return 1; } if (fstat(fd, &st)) { perror("fstat2"); return 2; } printf("ftruncate(0x%llx) OK; in-memory size now %jd (0x%jx)\n", sz, (intmax_t)st.st_size, (uintmax_t)st.st_size); if (st.st_size > 0xFFFFFFFFULL) printf("NOTE: size exceeds MSDOSFS_FILESIZE_MAX (0xFFFFFFFF); " "dirent field is 32-bit\n"); close(fd); return 0; } |