예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
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;
}
예제 #5
0
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;
}
예제 #6
0
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;
         }
    }