struct inode* unixfs_internal_iget(ino_t ino) { if (ino == OSXFUSE_ROOTINO) ino = MINIX_ROOT_INO; struct super_block* sb = unixfs; struct inode* inode = unixfs_inodelayer_iget(ino); if (!inode) { fprintf(stderr, "*** fatal error: no inode for %llu\n", ino); abort(); } if (inode->I_initialized) return inode; inode->I_sb = unixfs; inode->I_blkbits = sb->s_blocksize_bits; if (minixfs_iget(sb, inode) != 0) { fprintf(stderr, "major problem: failed to read inode %llu\n", ino); unixfs_inodelayer_ifailed(inode); goto bad_inode; } unixfs_inodelayer_isucceeded(inode); return inode; bad_inode: return NULL; }
static struct inode* unixfs_internal_iget(ino_t ino) { struct inode* ip = unixfs_inodelayer_iget(ino); if (!ip) { fprintf(stderr, "*** fatal error: no inode for %llu\n", (ino64_t)ino); abort(); } if (ip->I_initialized) return ip; unixfs_inodelayer_ifailed(ip); return NULL; }
static void* unixfs_internal_init(const char* dmg, uint32_t flags, fs_endian_t fse, char** fsname, char** volname) { int fd = -1; if ((fd = open(dmg, O_RDONLY)) < 0) { perror("open"); return NULL; } int err; struct stat stbuf; struct super_block* sb = (struct super_block*)0; struct filsys* fs = (struct filsys*)0; if ((err = fstat(fd, &stbuf)) != 0) { perror("fstat"); goto out; } if (!S_ISREG(stbuf.st_mode) && !(flags & UNIXFS_FORCE)) { err = EINVAL; fprintf(stderr, "%s is not an ar image file\n", dmg); goto out; } uint16_t magic; if (read(fd, &magic, sizeof(uint16_t)) != sizeof(uint16_t)) { err = EIO; fprintf(stderr, "failed to read magic from file\n"); goto out; } uint16_t armagic = fs16_to_host(UNIXFS_FS_PDP, magic); fs_endian_t e = UNIXFS_FS_PDP; if (armagic != ARMAG) { armagic = fs16_to_host(UNIXFS_FS_BIG, magic); e = UNIXFS_FS_BIG; if (armagic != ARMAG) { err = EINVAL; fprintf(stderr, "%s is not an ar image file\n", dmg); goto out; } } sb = malloc(sizeof(struct super_block)); if (!sb) { err = ENOMEM; goto out; } assert(sizeof(struct filsys) <= BSIZE); fs = calloc(1, BSIZE); if (!fs) { free(sb); err = ENOMEM; goto out; } unixfs = sb; unixfs->s_flags = flags; unixfs->s_endian = (fse == UNIXFS_FS_INVALID) ? e : fse; unixfs->s_fs_info = (void*)fs; unixfs->s_bdev = fd; /* must initialize the inode layer before sanity checking */ if ((err = unixfs_inodelayer_init(sizeof(struct ar_node_info))) != 0) goto out; struct inode* rootip = unixfs_inodelayer_iget((ino_t)ROOTINO); if (!rootip) { fprintf(stderr, "*** fatal error: no root inode\n"); abort(); } rootip->I_mode = S_IFDIR | 0755; rootip->I_uid = getuid(); rootip->I_gid = getgid(); rootip->I_size = 2; rootip->I_atime_sec = rootip->I_mtime_sec = rootip->I_ctime_sec = time(0); struct ar_node_info* rootai = (struct ar_node_info*)rootip->I_private; rootai->ar_self = rootip; rootai->ar_name[0] = '\0'; rootai->ar_parent = NULL; rootai->ar_children = NULL; rootai->ar_next_sibling = NULL; unixfs_inodelayer_isucceeded(rootip); fs->s_fsize = (stbuf.st_size / BSIZE) + 1; fs->s_files = 0; fs->s_directories = 1 + 1 + 1; fs->s_rootip = rootip; fs->s_lastino = ROOTINO; char cnp[DIRSIZ + 1]; struct ar_hdr ar; ino_t parent_ino = ROOTINO; for (;;) { if (ancientfs_ar_readheader(fd, &ar) != 0) break; snprintf(cnp, DIRSIZ + 1, "%s", ar.ar_name); cnp[DIRSIZ] = '\0'; int missing = unixfs_internal_namei(parent_ino, cnp, &stbuf); if (!missing) /* duplicate */ goto next; struct inode* ip = unixfs_inodelayer_iget((ino_t)(fs->s_lastino + 1)); if (!ip) { fprintf(stderr, "*** fatal error: no inode for %llu\n", (ino64_t)(fs->s_lastino + 1)); abort(); } ip->I_mode = ancientfs_ar_mode(ar.ar_mode); ip->I_uid = ar.ar_uid; ip->I_gid = ar.ar_gid; ip->I_nlink = 1; ip->I_size = ar.ar_size; ip->I_atime_sec = ip->I_mtime_sec = ip->I_ctime_sec = ar.ar_date; struct ar_node_info* ai = (struct ar_node_info*)ip->I_private; ip->I_daddr[0] = (uint32_t)lseek(fd, (off_t)0, SEEK_CUR); memcpy(ai->ar_name, cnp, strlen(cnp)); ai->ar_self = ip; ai->ar_children = NULL; struct inode* parent_ip = unixfs_internal_iget(parent_ino); parent_ip->I_size += 1; ai->ar_parent = (struct ar_node_info*)(parent_ip->I_private); ai->ar_next_sibling = ai->ar_parent->ar_children; ai->ar_parent->ar_children = ai; if (S_ISDIR(ip->I_mode)) { fs->s_directories++; parent_ino = fs->s_lastino + 1; ip->I_size = 2; ip->I_daddr[0] = 0; } else { fs->s_files++; fs->s_lastino++; unixfs_internal_iput(parent_ip); unixfs_inodelayer_isucceeded(ip); /* no put */ } fs->s_lastino++; next: (void)lseek(fd, (off_t)(ar.ar_size + (ar.ar_size & 1)), SEEK_CUR); } unixfs->s_statvfs.f_bsize = BSIZE; unixfs->s_statvfs.f_frsize = BSIZE; unixfs->s_statvfs.f_ffree = 0; unixfs->s_statvfs.f_files = fs->s_files + fs->s_directories; unixfs->s_statvfs.f_blocks = fs->s_fsize; unixfs->s_statvfs.f_bfree = 0; unixfs->s_statvfs.f_bavail = 0; unixfs->s_dentsize = 1; unixfs->s_statvfs.f_namemax = DIRSIZ; snprintf(unixfs->s_fsname, UNIXFS_MNAMELEN, "UNIX Old ar"); char* dmg_basename = basename((char*)dmg); snprintf(unixfs->s_volname, UNIXFS_MAXNAMLEN, "%s (tape=%s)", unixfs_fstype, (dmg_basename) ? dmg_basename : "Archive Image"); *fsname = unixfs->s_fsname; *volname = unixfs->s_volname; out: if (err) { if (fd >= 0) close(fd); if (fs) free(fs); if (sb) free(sb); return NULL; } return sb; }
static void* unixfs_internal_init(const char* dmg, uint32_t flags, fs_endian_t fse, char** fsname, char** volname) { int fd = -1; if ((fd = open(dmg, O_RDONLY)) < 0) { perror("open"); return NULL; } int err, i, j; struct stat stbuf; struct super_block* sb = (struct super_block*)0; struct filsys* fs = (struct filsys*)0; uint32_t tapedir_begin_block = 0, tapedir_end_block = 0, last_block = 0; if ((err = fstat(fd, &stbuf)) != 0) { perror("fstat"); goto out; } if (!S_ISREG(stbuf.st_mode) && !(flags & UNIXFS_FORCE)) { err = EINVAL; fprintf(stderr, "%s is not a tape image file\n", dmg); goto out; } if (flags & ANCIENTFS_DECTAPE) { tapedir_begin_block = 0; tapedir_end_block = TAPEDIR_END_BLOCK_DEC; } else if (flags & ANCIENTFS_MAGTAPE) { tapedir_begin_block = 0; tapedir_end_block = TAPEDIR_END_BLOCK_MAG; } else if (flags & ANCIENTFS_GENTAPE) { tapedir_begin_block = 0; tapedir_end_block = TAPEDIR_END_BLOCK_GENERIC; } else { err = EINVAL; fprintf(stderr, "unrecognized tape type\n"); goto out; } if (S_ISREG(stbuf.st_mode)) last_block = stbuf.st_size / BSIZE; else last_block = tapedir_end_block; sb = malloc(sizeof(struct super_block)); if (!sb) { err = ENOMEM; goto out; } assert(sizeof(struct filsys) <= BSIZE); fs = calloc(1, BSIZE); if (!fs) { free(sb); err = ENOMEM; goto out; } unixfs = sb; unixfs->s_flags = flags; unixfs->s_endian = (fse == UNIXFS_FS_INVALID) ? UNIXFS_FS_PDP : fse; unixfs->s_fs_info = (void*)fs; unixfs->s_bdev = fd; /* must initialize the inode layer before sanity checking */ if ((err = unixfs_inodelayer_init(sizeof(struct tap_node_info))) != 0) goto out; struct inode* rootip = unixfs_inodelayer_iget((ino_t)ROOTINO); if (!rootip) { fprintf(stderr, "*** fatal error: no root inode\n"); abort(); } rootip->I_mode = S_IFDIR | 0755; rootip->I_uid = getuid(); rootip->I_gid = getgid(); rootip->I_size = 2; rootip->I_atime_sec = rootip->I_mtime_sec = rootip->I_ctime_sec = time(0); struct tap_node_info* rootti = (struct tap_node_info*)rootip->I_private; rootti->ti_self = rootip; rootti->ti_name[0] = '\0'; rootti->ti_parent = NULL; rootti->ti_children = NULL; rootti->ti_next_sibling = NULL; unixfs_inodelayer_isucceeded(rootip); fs->s_fsize = stbuf.st_size / BSIZE; fs->s_files = 0; fs->s_directories = 1 + 1 + 1; fs->s_rootip = rootip; fs->s_lastino = ROOTINO; char tapeblock[BSIZE]; for (i = tapedir_begin_block; i < tapedir_end_block; i++) { if (pread(fd, tapeblock, BSIZE, (off_t)(i * BSIZE)) != BSIZE) { fprintf(stderr, "*** fatal error: cannot read tape block %llu\n", (off_t)i); err = EIO; goto out; } struct dinode_dtp* di = (struct dinode_dtp*)tapeblock; int inopb = INOPB; if (i == 0) { /* special case block 0 */ uint8_t* doff = (uint8_t*)tapeblock; fs->s_dataoffset = 64 * (256 * doff[6] + doff[7]); di = (struct dinode_dtp*)((char*)tapeblock + 128); inopb--; } else if ((i * BSIZE) >= fs->s_dataoffset) { i = tapedir_end_block; j = inopb; break; } for (j = 0; j < inopb; j++, di++) { /* no checksum? */ if (!di->di_path[0]) { if (flags & ANCIENTFS_GENTAPE) { i = tapedir_end_block; j = inopb; } continue; } ino_t parent_ino = ROOTINO; char* path = (char*)di->di_path; size_t pathlen = strlen(path); if ((*path == '.') && ((pathlen == 1) || ((pathlen == 2) && (*(path + 1) == '/')))) { /* root */ rootip->I_mode = fs16_to_host(unixfs->s_endian, di->di_mode); rootip->I_atime_sec = \ rootip->I_mtime_sec = \ rootip->I_ctime_sec = \ fs32_to_host(unixfs->s_endian, di->di_mtime); continue; } /* we don't deal with many fancy paths here: just '/' and './' */ if (*path == '/') path++; else if (*path == '.' && *(path + 1) == '/') path += 2; char *cnp, *term; for (cnp = strtok_r(path, "/", &term); cnp; cnp = strtok_r(NULL, "/", &term)) { /* we have { parent_ino, cnp } */ struct stat stbuf; int missing = unixfs_internal_namei(parent_ino, cnp, &stbuf); if (!missing) { parent_ino = stbuf.st_ino; continue; } struct inode* ip = unixfs_inodelayer_iget((ino_t)(fs->s_lastino + 1)); if (!ip) { fprintf(stderr, "*** fatal error: no inode for %llu\n", (ino64_t)(fs->s_lastino + 1)); abort(); } ip->I_mode = fs16_to_host(unixfs->s_endian, di->di_mode); ip->I_uid = di->di_uid; ip->I_gid = di->di_gid; ip->I_size = di->di_size0 << 16 | fs16_to_host(unixfs->s_endian, di->di_size1); ip->I_daddr[0] = (uint32_t)fs16_to_host(unixfs->s_endian, di->di_addr); ip->I_nlink = 1; ip->I_atime_sec = ip->I_mtime_sec = ip->I_ctime_sec = fs32_to_host(unixfs->s_endian, di->di_mtime); struct tap_node_info* ti = (struct tap_node_info*)ip->I_private; memcpy(ti->ti_name, cnp, strlen(cnp)); ti->ti_self = ip; ti->ti_children = NULL; /* this should work out as long as we have no corruption */ struct inode* parent_ip = unixfs_internal_iget(parent_ino); parent_ip->I_size += 1; ti->ti_parent = (struct tap_node_info*)(parent_ip->I_private); ti->ti_next_sibling = ti->ti_parent->ti_children; ti->ti_parent->ti_children = ti; if (S_ISDIR(ancientfs_dtp_mode(ip->I_mode, flags))) { fs->s_directories++; parent_ino = fs->s_lastino + 1; ip->I_size = 2; ip->I_daddr[0] = 0; } else fs->s_files++; fs->s_lastino++; unixfs_internal_iput(parent_ip); unixfs_inodelayer_isucceeded(ip); /* no put */ } } } unixfs->s_statvfs.f_bsize = BSIZE; unixfs->s_statvfs.f_frsize = BSIZE; unixfs->s_statvfs.f_ffree = 0; unixfs->s_statvfs.f_files = fs->s_files + fs->s_directories; unixfs->s_statvfs.f_blocks = fs->s_fsize; unixfs->s_statvfs.f_bfree = 0; unixfs->s_statvfs.f_bavail = 0; unixfs->s_dentsize = 1; unixfs->s_statvfs.f_namemax = DIRSIZ; snprintf(unixfs->s_fsname, UNIXFS_MNAMELEN, "UNIX dtp"); char* dmg_basename = basename((char*)dmg); snprintf(unixfs->s_volname, UNIXFS_MAXNAMLEN, "%s (tape=%s)", unixfs_fstype, (dmg_basename) ? dmg_basename : "Tape Image"); *fsname = unixfs->s_fsname; *volname = unixfs->s_volname; out: if (err) { if (fd >= 0) close(fd); if (fs) free(fs); if (sb) free(sb); return NULL; } return sb; }
static void* unixfs_internal_init(const char* dmg, uint32_t flags, fs_endian_t fse, char** fsname, char** volname) { int fd = -1; if ((fd = open(dmg, O_RDONLY)) < 0) { perror("open"); return NULL; } int err; struct stat stbuf; struct super_block* sb = (struct super_block*)0; struct filsys* fs = (struct filsys*)0; if ((err = fstat(fd, &stbuf)) != 0) { perror("fstat"); goto out; } if (!S_ISREG(stbuf.st_mode) && !(flags & UNIXFS_FORCE)) { err = EINVAL; fprintf(stderr, "%s is not a tape image file\n", dmg); goto out; } struct cpio_newc_header hdr; if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { fprintf(stderr, "failed to read data from file\n"); err = EIO; goto out; } char* magic = CPIO_NEWC_MAGIC; if (unixfs->s_flags & ANCIENTFS_NEWCRC) magic = CPIO_NEWCRC_MAGIC; if (strncmp(hdr.c_magic, magic, CPIO_NEWC_MAGLEN) != 0) { fprintf(stderr, "not recognized as a cpio_newc archive\n"); err = EINVAL; goto out; } sb = malloc(sizeof(struct super_block)); if (!sb) { err = ENOMEM; goto out; } assert(sizeof(struct filsys) <= CPIO_NEWC_BLOCK); fs = calloc(1, CPIO_NEWC_BLOCK); if (!fs) { free(sb); err = ENOMEM; goto out; } unixfs = sb; unixfs->s_flags = flags; /* not used */ unixfs->s_endian = (fse == UNIXFS_FS_INVALID) ? UNIXFS_FS_LITTLE : fse; unixfs->s_fs_info = (void*)fs; unixfs->s_bdev = fd; /* must initialize the inode layer before sanity checking */ if ((err = unixfs_inodelayer_init(sizeof(struct cpio_newc_node_info))) != 0) goto out; struct inode* rootip = unixfs_inodelayer_iget((ino_t)ROOTINO); if (!rootip) { fprintf(stderr, "*** fatal error: no root inode\n"); abort(); } rootip->I_mode = S_IFDIR | 0755; rootip->I_uid = getuid(); rootip->I_gid = getgid(); rootip->I_size = 2; rootip->I_atime_sec = rootip->I_mtime_sec = rootip->I_ctime_sec = time(0); struct cpio_newc_node_info* rootci = (struct cpio_newc_node_info*)rootip->I_private; rootci->ci_self = rootip; rootci->ci_parent = NULL; rootci->ci_children = NULL; rootci->ci_next_sibling = NULL; unixfs_inodelayer_isucceeded(rootip); fs->s_fsize = stbuf.st_size / CPIO_NEWC_BLOCK; fs->s_files = 0; fs->s_directories = 1 + 1 + 1; fs->s_rootip = rootip; fs->s_lastino = ROOTINO; lseek(fd, (off_t)0, SEEK_SET); /* rewind tape */ struct cpio_newc_entry _ce, *ce = &_ce; for (;;) { if ((err = ancientfs_cpio_newc_readheader(fd, ce)) != 0) { if (err == 1) break; else { fprintf(stderr, "*** fatal error: cannot read block (error %d)\n", err); err = EIO; goto out; } } char* path = ce->name; ino_t parent_ino = ROOTINO; size_t pathlen = strlen(ce->name); if ((*path == '.') && ((pathlen == 1) || ((pathlen == 2) && (*(path + 1) == '/')))) { /* root */ rootip->I_mode = ce->stat.st_mode; rootip->I_atime_sec = \ rootip->I_mtime_sec = \ rootip->I_ctime_sec = ce->stat.st_mtime; continue; } /* we don't deal with many fancy paths here: just '/' and './' */ if (*path == '/') path++; else if (*path == '.' && *(path + 1) == '/') path += 2; char *cnp, *term; for (cnp = strtok_r(path, "/", &term); cnp; cnp = strtok_r(NULL, "/", &term)) { /* we have { parent_ino, cnp } */ struct stat stbuf; int missing = unixfs_internal_namei(parent_ino, cnp, &stbuf); if (!missing) { parent_ino = stbuf.st_ino; if (!term) { /* out of order */ struct inode* dirp = unixfs_inodelayer_iget(parent_ino); if (!dirp || !dirp->I_initialized) { fprintf(stderr, "*** fatal error: inode %llu inconsistent\n", (ino64_t)parent_ino); abort(); } dirp->I_mode = ce->stat.st_mode; dirp->I_uid = ce->stat.st_uid; dirp->I_gid = ce->stat.st_gid; unixfs_inodelayer_iput(dirp); } continue; } struct inode* ip = unixfs_inodelayer_iget((ino_t)(fs->s_lastino + 1)); /* unixfs_inodelayer_iget(ce->stat.st_ino); */ if (!ip) { fprintf(stderr, "*** fatal error: no inode for %llu\n", (ino64_t)(fs->s_lastino + 1)); abort(); } ip->I_mode = ce->stat.st_mode; ip->I_uid = ce->stat.st_uid; ip->I_gid = ce->stat.st_gid; ip->I_size = ce->stat.st_size; ip->I_nlink = ce->stat.st_nlink; ip->I_rdev = ce->stat.st_rdev; ip->I_atime_sec = ip->I_mtime_sec = ip->I_ctime_sec = ce->stat.st_mtime; struct cpio_newc_node_info* ci = (struct cpio_newc_node_info*)ip->I_private; size_t namelen = strlen(cnp); ci->ci_name = malloc(namelen + 1); if (!ci->ci_name) { fprintf(stderr, "*** fatal error: cannot allocate memory\n"); abort(); } memcpy(ci->ci_name, cnp, namelen); ci->ci_name[namelen] = '\0'; ip->I_daddr[0] = 0; if (S_ISLNK(ip->I_mode)) { namelen = strlen(ce->linktargetname); ci->ci_linktargetname = malloc(namelen + 1); if (!ci->ci_name) { fprintf(stderr, "*** fatal error: cannot allocate memory\n"); abort(); } memcpy(ci->ci_linktargetname, ce->linktargetname, namelen); ci->ci_linktargetname[namelen] = '\0'; } else if (S_ISREG(ip->I_mode)) { ip->I_daddr[0] = ce->daddr; } ci->ci_self = ip; ci->ci_children = NULL; struct inode* parent_ip = unixfs_internal_iget(parent_ino); parent_ip->I_size += 1; ci->ci_parent = (struct cpio_newc_node_info*)(parent_ip->I_private); ci->ci_next_sibling = ci->ci_parent->ci_children; ci->ci_parent->ci_children = ci; if (term && !S_ISDIR(ip->I_mode)) /* out of order */ ip->I_mode = S_IFDIR | 0755; if (S_ISDIR(ip->I_mode)) { fs->s_directories++; parent_ino = fs->s_lastino + 1; /* parent_ino = ip->I_ino; */ ip->I_size = 2; } else fs->s_files++; fs->s_lastino++; /* if (ip->I_ino > fs->s_lastino) fs->s_lastino = ip->I_ino; */ unixfs_internal_iput(parent_ip); unixfs_inodelayer_isucceeded(ip); /* no put */ } /* for each component */ } /* for each block */ err = 0; unixfs->s_statvfs.f_bsize = CPIO_NEWC_BLOCK; unixfs->s_statvfs.f_frsize = CPIO_NEWC_BLOCK; unixfs->s_statvfs.f_ffree = 0; unixfs->s_statvfs.f_files = fs->s_files + fs->s_directories; unixfs->s_statvfs.f_blocks = fs->s_fsize; unixfs->s_statvfs.f_bfree = 0; unixfs->s_statvfs.f_bavail = 0; unixfs->s_dentsize = 1; unixfs->s_statvfs.f_namemax = UNIXFS_MAXNAMLEN; snprintf(unixfs->s_fsname, UNIXFS_MNAMELEN, "ASCII cpio (newc%s)", (unixfs->s_flags & ANCIENTFS_NEWCRC) ? "rc" : ""); char* dmg_basename = basename((char*)dmg); snprintf(unixfs->s_volname, UNIXFS_MAXNAMLEN, "%s (archive=%s)", unixfs_fstype, (dmg_basename) ? dmg_basename : "cpio_newc Image"); *fsname = unixfs->s_fsname; *volname = unixfs->s_volname; out: if (err) { if (fd >= 0) close(fd); if (fs) free(fs); if (sb) free(sb); return NULL; } return sb; }
static void* unixfs_internal_init(const char* dmg, uint32_t flags, fs_endian_t fse, char** fsname, char** volname) { int fd = -1; if ((fd = open(dmg, O_RDONLY)) < 0) { perror("open"); return NULL; } int err, i; struct stat stbuf; struct super_block* sb = (struct super_block*)0; struct filsys* fs = (struct filsys*)0; assert(sizeof(struct spcl) == BSIZE); if ((err = fstat(fd, &stbuf)) != 0) { perror("fstat"); goto out; } if (!S_ISREG(stbuf.st_mode) && !(flags & UNIXFS_FORCE)) { err = EINVAL; fprintf(stderr, "%s is not a tape dump image file\n", dmg); goto out; } if ((stbuf.st_size % TAPE_BSIZE) && !(flags & UNIXFS_FORCE)) { err = EINVAL; fprintf(stderr, "%s is not a multiple of tape block size\n", dmg); goto out; } if (S_ISREG(stbuf.st_mode) && (stbuf.st_size < TAPE_BSIZE)) { err = EINVAL; fprintf(stderr, "*** fatal error: %s is smaller in size than a " "physical tape block\n", dmg); goto out; } sb = malloc(sizeof(struct super_block)); if (!sb) { err = ENOMEM; goto out; } fs = calloc(1, sizeof(struct filsys)); if (!fs) { free(sb); err = ENOMEM; goto out; } unixfs = sb; unixfs->s_flags = flags; unixfs->s_endian = (fse == UNIXFS_FS_INVALID) ? UNIXFS_FS_PDP : fse; unixfs->s_fs_info = (void*)fs; unixfs->s_bdev = fd; unixfs->s_statvfs.f_bsize = BSIZE; unixfs->s_statvfs.f_frsize = BSIZE; fs->s_fsize += stbuf.st_size / BSIZE; /* must initialize the inode layer before sanity checking */ if ((err = unixfs_inodelayer_init(sizeof(struct tap_node_info))) != 0) goto out; struct spcl spcl; if (ancientfs_dump_readheader(fd, &spcl) != 0) { fprintf(stderr, "failed to read dump header\n"); err = EINVAL; goto out; } if (spcl.c_type != TS_TAPE) { fprintf(stderr, "failed to recognize image as a tape dump\n"); err = EINVAL; goto out; } fs->s_date = fs32_to_host(unixfs->s_endian, spcl.c_date); fs->s_ddate = fs32_to_host(unixfs->s_endian, spcl.c_ddate); int done = 0; while (!done) { err = ancientfs_dump_readheader(fd, &spcl); if (err) { if (err != 1) { fprintf(stderr, "*** warning: no tape header: retrying\n"); continue; } else { fprintf(stderr, "failed to read next header (%d)\n", err); err = EINVAL; goto out; } } next: switch (spcl.c_type) { case TS_TAPE: break; case TS_END: done = 1; break; case TS_BITS: if (!fs->s_initialized) { fs->s_initialized = 1; int count = spcl.c_count; char* bmp = (char*)fs->s_dumpmap; while (count--) { if (read(fd, bmp, BSIZE) != BSIZE) { fprintf(stderr, "*** fatal error: failed to read bitmap\n"); err = EIO; goto out; } /* fix up endian-ness */ int idx; for (idx = 0; idx < BSIZE/sizeof(uint16_t); idx++) bmp[idx] = fs16_to_host(unixfs->s_endian, bmp[idx]); bmp += BSIZE / sizeof(uint16_t); } } else { fprintf(stderr, "*** warning: duplicate inode map\n"); /* ignore the data */ (void)lseek(fd, (off_t)(spcl.c_count * BSIZE), SEEK_CUR); } break; case TS_INODE: { struct dinode* dip = &spcl.c_dinode; a_ino_t candidate = spcl.c_inumber; if ((!BIT_ON(candidate, fs->s_dumpmap)) || (candidate == BADINO)) continue; struct inode* ip = unixfs_inodelayer_iget((ino_t)candidate); if (!ip) { fprintf(stderr, "*** fatal error: no inode for %llu\n", (ino64_t)candidate); abort(); } struct tap_node_info* ti = (struct tap_node_info*)ip->I_private; ti->ti_daddr = NULL; assert(!ip->I_initialized); ip->I_number = (ino_t)candidate; ip->I_mode = dip->di_mode; ip->I_nlink = dip->di_nlink; ip->I_uid = dip->di_uid; ip->I_gid = dip->di_gid; ip->I_size = dip->di_size; ip->I_atime_sec = dip->di_atime; ip->I_mtime_sec = dip->di_mtime; ip->I_ctime_sec = dip->di_ctime; if (S_ISDIR(ip->I_mode)) fs->s_directories++; else fs->s_files++; /* populate i_daddr */ off_t nblocks = (off_t)((ip->I_size + (BSIZE - 1)) / BSIZE); ti->ti_daddr = (uint32_t*)calloc(nblocks, sizeof(uint32_t)); if (!ti->ti_daddr) { fprintf(stderr, "*** fatal error: cannot allocate memory\n"); abort(); } int block_index = 0; for (i = 0; i < nblocks; i++) { if (block_index >= spcl.c_count) { if (ancientfs_dump_readheader(fd, &spcl) == -1) { fprintf(stderr, "*** fatal error: cannot read header\n"); abort(); } if (spcl.c_type != TS_ADDR) { fprintf(stderr, "*** warning: expected TS_ADDR but " "got %hd\n", spcl.c_type); int k = i; for (; k < nblocks; k++) ti->ti_daddr[k] = 0; goto next; } block_index = 0; } if (spcl.c_addr[block_index]) { off_t nextb = lseek(fd, (off_t)BSIZE, SEEK_CUR); if (nextb == -1) { fprintf(stderr, "*** fatal error: cannot read tape\n"); abort(); } ti->ti_daddr[i] = spcl.c_tapea + block_index + 1; } else { ti->ti_daddr[i] = 0; /* zero fill */ } block_index++; } if (S_ISCHR(ip->I_mode) || S_ISBLK(ip->I_mode)) { char* p1 = (char*)(ip->I_daddr); char* p2 = (char*)(dip->di_addr); for (i = 0; i < 4; i++) { *p1++ = *p2++; *p1++ = 0; *p1++ = *p2++; *p1++ = *p2++; } ip->I_daddr[0] = fs32_to_host(unixfs->s_endian, ip->I_daddr[0]); uint32_t rdev = ip->I_daddr[0]; ip->I_rdev = makedev((rdev >> 8) & 255, rdev & 255); } if (ip->I_ino > fs->s_lastino) fs->s_lastino = ip->I_ino; unixfs_inodelayer_isucceeded(ip); } break; } }