static void
unixfs_internal_fini(void* filsys)
{
    struct super_block* sb = (struct super_block*)filsys;
    struct filsys* fs = (struct filsys*)sb->s_fs_info;
    ino_t i = fs->s_lastino;
    for (; i >= ROOTINO; i--) {
        struct inode* tmp = unixfs_internal_iget(i);
        if (tmp) {
            struct cpio_newc_node_info* ci =
                (struct cpio_newc_node_info*)tmp->I_private;
            if (ci) {
                free(ci->ci_name);
                if (ci->ci_linktargetname)
                    free(ci->ci_linktargetname);
            }
            unixfs_internal_iput(tmp);
            unixfs_internal_iput(tmp);
        }
    }

    unixfs_inodelayer_fini();

    if (sb) {
        if (sb->s_bdev >= 0)
            close(sb->s_bdev);
        sb->s_bdev = -1;
        if (sb->s_fs_info)
            free(sb->s_fs_info);
    }
}
static int
unixfs_internal_readlink(ino_t ino, char path[UNIXFS_MAXPATHLEN])
{
    struct inode* ip = unixfs_internal_iget(ino);
    if (!ip)
        return ENOENT;

    int error;

    struct cpio_newc_node_info* ci = (struct cpio_newc_node_info*)ip->I_private;
    if (!ci->ci_linktargetname) {
        error = ENOENT;
        goto out;
    } 

    size_t linklen = min(ip->I_size, CPIO_NEWC_BLOCK);
    memcpy(path, ci->ci_linktargetname, linklen);
    path[linklen] = '\0';

    error = 0;

out:
    unixfs_internal_iput(ip);

    return error;
}
Beispiel #3
0
static int
unixfs_internal_readlink(ino_t ino, char path[UNIXFS_MAXPATHLEN])
{
    struct inode* ip = unixfs_internal_iget(ino);
    if (!ip)
        return ENOENT;

    int error = 0;

    size_t linklen =
        (ip->I_size > UNIXFS_MAXPATHLEN - 1) ? UNIXFS_MAXPATHLEN - 1: ip->I_size;

    char page[PAGE_SIZE];
    error = minixfs_get_page(ip, (off_t)0, page);
    if (error)
        goto out;
    memcpy(path, page, linklen);

    path[linklen] = '\0';

out:
    unixfs_internal_iput(ip);

    return error;
}
Beispiel #4
0
static int
unixfs_internal_igetattr(ino_t ino, struct stat* stbuf)
{
    struct inode* ip = unixfs_internal_iget(ino);
    if (!ip)
        return ENOENT;

    unixfs_internal_istat(ip, stbuf);

    unixfs_internal_iput(ip);

    return 0;
}
Beispiel #5
0
static void
unixfs_internal_fini(void* filsys)
{
    struct super_block* sb = (struct super_block*)filsys;
    struct filsys* fs = (struct filsys*)sb->s_fs_info;
    ino_t i = fs->s_lastino;
    for (; i >= ROOTINO; i--) {
        struct inode* tmp = unixfs_internal_iget(i);
        if (tmp) {
            unixfs_internal_iput(tmp);
            unixfs_internal_iput(tmp);
        }
    }

    unixfs_inodelayer_fini();

    if (sb) {
        if (sb->s_bdev >= 0)
            close(sb->s_bdev);
        sb->s_bdev = -1;
        if (sb->s_fs_info)
            free(sb->s_fs_info);
    }
}
Beispiel #6
0
static int
unixfs_internal_igetattr(ino_t ino, struct stat* stbuf)
{
    if (ino == OSXFUSE_ROOTINO)
        ino = MINIX_ROOT_INO;

    struct inode* ip = unixfs_internal_iget(ino);
    if (!ip)
        return ENOENT;

    unixfs_internal_istat(ip, stbuf);

    unixfs_internal_iput(ip);

    return 0;
}
Beispiel #7
0
static int
unixfs_internal_namei(ino_t parentino, const char* name, struct stat* stbuf)
{
    int ret = ENOENT;
    stbuf->st_ino = 0;

    size_t namelen = strlen(name);
    if (namelen > DIRSIZ)
        return ENAMETOOLONG;

    struct inode* dp = unixfs_internal_iget(parentino);
    if (!dp)
        return ENOENT;

    if (!S_ISDIR(dp->I_mode)) {
        ret = ENOTDIR;
        goto out;
    }

    struct ar_node_info* child =
        ((struct ar_node_info*)dp->I_private)->ar_children;;

    if (!child) {
        ret = ENOENT;
        goto out;
    }

    int found = 0;

    do {
        size_t target_namelen = strlen((const char*)child->ar_name);
        if ((namelen == target_namelen) &&
                (memcmp(name, child->ar_name, target_namelen) == 0)) {
            found = 1;
            break;
        }
        child = child->ar_next_sibling;
    } while (child);

    if (found)
        ret = unixfs_internal_igetattr((ino_t)child->ar_self->I_ino, stbuf);

out:
    unixfs_internal_iput(dp);

    return ret;
}
static int
unixfs_internal_nextdirentry(struct inode* dp, struct unixfs_dirbuf* dirbuf,
                             off_t* offset, struct unixfs_direntry* dent)
{
    if (*offset >= dp->I_size)
        return -1;

    if (*offset < 2) {
        int idx = 0;
        dent->name[idx++] = '.';
        dent->ino = ROOTINO;
        if (*offset == 1) {
            if (dp->I_ino != ROOTINO) {
                struct inode* pdp = unixfs_internal_iget(dp->I_ino);
                if (pdp) {
                    dent->ino = pdp->I_ino;
                    unixfs_internal_iput(pdp);
                }
            }
            dent->name[idx++] = '.';
        }
        dent->name[idx++] = '\0';
        goto out;
    }

    struct cpio_newc_node_info* child =
        ((struct cpio_newc_node_info*)dp->I_private)->ci_children;;

    off_t i;

    for (i = 0; i < (*offset - 2); i++)
        child = child->ci_next_sibling;

    dent->ino = (ino_t)child->ci_self->I_ino;
    size_t dirnamelen = strlen(child->ci_name);
    dirnamelen = min(dirnamelen, UNIXFS_MAXNAMLEN);
    memcpy(dent->name, child->ci_name, dirnamelen);
    dent->name[dirnamelen] = '\0';

out:
    *offset += 1;

    return 0;
}
Beispiel #9
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;
}
Beispiel #10
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;
}
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;
}
Beispiel #12
0
static int
unixfs_internal_namei(ino_t parentino, const char* name, struct stat* stbuf)
{
    if (parentino == OSXFUSE_ROOTINO)
        parentino = MINIX_ROOT_INO;

    stbuf->st_ino = ENOENT;

    struct inode* dir = unixfs_internal_iget(parentino);
    if (!dir)
        return ENOENT;

    if (!S_ISDIR(dir->I_mode)) {
        unixfs_internal_iput(dir);
        return ENOTDIR;
    }

    int ret = ENOENT;

    unsigned long namelen = strlen(name);
    unsigned long start, n;
    unsigned long npages = minix_dir_pages(dir);
    minix3_dirent* de3;
    minix_dirent* de;
    char page[PAGE_SIZE];
    char* kaddr = NULL;


    struct super_block* sb = dir->I_sb;
    struct minix_sb_info* sbi = minix_sb(sb);
    unsigned chunk_size = sbi->s_dirsize;
    struct minix_inode_info* minix_inode = minix_i(dir);

    start = minix_inode->i_dir_start_lookup;
    if (start >= npages)
        start = 0;
    n = start;

    ino_t found_ino = 0;

    do {
        int error = minixfs_get_page(dir, n, page);
        if (!error) {
            kaddr = (char*)page;
            if (INODE_VERSION(dir) == MINIX_V3) {
                de3 = (minix3_dirent*)kaddr;
                kaddr += PAGE_CACHE_SIZE - chunk_size;
                for (; (char*)de3 <= kaddr; de3++) {
                    if (!de3->inode)
                        continue;
                    if (minix_namecompare(namelen, chunk_size,
                                          name, de3->name)) {
                        found_ino = de3->inode;
                        goto found;
                    }
                }
            } else {
                de = (minix_dirent*)kaddr;
                kaddr += PAGE_CACHE_SIZE - chunk_size;
                for (; (char*)de <= kaddr; de++) {
                    if (!de->inode)
                        continue;
                    if (minix_namecompare(namelen, chunk_size,
                                          name, de->name)) {
                        found_ino = de->inode;
                        goto found;
                    }
                }
            }
        }

        if (++n >= npages)
            n = 0;
    } while (n != start);

found:

    if (found_ino)
        minix_inode->i_dir_start_lookup = n;

    unixfs_internal_iput(dir);

    if (found_ino)
        ret = unixfs_internal_igetattr(found_ino, stbuf);

    return ret;
}