Exemple #1
0
/*
 * Find empty directory entry and put new entry on it.
 * This search is done only in directory of specified cluster.
 * @dvp: vnode for directory.
 * @np: pointer to fat node
 */
int
fatfs_add_node(vnode_t dvp, struct fatfs_node *np)
{
	struct fatfsmount *fmp;
	u_long cl, sec, sec_start;
	int err;
	u_long i, next;

	fmp = (struct fatfsmount *)dvp->v_mount->m_data;
	cl = dvp->v_blkno;

	DPRINTF(("fatfs_add_node: cl=%d\n", cl));

	if (cl == CL_ROOT && !(FAT32(fmp))) {
		/* Add entry in root directory */
		sec_start = fmp->root_start;
		for (sec = sec_start; sec < fmp->data_start; sec++) {
			err = fat_add_dirent(fmp, sec, np);
			if (err != ENOENT)
				return err;
		}
	} else {
		/* Search entry in sub directory */
		if(cl == CL_ROOT)	/* CL_ROOT of FAT32 */
			cl = fmp->root_start;
		while (!IS_EOFCL(fmp, cl)) {
			sec = cl_to_sec(fmp, cl);
			for (i = 0; i < fmp->sec_per_cl; i++) {
				err = fat_add_dirent(fmp, sec, np);
				if (err != ENOENT)
					return err;
				sec++;
			}
			err = fat_next_cluster(fmp, cl, &next);
			if (err)
				return err;
			cl = next;
		}
		/* No entry found, add one more free cluster for directory */
		DPRINTF(("fatfs_add_node: expand dir\n"));
		err = fat_expand_dir(fmp, cl, &next);
		if (err)
			return err;

		/* Initialize free cluster. */
		memset(fmp->dir_buf, 0, SEC_SIZE);
		sec = cl_to_sec(fmp, next);
		for (i = 0; i < fmp->sec_per_cl; i++) {
			err = fat_write_dirent(fmp, sec);
			if (err)
				return err;
			sec++;
		}
		/* Try again */
		sec = cl_to_sec(fmp, next);
		err = fat_add_dirent(fmp, sec, np);
		return err;
	}
	return ENOENT;
}
Exemple #2
0
/*
 * Find directory entry for specified name in directory.
 * The fat vnode data is filled if success.
 *
 * @dvp: vnode for directory.
 * @name: file name
 * @np: pointer to fat node
 */
int
fatfs_lookup_node(vnode_t dvp, char *name, struct fatfs_node *np)
{
	struct fatfsmount *fmp;
	char fat_name[12];
	u_long i, cl, sec, sec_start;
	int err;

	if (name == NULL)
		return ENOENT;

	DPRINTF(("fat_lookup_denode: cl=%d name=%s\n", dvp->v_blkno, name));

	fat_convert_name(name, fat_name);
	*(fat_name + 11) = '\0';

	fmp = (struct fatfsmount *)dvp->v_mount->m_data;
	cl = dvp->v_blkno;
	if (cl == CL_ROOT && !(FAT32(fmp))) {
		/* Search entry in root directory */
		sec_start = fmp->root_start;
		for (sec = sec_start; sec < fmp->data_start; sec++) {
			err = fat_lookup_dirent(fmp, sec, fat_name, np);
			if (err != EAGAIN)
				return err;
		}
	} else {
		/* Search entry in sub directory */
		if(cl == CL_ROOT)	/* CL_ROOT of FAT32 */
			cl = fmp->root_start;
		while (!IS_EOFCL(fmp, cl)) {
			sec = cl_to_sec(fmp, cl);
			for (i = 0; i < fmp->sec_per_cl; i++) {
				err = fat_lookup_dirent(fmp, sec, fat_name,
						   np);
				if (err != EAGAIN)
					return err;
				sec++;
			}
			err = fat_next_cluster(fmp, cl, &cl);
			if (err)
				return err;
		}
	}
	return ENOENT;
}
Exemple #3
0
/*
 * Get directory entry for specified index.
 *
 * @dvp: vnode for directory.
 * @index: index of the entry
 * @np: pointer to fat node
 */
