static int do_ext2fs_mknod()

in fs/extfs/extfs.cpp [582:666]


static int do_ext2fs_mknod(ext2_filsys fs, const char *path, unsigned int st_mode, unsigned int st_rdev) {
    ext2_ino_t parent, ino;
    errcode_t ret = 0;
    unsigned long devmajor, devminor;
    int filetype;

    DEFER(LOG_DEBUG("mknod ", VALUE(path), VALUE(parent), VALUE(ino), VALUE(ret)));
    ino = string_to_inode(fs, path, 0);
    if (ino) {
        return -(ret = EEXIST);
    }

    parent = get_parent_dir_ino(fs, path);
    if (parent == 0) {
        return -(ret = ENOTDIR);
    }

    char *filename = get_filename(path);
    if (filename == nullptr) {
        return -(ret = EISDIR);
    }

    switch (st_mode & S_IFMT) {
        case S_IFCHR:
            filetype = EXT2_FT_CHRDEV;
            break;
        case S_IFBLK:
            filetype = EXT2_FT_BLKDEV;
            break;
        case S_IFIFO:
            filetype = EXT2_FT_FIFO;
            break;
#ifndef _WIN32
        case S_IFSOCK:
            filetype = EXT2_FT_SOCK;
            break;
#endif
        default:
            return EXT2_ET_INVALID_ARGUMENT;
    }

    ret = ext2fs_new_inode(fs, parent, 010755, 0, &ino);
    if (ret) return parse_extfs_error(fs, 0, ret);

    ret = ext2fs_link(fs, parent, filename, ino, filetype);
    if (ret == EXT2_ET_DIR_NO_SPACE) {
        ret = ext2fs_expand_dir(fs, parent);
        if (ret) return parse_extfs_error(fs, parent, ret);

        ret = ext2fs_link(fs, parent, filename, ino, filetype);
    }
    if (ret) return parse_extfs_error(fs, parent, ret);

    if (ext2fs_test_inode_bitmap2(fs->inode_map, ino))
        LOG_WARN("Warning: inode already set");
    ext2fs_inode_alloc_stats2(fs, ino, +1, 0);

    struct ext2_inode inode;
    memset(&inode, 0, sizeof(inode));
    inode.i_mode = st_mode;
#ifndef NO_TIMESTAMP
    inode.i_atime = inode.i_ctime = inode.i_mtime =
        fs->now ? fs->now : time(0);
#endif

    if (filetype != S_IFIFO) {
        devmajor = major(st_rdev);
        devminor = minor(st_rdev);

        if ((devmajor < 256) && (devminor < 256)) {
            inode.i_block[0] = devmajor * 256 + devminor;
            inode.i_block[1] = 0;
        } else {
            inode.i_block[0] = 0;
            inode.i_block[1] = (devminor & 0xff) | (devmajor << 8) |
                               ((devminor & ~0xff) << 12);
        }
    }
    inode.i_links_count = 1;

    ret = ext2fs_write_new_inode(fs, ino, &inode);
    if (ret) return parse_extfs_error(fs, ino, ret);

    return 0;
}