development
Thomas Lindner 2023-02-12 23:06:55 +01:00
parent 2bd8cca428
commit fc2b116dc2
1 changed files with 139 additions and 202 deletions

View File

@ -44,10 +44,24 @@ union dinode {
#define DIP(dp, field) \
((sblock->fs_magic == FS_UFS1_MAGIC) ? (dp)->dp1.field : (dp)->dp2.field)
typedef void (*process_fn)(union dinode *dp, void *datablock, size_t blksize,
off_t blkoff);
void usage(void);
void dump_inode(ino_t inum, union dinode *dp);
void dump_directory(union dinode *dp);
void dump_file(union dinode *dp);
void dump_data(union dinode *dp, process_fn process_data,
process_fn process_gap);
void dump_indirect(union dinode *dp, void *indirblock, int level,
off_t *filesize, process_fn process_data,
process_fn process_gap);
void process_directory(union dinode *dp, void *datablock, size_t blksize,
off_t blkoff);
void process_dirblk(int deleted, void *dirblk, size_t size);
void process_file(union dinode *dp, void *datablock, size_t blksize,
off_t blkoff);
void process_file_gap(union dinode *dp, void *datablock, size_t gapsize,
off_t blkoff);
void *xmalloc(size_t size);
void xpread(int fd, void *buf, size_t nbytes, off_t offset);
@ -158,7 +172,9 @@ int main(int argc, char **argv) {
(struct ufs2_dinode *)inoblock)[ino_to_fsbo(sblock, inum)];
}
if (mode & MODE_DIRECTORY) {
dump_directory(dp);
if ((DIP(dp, di_mode) & IFMT) == IFDIR) {
dump_data(dp, process_directory, NULL);
}
} else {
dump_inode(inum, dp);
}
@ -175,12 +191,14 @@ int main(int argc, char **argv) {
(struct ufs2_dinode *)inoblock)[ino_to_fsbo(sblock, inode)];
}
if (mode & MODE_FILE) {
dump_file(dp);
dump_data(dp, process_file, process_file_gap);
fprintf(stderr, "\r%" PRIu64 "/%" PRIu64 "\n", DIP(dp, di_size),
DIP(dp, di_size));
} else if (mode & MODE_DIRECTORY) {
if ((DIP(dp, di_mode) & IFMT) != IFDIR) {
errx(1, "Not a directory");
}
dump_directory(dp);
dump_data(dp, process_directory, NULL);
} else {
dump_inode(inode, dp);
}
@ -233,10 +251,99 @@ void dump_inode(ino_t inum, union dinode *dp) {
DIP(dp, di_mtime), DIP(dp, di_ctime));
}
void dump_dirblk(int deleted, void *dirblk, size_t size) {
void dump_data(union dinode *dp, process_fn process_data,
process_fn process_gap) {
char *datablock = xmalloc(sblock->fs_bsize);
off_t filesize = DIP(dp, di_size);
for (int i = 0; filesize > 0 && i < NDADDR;
filesize -= sblock->fs_bsize, i++) {
if (!DIP(dp, di_db[i])) {
if (process_gap) {
memset(datablock, 0, sblock->fs_bsize);
process_gap(dp, datablock, sblock->fs_bsize,
DIP(dp, di_size) - filesize);
}
continue;
}
size_t blksize = sblksize(sblock, DIP(dp, di_size), i);
daddr_t blkno = fsbtodb(sblock, DIP(dp, di_db[i]));
xpread(diskfd, datablock, blksize, blkno * DEV_BSIZE);
if (filesize < blksize) {
blksize = filesize;
}
process_data(dp, datablock, blksize, DIP(dp, di_size) - filesize);
}
for (int i = 0; filesize > 0 && i < NIADDR; i++) {
if (!DIP(dp, di_ib[i])) {
size_t gapsize = NINDIR(sblock) * sblock->fs_bsize;
for (int j = 0; j < i; j++) {
gapsize *= NINDIR(sblock);
}
if (process_gap) {
memset(datablock, 0, sblock->fs_bsize);
process_gap(dp, datablock, gapsize, DIP(dp, di_size) - filesize);
}
filesize -= gapsize;
continue;
}
daddr_t blkno = fsbtodb(sblock, DIP(dp, di_ib[i]));
xpread(diskfd, datablock, sblock->fs_bsize, blkno * DEV_BSIZE);
dump_indirect(dp, datablock, i, &filesize, process_data, process_gap);
}
free(datablock);
}
void dump_indirect(union dinode *dp, void *indirblock, int level,
off_t *filesize, process_fn process_data,
process_fn process_gap) {
void *datablock = xmalloc(sblock->fs_bsize);
for (int i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
daddr_t fsblkno;
if (sblock->fs_magic == FS_UFS1_MAGIC) {
fsblkno = ((uint32_t *)indirblock)[i];
} else {
fsblkno = ((uint64_t *)indirblock)[i];
}
if (!fsblkno) {
size_t gapsize = sblock->fs_bsize;
for (int j = 0; j < level; j++) {
gapsize *= NINDIR(sblock);
}
if (process_gap) {
memset(datablock, 0, sblock->fs_bsize);
process_gap(dp, datablock, gapsize, DIP(dp, di_size) - *filesize);
}
*filesize -= gapsize;
continue;
}
size_t blksize = sblock->fs_bsize;
daddr_t blkno = fsbtodb(sblock, fsblkno);
xpread(diskfd, datablock, blksize, blkno * DEV_BSIZE);
if (level) {
dump_indirect(dp, datablock, level - 1, filesize, process_data,
process_gap);
} else {
if (*filesize < blksize) {
blksize = *filesize;
}
process_data(dp, datablock, blksize, DIP(dp, di_size) - *filesize);
*filesize -= sblock->fs_bsize;
}
}
free(datablock);
}
void process_directory(union dinode *dp, void *datablock, size_t blksize,
off_t blkoff) {
for (size_t j = 0; j < blksize; j += DIRBLKSIZ) {
process_dirblk(0, datablock + j, MIN(blksize - j, DIRBLKSIZ));
}
}
void process_dirblk(int deleted, void *dirblk, size_t size) {
char *end = (char *)dirblk + size;
for (struct direct *d = dirblk;
(char *)&d->d_name < end && d->d_name + d->d_namlen - 1 < end;
(char *)&d->d_namlen < end && d->d_name + d->d_namlen - 1 < end;
d = (struct direct *)((char *)d + d->d_reclen)) {
char type;
switch (d->d_type) {
@ -278,210 +385,40 @@ void dump_dirblk(int deleted, void *dirblk, size_t size) {
return;
}
if (d->d_reclen > DIRSIZ(NEWDIRFMT, d)) {
dump_dirblk(1, (char *)d + DIRSIZ(NEWDIRFMT, d),
d->d_reclen - DIRSIZ(NEWDIRFMT, d));
process_dirblk(1, (char *)d + DIRSIZ(NEWDIRFMT, d),
d->d_reclen - DIRSIZ(NEWDIRFMT, d));
}
}
}
void dump_directory_indirect(union dinode *dp, void *indirblock, int level, off_t *filesize) {
void *datablock = xmalloc(sblock->fs_bsize);
if (!level) {
for (int i = 0; *filesize > 0 && i < NINDIR(sblock);
*filesize -= sblock->fs_bsize, i++) {
daddr_t fsblkno;
if (sblock->fs_magic == FS_UFS1_MAGIC) {
fsblkno = ((uint32_t *)indirblock)[i];
} else {
fsblkno = ((uint64_t *)indirblock)[i];
}
if (!fsblkno) {
continue;
}
size_t blksize = sblock->fs_bsize;
daddr_t blkno = fsbtodb(sblock, fsblkno);
xpread(diskfd, datablock, blksize, blkno * DEV_BSIZE);
if (*filesize < blksize) {
blksize = *filesize;
}
for (size_t j = 0; j < blksize; j += DIRBLKSIZ) {
dump_dirblk(0, datablock + j, MIN(blksize - j, DIRBLKSIZ));
}
void process_file(union dinode *dp, void *datablock, size_t blksize,
off_t blkoff) {
if (filefd == STDOUT_FILENO) {
xwrite(filefd, datablock, blksize);
} else {
xpwrite(filefd, datablock, blksize, blkoff);
}
if (blkoff / (1024 * 1024) != (blkoff + blksize) / (1024 * 1024)) {
fprintf(stderr, "\r%" PRIu64 "/%" PRIu64, blkoff + blksize,
DIP(dp, di_size));
}
}
void process_file_gap(union dinode *dp, void *datablock, size_t gapsize,
off_t blkoff) {
if (filefd == STDOUT_FILENO) {
for (int j = 0; j < gapsize / sblock->fs_bsize; j++) {
xwrite(filefd, datablock, sblock->fs_bsize);
}
} else {
for (int i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
daddr_t fsblkno;
if (sblock->fs_magic == FS_UFS1_MAGIC) {
fsblkno = ((uint32_t *)indirblock)[i];
} else {
fsblkno = ((uint64_t *)indirblock)[i];
}
if (!fsblkno) {
size_t gapsize = NINDIR(sblock) * sblock->fs_bsize;
for (int j = 0; j < i; j++) {
gapsize *= NINDIR(sblock);
}
*filesize -= gapsize;
continue;
}
daddr_t blkno = fsbtodb(sblock, fsblkno);
xpread(diskfd, datablock, sblock->fs_bsize, blkno * DEV_BSIZE);
dump_directory_indirect(dp, datablock, level - 1, filesize);
if (ftruncate(filefd, blkoff + gapsize) == -1) {
err(1, "ftruncate() failed");
}
}
free(datablock);
}
void dump_directory(union dinode *dp) {
if ((DIP(dp, di_mode) & IFMT) != IFDIR) {
return;
if (blkoff / (1024 * 1024) != (blkoff + gapsize) / (1024 * 1024)) {
fprintf(stderr, "\r%" PRIu64 "/%" PRIu64, blkoff + gapsize,
DIP(dp, di_size));
}
char *datablock = xmalloc(sblock->fs_bsize);
off_t filesize = DIP(dp, di_size);
for (int i = 0; filesize > 0 && i < NDADDR;
filesize -= sblock->fs_bsize, i++) {
if (!DIP(dp, di_db[i])) {
continue;
}
size_t blksize = sblksize(sblock, DIP(dp, di_size), i);
daddr_t blkno = fsbtodb(sblock, DIP(dp, di_db[i]));
xpread(diskfd, datablock, blksize, blkno * DEV_BSIZE);
if (filesize < blksize) {
blksize = filesize;
}
for (size_t j = 0; j < blksize; j += DIRBLKSIZ) {
dump_dirblk(0, datablock + j, MIN(blksize - j, DIRBLKSIZ));
}
}
for (int i = 0; filesize > 0 && i < NIADDR; i++) {
if (!DIP(dp, di_ib[i])) {
size_t gapsize = NINDIR(sblock) * sblock->fs_bsize;
for (int j = 0; j < i; j++) {
gapsize *= NINDIR(sblock);
}
filesize -= gapsize;
continue;
}
daddr_t blkno = fsbtodb(sblock, DIP(dp, di_ib[i]));
xpread(diskfd, datablock, sblock->fs_bsize, blkno * DEV_BSIZE);
dump_directory_indirect(dp, datablock, i, &filesize);
}
free(datablock);
}
void dump_file_indirect(union dinode *dp, void *indirblock, int level,
off_t *filesize) {
void *datablock = xmalloc(sblock->fs_bsize);
if (!level) {
for (int i = 0; *filesize > 0 && i < NINDIR(sblock);
*filesize -= sblock->fs_bsize, i++) {
daddr_t fsblkno;
if (sblock->fs_magic == FS_UFS1_MAGIC) {
fsblkno = ((uint32_t *)indirblock)[i];
} else {
fsblkno = ((uint64_t *)indirblock)[i];
}
if (!fsblkno) {
if (filefd == STDOUT_FILENO) {
memset(datablock, 0, sblock->fs_bsize);
xwrite(filefd, datablock, sblock->fs_bsize);
}
continue;
}
size_t blksize = sblock->fs_bsize;
daddr_t blkno = fsbtodb(sblock, fsblkno);
xpread(diskfd, datablock, blksize, blkno * DEV_BSIZE);
if (*filesize < blksize) {
blksize = *filesize;
}
if (filefd == STDOUT_FILENO) {
xwrite(filefd, datablock, blksize);
} else {
xpwrite(filefd, datablock, blksize, DIP(dp, di_size) - *filesize);
}
}
} else {
for (int i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
daddr_t fsblkno;
if (sblock->fs_magic == FS_UFS1_MAGIC) {
fsblkno = ((uint32_t *)indirblock)[i];
} else {
fsblkno = ((uint64_t *)indirblock)[i];
}
if (!fsblkno) {
size_t gapsize = NINDIR(sblock) * sblock->fs_bsize;
for (int j = 0; j < i; j++) {
gapsize *= NINDIR(sblock);
}
*filesize -= gapsize;
if (filefd == STDOUT_FILENO) {
memset(datablock, 0, sblock->fs_bsize);
for (int j = 0; j < gapsize / sblock->fs_bsize; j++) {
xwrite(filefd, datablock, sblock->fs_bsize);
}
}
continue;
}
daddr_t blkno = fsbtodb(sblock, fsblkno);
xpread(diskfd, datablock, sblock->fs_bsize, blkno * DEV_BSIZE);
dump_file_indirect(dp, datablock, level - 1, filesize);
}
}
free(datablock);
fprintf(stderr, "\r%" PRIu64 "/%" PRIu64, DIP(dp, di_size) - *filesize,
DIP(dp, di_size));
}
void dump_file(union dinode *dp) {
off_t filesize = DIP(dp, di_size);
if (filefd != STDOUT_FILENO && ftruncate(filefd, filesize) == -1) {
err(1, "ftruncate() failed");
}
void *datablock = xmalloc(sblock->fs_bsize);
int i;
for (i = 0; filesize > 0 && i < NDADDR; filesize -= sblock->fs_bsize, i++) {
if (!DIP(dp, di_db[i])) {
if (filefd == STDOUT_FILENO) {
memset(datablock, 0, sblock->fs_bsize);
xwrite(filefd, datablock, sblksize(sblock, DIP(dp, di_size), i));
}
continue;
}
size_t blksize = sblksize(sblock, DIP(dp, di_size), i);
daddr_t blkno = fsbtodb(sblock, DIP(dp, di_db[i]));
xpread(diskfd, datablock, blksize, blkno * DEV_BSIZE);
if (filesize < blksize) {
blksize = filesize;
}
if (filefd == STDOUT_FILENO) {
xwrite(filefd, datablock, blksize);
} else {
xpwrite(filefd, datablock, blksize, DIP(dp, di_size) - filesize);
}
}
for (i = 0; filesize > 0 && i < NIADDR; i++) {
if (!DIP(dp, di_ib[i])) {
size_t gapsize = NINDIR(sblock) * sblock->fs_bsize;
for (int j = 0; j < i; j++) {
gapsize *= NINDIR(sblock);
}
filesize -= gapsize;
if (filefd == STDOUT_FILENO) {
memset(datablock, 0, sblock->fs_bsize);
for (int j = 0; j < gapsize / sblock->fs_bsize; j++) {
xwrite(filefd, datablock, sblock->fs_bsize);
}
}
continue;
}
daddr_t blkno = fsbtodb(sblock, DIP(dp, di_ib[i]));
xpread(diskfd, datablock, sblock->fs_bsize, blkno * DEV_BSIZE);
dump_file_indirect(dp, datablock, i, &filesize);
}
if (i) {
fputc('\n', stderr);
}
free(datablock);
}
void *xmalloc(size_t size) {