예제 #1
0
파일: main.c 프로젝트: draekko/exfat
static void print_generic_info(const struct exfat_super_block* sb)
{
	printf("Volume serial number      0x%08x\n",
			le32_to_cpu(sb->volume_serial));
	printf("FS version                       %hhu.%hhu\n",
			sb->version.major, sb->version.minor);
	printf("Sector size               %10u\n",
			SECTOR_SIZE(*sb));
	printf("Cluster size              %10u\n",
			CLUSTER_SIZE(*sb));
}
예제 #2
0
파일: cluster.c 프로젝트: svn2github/exfat
int exfat_find_used_sectors(const struct exfat* ef, off_t* a, off_t* b)
{
	cluster_t ca, cb;

	if (*a == 0 && *b == 0)
		ca = cb = EXFAT_FIRST_DATA_CLUSTER - 1;
	else
	{
		ca = s2c(ef, *a);
		cb = s2c(ef, *b);
	}
	if (find_used_clusters(ef, &ca, &cb) != 0)
		return 1;
	if (*a != 0 || *b != 0)
		*a = c2s(ef, ca);
	*b = c2s(ef, cb) + (CLUSTER_SIZE(*ef->sb) - 1) / SECTOR_SIZE(*ef->sb);
	return 0;
}
예제 #3
0
파일: fs.c 프로젝트: Joyless/syslinux
void pm_open_file(com32sys_t *regs)
{
    int rv;
    struct file *file;
    const char *name = MK_PTR(regs->es, regs->esi.w[0]);
    char mangled_name[FILENAME_MAX];

    dprintf("pm_open_file %s\n", name);

    mangle_name(mangled_name, name);
    rv = searchdir(mangled_name);
    if (rv < 0) {
	regs->eflags.l |= EFLAGS_CF;
    } else {
	file = handle_to_file(rv);
	regs->eflags.l &= ~EFLAGS_CF;
	regs->eax.l = file->inode->size;
	regs->ecx.w[0] = SECTOR_SIZE(file->fs);
	regs->esi.w[0] = rv;
    }
}
예제 #4
0
void pm_load_high(com32sys_t *regs)
{
    struct fs_info *fs;
    uint32_t bytes;
    uint32_t zero_mask;
    bool have_more;
    uint32_t bytes_read;
    char *buf, *limit;
    struct file *file;
    uint32_t sector_mask;
    size_t pad;
    uint32_t retflags = 0;

    bytes     = regs->eax.l;
    zero_mask = regs->edx.w[0];
    buf       = (char *)regs->edi.l;
    limit     = (char *)(regs->ebp.l & ~zero_mask);
    file      = handle_to_file(regs->esi.w[0]);
    fs        = file->fs;

    sector_mask = SECTOR_SIZE(fs) - 1;

    while (bytes) {
	uint32_t sectors;
	uint32_t chunk;

	if (buf + SECTOR_SIZE(fs) > limit) {
	    /* Can't fit even one more sector in... */
	    retflags = EFLAGS_OF;
	    break;
	}

	chunk = bytes;

	if (regs->ebx.w[0]) {
	    call16((void (*)(void))(size_t)regs->ebx.w[0], &zero_regs, NULL);
	    chunk = min(chunk, MAX_CHUNK);
	}

	if (chunk > (((char *)limit - buf) & ~sector_mask))
	    chunk = ((char *)limit - buf) & ~sector_mask;

	sectors = (chunk + sector_mask) >> SECTOR_SHIFT(fs);
	bytes_read = fs->fs_ops->getfssec(file, buf, sectors, &have_more);

	if (bytes_read > chunk)
	    bytes_read = chunk;

	buf += bytes_read;
	bytes -= bytes_read;

	if (!have_more) {
	    /*
	     * If we reach EOF, the filesystem driver will have already closed
	     * the underlying file... this really should be cleaner.
	     */
	    _close_file(file);
	    regs->esi.w[0] = 0;
	    retflags = EFLAGS_CF;
	    break;
	}
    }

    pad = (size_t)buf & zero_mask;
    if (pad)
	memset(buf, 0, pad);

    regs->ebx.l = (size_t)buf;
    regs->edi.l = (size_t)buf + pad;
    set_flags(regs, retflags);
}
예제 #5
0
파일: mount.c 프로젝트: salass00/exfat
int exfat_mount(struct exfat* ef, const char* spec, const char* options)
{
	int rc;
	enum exfat_mode mode;

	exfat_tzset();
	memset(ef, 0, sizeof(struct exfat));

	parse_options(ef, options);

	if (match_option(options, "ro"))
		mode = EXFAT_MODE_RO;
	else if (match_option(options, "ro_fallback"))
		mode = EXFAT_MODE_ANY;
	else
		mode = EXFAT_MODE_RW;
	ef->dev = exfat_open(spec, mode);
	if (ef->dev == NULL)
		return -EIO;
	if (exfat_get_mode(ef->dev) == EXFAT_MODE_RO)
	{
		if (mode == EXFAT_MODE_ANY)
			ef->ro = -1;
		else
			ef->ro = 1;
	}

	ef->sb = malloc(sizeof(struct exfat_super_block));
	if (ef->sb == NULL)
	{
		exfat_close(ef->dev);
		exfat_error("failed to allocate memory for the super block");
		return -ENOMEM;
	}
	memset(ef->sb, 0, sizeof(struct exfat_super_block));

	if (exfat_pread(ef->dev, ef->sb, sizeof(struct exfat_super_block), 0) < 0)
	{
		exfat_close(ef->dev);
		free(ef->sb);
		exfat_error("failed to read boot sector");
		return -EIO;
	}
	if (memcmp(ef->sb->oem_name, "EXFAT   ", 8) != 0)
	{
		exfat_close(ef->dev);
		free(ef->sb);
		exfat_error("exFAT file system is not found");
		return -EIO;
	}
	/* sector cannot be smaller than 512 bytes */
	if (ef->sb->sector_bits < 9)
	{
		exfat_close(ef->dev);
		exfat_error("too small sector size: 2^%hhd", ef->sb->sector_bits);
		free(ef->sb);
		return -EIO;
	}
	/* officially exFAT supports cluster size up to 32 MB */
	if ((int) ef->sb->sector_bits + (int) ef->sb->spc_bits > 25)
	{
		exfat_close(ef->dev);
		exfat_error("too big cluster size: 2^(%hhd+%hhd)",
				ef->sb->sector_bits, ef->sb->spc_bits);
		free(ef->sb);
		return -EIO;
	}
	ef->zero_cluster = malloc(CLUSTER_SIZE(*ef->sb));
	if (ef->zero_cluster == NULL)
	{
		exfat_close(ef->dev);
		free(ef->sb);
		exfat_error("failed to allocate zero sector");
		return -ENOMEM;
	}
	/* use zero_cluster as a temporary buffer for VBR checksum verification */
	if (!verify_vbr_checksum(ef->dev, ef->zero_cluster, SECTOR_SIZE(*ef->sb)))
	{
		free(ef->zero_cluster);
		exfat_close(ef->dev);
		free(ef->sb);
		return -EIO;
	}
	memset(ef->zero_cluster, 0, CLUSTER_SIZE(*ef->sb));
	if (ef->sb->version.major != 1 || ef->sb->version.minor != 0)
	{
		free(ef->zero_cluster);
		exfat_close(ef->dev);
		exfat_error("unsupported exFAT version: %hhu.%hhu",
				ef->sb->version.major, ef->sb->version.minor);
		free(ef->sb);
		return -EIO;
	}
	if (ef->sb->fat_count != 1)
	{
		free(ef->zero_cluster);
		exfat_close(ef->dev);
		exfat_error("unsupported FAT count: %hhu", ef->sb->fat_count);
		free(ef->sb);
		return -EIO;
	}
	if (le64_to_cpu(ef->sb->sector_count) * SECTOR_SIZE(*ef->sb) >
			exfat_get_size(ef->dev))
	{
		/* this can cause I/O errors later but we don't fail mounting to let
		   user rescue data */
		exfat_warn("file system is larger than underlying device: "
				"%"PRIu64" > %"PRIu64,
				le64_to_cpu(ef->sb->sector_count) * SECTOR_SIZE(*ef->sb),
				exfat_get_size(ef->dev));
	}

	ef->root = malloc(sizeof(struct exfat_node));
	if (ef->root == NULL)
	{
		free(ef->zero_cluster);
		exfat_close(ef->dev);
		free(ef->sb);
		exfat_error("failed to allocate root node");
		return -ENOMEM;
	}
	memset(ef->root, 0, sizeof(struct exfat_node));
	ef->root->flags = EXFAT_ATTRIB_DIR;
	ef->root->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
	ef->root->fptr_cluster = ef->root->start_cluster;
	ef->root->name[0] = cpu_to_le16('\0');
	ef->root->size = rootdir_size(ef);
	if (ef->root->size == 0)
	{
		free(ef->root);
		free(ef->zero_cluster);
		exfat_close(ef->dev);
		free(ef->sb);
		return -EIO;
	}
	/* exFAT does not have time attributes for the root directory */
	ef->root->mtime = 0;
	ef->root->atime = 0;
	/* always keep at least 1 reference to the root node */
	exfat_get_node(ef->root);

	rc = exfat_cache_directory(ef, ef->root);
	if (rc != 0)
		goto error;
	if (ef->upcase == NULL)
	{
		exfat_error("upcase table is not found");
		goto error;
	}
	if (ef->cmap.chunk == NULL)
	{
		exfat_error("clusters bitmap is not found");
		goto error;
	}

	if (prepare_super_block(ef) != 0)
		goto error;

	return 0;

error:
	exfat_put_node(ef, ef->root);
	exfat_reset_cache(ef);
	free(ef->root);
	free(ef->zero_cluster);
	exfat_close(ef->dev);
	free(ef->sb);
	return -EIO;
}
예제 #6
0
uint32_t generic_getfssec(struct file *file, char *buf,
			  int sectors, bool *have_more)
{
    struct inode *inode = file->inode;
    struct fs_info *fs = file->fs;
    struct disk *disk = fs->fs_dev->disk;
    uint32_t bytes_read = 0;
    uint32_t bytes_left = inode->size - file->offset;
    uint32_t sectors_left =
	(bytes_left + SECTOR_SIZE(fs) - 1) >> SECTOR_SHIFT(fs);
    uint32_t lsector;

    if (sectors > sectors_left)
	sectors = sectors_left;

    if (!sectors)
	return 0;

    lsector = file->offset >> SECTOR_SHIFT(fs);
    dprintf("Offset: %u  lsector: %u\n", file->offset, lsector);

    if (lsector < inode->this_extent.lstart ||
	lsector >= inode->this_extent.lstart + inode->this_extent.len) {
	/* inode->this_extent unusable, maybe next_extent is... */
	inode->this_extent = inode->next_extent;
    }

    if (lsector < inode->this_extent.lstart ||
	lsector >= inode->this_extent.lstart + inode->this_extent.len) {
	/* Still nothing useful... */
	inode->this_extent.lstart = lsector;
	inode->this_extent.len = 0;
    } else {
	/* We have some usable information */
	uint32_t delta = lsector - inode->this_extent.lstart;
	inode->this_extent.lstart = lsector;
	inode->this_extent.len -= delta;
	inode->this_extent.pstart
	    = next_psector(inode->this_extent.pstart, delta);
    }

    dprintf("this_extent: lstart %u pstart %llu len %u\n",
	    inode->this_extent.lstart,
	    inode->this_extent.pstart,
	    inode->this_extent.len);

    while (sectors) {
	uint32_t chunk;
	size_t len;

	while (sectors > inode->this_extent.len) {
	    if (!inode->next_extent.len ||
		inode->next_extent.lstart !=
		inode->this_extent.lstart + inode->this_extent.len)
		get_next_extent(inode);

	    if (!inode->this_extent.len) {
		/* Doesn't matter if it's contiguous... */
		inode->this_extent = inode->next_extent;
		if (!inode->next_extent.len) {
		    sectors = 0; /* Failed to get anything... we're dead */
		    break;
		}
	    } else if (inode->next_extent.len &&
		inode->next_extent.pstart == next_pstart(&inode->this_extent)) {
		/* Coalesce extents and loop */
		inode->this_extent.len += inode->next_extent.len;
	    } else {
		/* Discontiguous extents */
		break;
	    }
	}

	dprintf("this_extent: lstart %u pstart %llu len %u\n",
		inode->this_extent.lstart,
		inode->this_extent.pstart,
		inode->this_extent.len);

	chunk = min(sectors, inode->this_extent.len);
	len = chunk << SECTOR_SHIFT(fs);

	dprintf("   I/O: inode %p @ %u start %llu len %u\n",
		inode, inode->this_extent.lstart,
		inode->this_extent.pstart, chunk);

	if (inode->this_extent.pstart == EXTENT_ZERO) {
	    memset(buf, 0, len);
	} else {
	    disk->rdwr_sectors(disk, buf, inode->this_extent.pstart, chunk, 0);
	    inode->this_extent.pstart += chunk;
	}

	buf += len;
	sectors -= chunk;
	bytes_read += len;
	inode->this_extent.lstart += chunk;
	inode->this_extent.len -= chunk;
    }

    bytes_read = min(bytes_read, bytes_left);
    file->offset += bytes_read;

    if (have_more)
	*have_more = bytes_read < bytes_left;

    return bytes_read;
}