int
fatfs_get_node(vnode_t dvp, int index, struct fatfs_node *np)
{
	struct fatfsmount *fmp;
	u_long i, cl, sec, sec_start;
	int cur_index, err;

	fmp = (struct fatfsmount *)dvp->v_mount->m_data;
	cl = dvp->v_blkno;
	cur_index = 0;

	DPRINTF(("fatfs_get_node: index=%d\n", index));

	if (cl == CL_ROOT && !(FAT32(fmp))) {
		/* Get entry from the root directory */
		sec_start = fmp->root_start;
		for (sec = sec_start; sec < fmp->data_start; sec++) {
			err = fat_get_dirent(fmp, sec, index, &cur_index, np);
			if (err != EAGAIN)
				return err;
		}
	} else {
		if(cl == CL_ROOT)	/* CL_ROOT of FAT32 */
			cl = fmp->root_start;
		/* Get entry from the sub directory */
		while (!IS_EOFCL(fmp, cl)) {
			sec = cl_to_sec(fmp, cl);
			for (i = 0; i < fmp->sec_per_cl; i++) {
				err = fat_get_dirent(fmp, sec, index,
						     &cur_index, np);
				if (err != EAGAIN)
					return err;
				sec++;
			}
			err = fat_next_cluster(fmp, cl, &cl);
			if (err)
				return err;
		}
	}
	return ENOENT;
}
Exemple #4
0
static int
fatfs_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
{
    struct fatfsmount *fmp;
    struct fatfs_node *np;
    struct fat_dirent *de;
    int nr_copy, nr_write, buf_pos, i, cl_size, error;
    u_long file_pos, end_pos;
    u_long cl;

    DPRINTF(("fatfs_write: vp=%x size=%d\n", vp, size));

    *result = 0;
    fmp = vp->v_mount->m_data;

    if (vp->v_type == VDIR)
        return EISDIR;
    if (vp->v_type != VREG)
        return EINVAL;

    mutex_lock(&fmp->lock);

    /* Check if file position exceeds the end of file. */
    end_pos = vp->v_size;
    file_pos = (fp->f_flags & O_APPEND) ? end_pos : fp->f_offset;
    if (file_pos + size > end_pos) {
        /* Expand the file size before writing to it */
        end_pos = file_pos + size;
        error = fat_expand_file(fmp, vp->v_blkno, end_pos);
        if (error) {
            error = EIO;
            goto out;
        }

        /* Update directory entry */
        np = vp->v_data;
        de = &np->dirent;
        de->size = end_pos;
        error = fatfs_put_node(fmp, np);
        if (error)
            goto out;
        vp->v_size = end_pos;
    }

    /* Seek to the cluster for the file offset */
    error = fat_seek_cluster(fmp, vp->v_blkno, file_pos, &cl);
    if (error)
        goto out;

    buf_pos = file_pos % fmp->cluster_size;
    cl_size = size / fmp->cluster_size + 1;
    nr_write = 0;
    i = 0;
    do {
        /* First and last cluster must be read before write */
        if (i == 0 || i == cl_size) {
            if (fat_read_cluster(fmp, cl)) {
                error = EIO;
                goto out;
            }
        }
        nr_copy = fmp->cluster_size;
        if (buf_pos > 0)
            nr_copy -= buf_pos;
        if (buf_pos + size < fmp->cluster_size)
            nr_copy = size;
        memcpy(fmp->io_buf + buf_pos, buf, nr_copy);

        if (fat_write_cluster(fmp, cl)) {
            error = EIO;
            goto out;
        }
        file_pos += nr_copy;
        nr_write += nr_copy;
        size -= nr_copy;
        if (size <= 0)
            break;

        error = fat_next_cluster(fmp, cl, &cl);
        if (error)
            goto out;

        buf = (void *)((u_long)buf + nr_copy);
        buf_pos = 0;
        i++;
    } while (!IS_EOFCL(fmp, cl));

    fp->f_offset = file_pos;

    /*
     * XXX: Todo!
     *    de.time = ?
     *    de.date = ?
     *    if (dirent_set(fp, &de))
     *        return EIO;
     */
    *result = nr_write;
    error = 0;
out:
    mutex_unlock(&fmp->lock);
    return error;
}
Exemple #5
0
static int
fatfs_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
{
    struct fatfsmount *fmp;
    int nr_read, nr_copy, buf_pos, error;
    u_long cl, file_pos;

    DPRINTF(("fatfs_read: vp=%x\n", vp));

    *result = 0;
    fmp = vp->v_mount->m_data;

    if (vp->v_type == VDIR)
        return EISDIR;
    if (vp->v_type != VREG)
        return EINVAL;

    /* Check if current file position is already end of file. */
    file_pos = fp->f_offset;
    if (file_pos >= vp->v_size)
        return 0;

    mutex_lock(&fmp->lock);

    /* Get the actual read size. */
    if (vp->v_size - file_pos < size)
        size = vp->v_size - file_pos;

    /* Seek to the cluster for the file offset */
    error = fat_seek_cluster(fmp, vp->v_blkno, file_pos, &cl);
    if (error)
        goto out;

    /* Read and copy data */
    nr_read = 0;
    buf_pos = file_pos % fmp->cluster_size;
    do {
        if (fat_read_cluster(fmp, cl)) {
            error = EIO;
            goto out;
        }

        nr_copy = fmp->cluster_size;
        if (buf_pos > 0)
            nr_copy -= buf_pos;
        if (buf_pos + size < fmp->cluster_size)
            nr_copy = size;
        memcpy(buf, fmp->io_buf + buf_pos, nr_copy);

        file_pos += nr_copy;
        nr_read += nr_copy;
        size -= nr_copy;
        if (size <= 0)
            break;

        error = fat_next_cluster(fmp, cl, &cl);
        if (error)
            goto out;

        buf = (void *)((u_long)buf + nr_copy);
        buf_pos = 0;
    } while (!IS_EOFCL(fmp, cl));

    fp->f_offset = file_pos;
    *result = nr_read;
    error = 0;
out:
    mutex_unlock(&fmp->lock);
    return error;
}