Ejemplo n.º 1
0
/* Handle a sparable partition map */
int
udf_get_spartmap(struct umount *ump, struct part_map_spare *pms)
{
	struct buf *bp;
	int i, error;

	ump->um_stbl = malloc(letoh32(pms->st_size), M_UDFMOUNT, M_NOWAIT);
	if (ump->um_stbl == NULL)
		return (ENOMEM);

	bzero(ump->um_stbl, letoh32(pms->st_size));

	/* Calculate the number of sectors per packet */
	ump->um_psecs = letoh16(pms->packet_len) / ump->um_bsize;

	error = udf_readlblks(ump, letoh32(pms->st_loc[0]),
	    letoh32(pms->st_size), &bp);

	if (error) {
		if (bp != NULL)
			brelse(bp);
		free(ump->um_stbl, M_UDFMOUNT);
		return (error); /* Failed to read sparing table */
	}

	bcopy(bp->b_data, ump->um_stbl, letoh32(pms->st_size));
	brelse(bp);
	bp = NULL;

	if (udf_checktag(&ump->um_stbl->tag, 0)) {
		free(ump->um_stbl, M_UDFMOUNT);
		return (EINVAL); /* Invalid sparing table found */
	}

	/*
	 * See how many valid entries there are here. The list is
	 * supposed to be sorted, 0xfffffff0 and higher are not valid.
	 */
	for (i = 0; i < letoh16(ump->um_stbl->rt_l); i++) {
		ump->um_stbl_len = i;
		if (letoh32(ump->um_stbl->entries[i].org) >= 0xfffffff0)
			break;
	}

	return (0);
}
Ejemplo n.º 2
0
udf_dirent_t *
udf_opendir(const udf_dirent_t *p_udf_dirent)
{
  if (p_udf_dirent->b_dir && !p_udf_dirent->b_parent && p_udf_dirent->fid) {
    udf_t *p_udf = p_udf_dirent->p_udf;
    udf_file_entry_t udf_fe;

    driver_return_code_t i_ret =
      udf_read_sectors(p_udf, &udf_fe, p_udf->i_part_start
		       + p_udf_dirent->fid->icb.loc.lba, 1);

    if (DRIVER_OP_SUCCESS == i_ret
	&& !udf_checktag(&udf_fe.tag, TAGID_FILE_ENTRY)) {

      if (ICBTAG_FILE_TYPE_DIRECTORY == udf_fe.icb_tag.file_type) {
	udf_dirent_t *p_udf_dirent_new =
	  udf_new_dirent(&udf_fe, p_udf, p_udf_dirent->psz_name, true, true);
	return p_udf_dirent_new;
      }
    }
  }
  return NULL;
}
Ejemplo n.º 3
0
/*
 * Do a lazy probe on the underlying media to check if it's a UDF volume, in
 * which case we fake a disk label for it.
 */
int
udf_disklabelspoof(dev_t dev, void (*strat)(struct buf *),
    struct disklabel *lp)
{
	char vid[32];
	int i, bsize = 2048, error = EINVAL;
	uint32_t sector = 256, mvds_start, mvds_end;
	struct buf *bp;
	struct anchor_vdp avdp;
	struct pri_vol_desc *pvd;

	/*
	 * Get a buffer to work with.
	 */
	bp = geteblk(bsize);
	bp->b_dev = dev;

	/*
	 * Look for an Anchor Volume Descriptor at sector 256.
	 */
	bp->b_blkno = sector * btodb(bsize);
	bp->b_bcount = bsize;
	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
	SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
	bp->b_resid = bp->b_blkno / lp->d_secpercyl;

	(*strat)(bp);
	if (biowait(bp))
		goto out;

	if (udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR))
		goto out;

	bcopy(bp->b_data, &avdp, sizeof(avdp));
	mvds_start = letoh32(avdp.main_vds_ex.loc);
	mvds_end = mvds_start + (letoh32(avdp.main_vds_ex.len) - 1) / bsize;

	/*
	 * Then try to find a reference to a Primary Volume Descriptor.
	 */
	for (sector = mvds_start; sector < mvds_end; sector++) {
		bp->b_blkno = sector * btodb(bsize);
		bp->b_bcount = bsize;
		CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
		SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
		bp->b_resid = bp->b_blkno / lp->d_secpercyl;

		(*strat)(bp);
		if (biowait(bp))
			goto out;

		pvd = (struct pri_vol_desc *)bp->b_data;
		if (!udf_checktag(&pvd->tag, TAGID_PRI_VOL))
			break;
	}

	/*
	 * If we couldn't find a reference, bail out.
	 */
	if (sector == mvds_end)
		goto out;

	/*
	 * Okay, it's a UDF volume. Spoof a disk label for it.
	 */
	if (udf_transname(pvd->vol_id, vid, sizeof(pvd->vol_id) - 1, NULL))
		strlcpy(lp->d_typename, vid, sizeof(lp->d_typename));

	for (i = 0; i < MAXPARTITIONS; i++) {
		DL_SETPSIZE(&lp->d_partitions[i], 0);
		DL_SETPOFFSET(&lp->d_partitions[i], 0);
	}

	/*
	 * Fake two partitions, 'a' and 'c'.
	 */
	DL_SETPSIZE(&lp->d_partitions[0], DL_GETDSIZE(lp));
	lp->d_partitions[0].p_fstype = FS_UDF;
	DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
	lp->d_partitions[RAW_PART].p_fstype = FS_UDF;
	lp->d_npartitions = MAXPARTITIONS;
	lp->d_version = 1;

	lp->d_bbsize = 8192;	/* Fake. */
	lp->d_sbsize = 64*1024;	/* Fake. */
	lp->d_magic = DISKMAGIC;
	lp->d_magic2 = DISKMAGIC;
	lp->d_checksum = dkcksum(lp);

	error = 0;
out:
	bp->b_flags |= B_INVAL;
	brelse(bp);

	return (error);
}
Ejemplo n.º 4
0
int
udf_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
{
	struct buf *bp;
	struct vnode *devvp;
	struct umount *ump;
	struct proc *p;
	struct vnode *vp, *nvp;
	struct unode *up;
	struct extfile_entry *xfe;
	struct file_entry *fe;
	int error, sector, size;

	p = curproc;
	bp = NULL;
	*vpp = NULL;
	ump = VFSTOUDFFS(mp);

	/* See if we already have this in the cache */
	if ((error = udf_hashlookup(ump, ino, LK_EXCLUSIVE, vpp)) != 0)
		return (error);
	if (*vpp != NULL)
		return (0);

	/*
	 * Allocate memory and check the tag id's before grabbing a new
	 * vnode, since it's hard to roll back if there is a problem.
	 */
	up = pool_get(&unode_pool, PR_WAITOK | PR_ZERO);

	/*
	 * Copy in the file entry.  Per the spec, the size can only be 1 block.
	 */
	sector = ino;
	devvp = ump->um_devvp;
	udf_vat_map(ump, &sector);
	if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
		printf("Cannot read sector %d\n", sector);
		pool_put(&unode_pool, up);
		if (bp != NULL)
			brelse(bp);
		return (error);
	}

	xfe = (struct extfile_entry *)bp->b_data;
	fe = (struct file_entry *)bp->b_data;
	error = udf_checktag(&xfe->tag, TAGID_EXTFENTRY);
	if (error == 0) {
		size = letoh32(xfe->l_ea) + letoh32(xfe->l_ad);
	} else {
		error = udf_checktag(&fe->tag, TAGID_FENTRY);
		if (error) {
			printf("Invalid file entry!\n");
			pool_put(&unode_pool, up);
			if (bp != NULL)
				brelse(bp);
			return (ENOMEM);
		} else
			size = letoh32(fe->l_ea) + letoh32(fe->l_ad);
	}

	/* Allocate max size of FE/XFE. */
	up->u_fentry = malloc(size + UDF_EXTFENTRY_SIZE, M_UDFFENTRY, M_NOWAIT | M_ZERO);
	if (up->u_fentry == NULL) {
		pool_put(&unode_pool, up);
		if (bp != NULL)
			brelse(bp);
		return (ENOMEM); /* Cannot allocate file entry block */
	}

	if (udf_checktag(&xfe->tag, TAGID_EXTFENTRY) == 0)
		bcopy(bp->b_data, up->u_fentry, size + UDF_EXTFENTRY_SIZE);
	else
		bcopy(bp->b_data, up->u_fentry, size + UDF_FENTRY_SIZE);
	
	brelse(bp);
	bp = NULL;

	if ((error = udf_allocv(mp, &vp, p))) {
		free(up->u_fentry, M_UDFFENTRY);
		pool_put(&unode_pool, up);
		return (error); /* Error from udf_allocv() */
	}

	up->u_vnode = vp;
	up->u_ino = ino;
	up->u_devvp = ump->um_devvp;
	up->u_dev = ump->um_dev;
	up->u_ump = ump;
	vp->v_data = up;
	vref(ump->um_devvp);

	lockinit(&up->u_lock, PINOD, "unode", 0, 0);

	/*
	 * udf_hashins() will lock the vnode for us.
	 */
	udf_hashins(up);

	switch (up->u_fentry->icbtag.file_type) {
	default:
		printf("Unrecognized file type (%d)\n", vp->v_type);
		vp->v_type = VREG;
		break;
	case UDF_ICB_FILETYPE_DIRECTORY:
		vp->v_type = VDIR;
		break;
	case UDF_ICB_FILETYPE_BLOCKDEVICE:
		vp->v_type = VBLK;
		break;
	case UDF_ICB_FILETYPE_CHARDEVICE:
		vp->v_type = VCHR;
		break;
	case UDF_ICB_FILETYPE_FIFO:
		vp->v_type = VFIFO;
		break;
	case UDF_ICB_FILETYPE_SOCKET:
		vp->v_type = VSOCK;
		break;
	case UDF_ICB_FILETYPE_SYMLINK:
		vp->v_type = VLNK;
		break;
	case UDF_ICB_FILETYPE_RANDOMACCESS:
	case UDF_ICB_FILETYPE_REALTIME:
	case UDF_ICB_FILETYPE_UNKNOWN:
		vp->v_type = VREG;
		break;
	}

	/* check if this is a vnode alias */
	if ((nvp = checkalias(vp, up->u_dev, ump->um_mountp)) != NULL) {
		printf("found a vnode alias\n");
		/*
		 * Discard unneeded vnode, but save its udf_node.
		 * Note that the lock is carried over in the udf_node
		 */
		nvp->v_data = vp->v_data;
		vp->v_data = NULL;
		vp->v_op = spec_vnodeop_p;
		vrele(vp);
		vgone(vp);
		/*
		 * Reinitialize aliased inode.
		 */
		vp = nvp;
		ump->um_devvp = vp;
	}

	*vpp = vp;

	return (0);
}
Ejemplo n.º 5
0
int
udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p)
{
	struct buf *bp = NULL;
	struct anchor_vdp avdp;
	struct umount *ump = NULL;
	struct part_desc *pd;
	struct logvol_desc *lvd;
	struct fileset_desc *fsd;
	struct extfile_entry *xfentry;
	struct file_entry *fentry;
	uint32_t sector, size, mvds_start, mvds_end;
	uint32_t fsd_offset = 0;
	uint16_t part_num = 0, fsd_part = 0;
	int error = EINVAL;
	int logvol_found = 0, part_found = 0, fsd_found = 0;
	int bsize;

	/*
	 * Disallow multiple mounts of the same device.
	 * Disallow mounting of a device that is currently in use
	 * (except for root, which might share swap device for miniroot).
	 * Flush out any old buffers remaining from a previous use.
	 */
	if ((error = vfs_mountedon(devvp)))
		return (error);
	if (vcount(devvp) > 1 && devvp != rootvp)
		return (EBUSY);
	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
	VOP_UNLOCK(devvp, 0, p);
	if (error)
		return (error);

	error = VOP_OPEN(devvp, FREAD, FSCRED, p);
	if (error)
		return (error);

	ump = malloc(sizeof(*ump), M_UDFMOUNT, M_WAITOK | M_ZERO);

	mp->mnt_data = (qaddr_t) ump;
	mp->mnt_stat.f_fsid.val[0] = devvp->v_rdev;
	mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_UDF);
	mp->mnt_flag |= MNT_LOCAL;

	ump->um_mountp = mp;
	ump->um_dev = devvp->v_rdev;
	ump->um_devvp = devvp;

	bsize = 2048;	/* Should probe the media for its size. */

	/* 
	 * Get the Anchor Volume Descriptor Pointer from sector 256.
	 * Should also check sector n - 256, n, and 512.
	 */
	sector = 256;
	if ((error = bread(devvp, sector * btodb(bsize), bsize, NOCRED,
			   &bp)) != 0)
		goto bail;
	if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR)))
		goto bail;

	bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp));
	brelse(bp);
	bp = NULL;

	/*
	 * Extract the Partition Descriptor and Logical Volume Descriptor
	 * from the Volume Descriptor Sequence.
	 * Should we care about the partition type right now?
	 * What about multiple partitions?
	 */
	mvds_start = letoh32(avdp.main_vds_ex.loc);
	mvds_end = mvds_start + (letoh32(avdp.main_vds_ex.len) - 1) / bsize;
	for (sector = mvds_start; sector < mvds_end; sector++) {
		if ((error = bread(devvp, sector * btodb(bsize), bsize, 
				   NOCRED, &bp)) != 0) {
			printf("Can't read sector %d of VDS\n", sector);
			goto bail;
		}
		lvd = (struct logvol_desc *)bp->b_data;
		if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) {
			ump->um_bsize = letoh32(lvd->lb_size);
			ump->um_bmask = ump->um_bsize - 1;
			ump->um_bshift = ffs(ump->um_bsize) - 1;
			fsd_part = letoh16(lvd->_lvd_use.fsd_loc.loc.part_num);
			fsd_offset = letoh32(lvd->_lvd_use.fsd_loc.loc.lb_num);
			if (udf_find_partmaps(ump, lvd))
				break;
			logvol_found = 1;
		}
		pd = (struct part_desc *)bp->b_data;
		if (!udf_checktag(&pd->tag, TAGID_PARTITION)) {
			part_found = 1;
			part_num = letoh16(pd->part_num);
			ump->um_len = ump->um_reallen = letoh32(pd->part_len);
			ump->um_start = ump->um_realstart = letoh32(pd->start_loc);
		}

		brelse(bp); 
		bp = NULL;
		if ((part_found) && (logvol_found))
			break;
	}

	if (!part_found || !logvol_found) {
		error = EINVAL;
		goto bail;
	}

	if (ISSET(ump->um_flags, UDF_MNT_USES_META)) {
		/* Read Metadata File 'File Entry' to find Metadata file. */
		struct long_ad *la;
		sector = ump->um_start + ump->um_meta_start; /* Set in udf_get_mpartmap() */
		if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
			printf("Cannot read sector %d for Metadata File Entry\n", sector);
			error = EINVAL;
			goto bail;
		}
		xfentry = (struct extfile_entry *)bp->b_data;
		fentry = (struct file_entry *)bp->b_data;
		if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0)
			la = (struct long_ad *)&xfentry->data[letoh32(xfentry->l_ea)];
		else if (udf_checktag(&fentry->tag, TAGID_FENTRY) == 0)
			la = (struct long_ad *)&fentry->data[letoh32(fentry->l_ea)];
		else {
			printf("Invalid Metadata File FE @ sector %d! (tag.id %d)\n",
			    sector, fentry->tag.id);
			error = EINVAL;
			goto bail;
		}
		ump->um_meta_start = letoh32(la->loc.lb_num);
		ump->um_meta_len = letoh32(la->len);
		if (bp != NULL) {
			brelse(bp);
			bp = NULL;
		}
	} else if (fsd_part != part_num) {
		printf("FSD does not lie within the partition!\n");
		error = EINVAL;
		goto bail;
	}

	mtx_init(&ump->um_hashmtx, IPL_NONE);
	ump->um_hashtbl = hashinit(UDF_HASHTBLSIZE, M_UDFMOUNT, M_WAITOK,
	    &ump->um_hashsz);

	/* Get the VAT, if needed */
	if (ump->um_flags & UDF_MNT_FIND_VAT) {
		error = udf_vat_get(ump, lb);
		if (error)
			goto bail;
	}

	/*
	 * Grab the Fileset Descriptor
	 * Thanks to Chuck McCrobie <*****@*****.**> for pointing
	 * me in the right direction here.
	 */

	if (ISSET(ump->um_flags, UDF_MNT_USES_META))
		sector = ump->um_meta_start; 
	else
		sector = fsd_offset;
	udf_vat_map(ump, &sector);
	if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
		printf("Cannot read sector %d of FSD\n", sector);
		goto bail;
	}
	fsd = (struct fileset_desc *)bp->b_data;
	if (!udf_checktag(&fsd->tag, TAGID_FSD)) {
		fsd_found = 1;
		bcopy(&fsd->rootdir_icb, &ump->um_root_icb,
		    sizeof(struct long_ad));
		if (ISSET(ump->um_flags, UDF_MNT_USES_META)) {
			ump->um_root_icb.loc.lb_num += ump->um_meta_start; 
			ump->um_root_icb.loc.part_num = part_num;
		}
	}

	brelse(bp);
	bp = NULL;

	if (!fsd_found) {
		printf("Couldn't find the fsd\n");
		error = EINVAL;
		goto bail;
	}

	/*
	 * Find the file entry for the root directory.
	 */
	sector = letoh32(ump->um_root_icb.loc.lb_num);
	size = letoh32(ump->um_root_icb.len);
	udf_vat_map(ump, &sector);
	if ((error = udf_readlblks(ump, sector, size, &bp)) != 0) {
		printf("Cannot read sector %d\n", sector);
		goto bail;
	}

	xfentry = (struct extfile_entry *)bp->b_data;
	fentry = (struct file_entry *)bp->b_data;
	error = udf_checktag(&xfentry->tag, TAGID_EXTFENTRY);
	if (error) {
	    	error = udf_checktag(&fentry->tag, TAGID_FENTRY);
		if (error) {
			printf("Invalid root file entry!\n");
			goto bail;
		}
	}

	brelse(bp);
	bp = NULL;

	devvp->v_specmountpoint = mp;

	return (0);

bail:
	if (ump->um_hashtbl != NULL)
		free(ump->um_hashtbl, M_UDFMOUNT);

	if (ump != NULL) {
		free(ump, M_UDFMOUNT);
		mp->mnt_data = NULL;
		mp->mnt_flag &= ~MNT_LOCAL;
	}
	if (bp != NULL)
		brelse(bp);

	vn_lock(devvp, LK_EXCLUSIVE|LK_RETRY, p);
	VOP_CLOSE(devvp, FREAD, FSCRED, p);
	VOP_UNLOCK(devvp, 0, p);

	return (error);
}
Ejemplo n.º 6
0
static int
udf_find_partmaps(struct udf_mnt *udfmp, struct logvol_desc *lvd)
{
	struct part_map_spare *pms;
	struct regid *pmap_id;
	struct buf *bp;
	unsigned char regid_id[UDF_REGID_ID_SIZE + 1];
	int i, k, ptype, psize, error;
	uint8_t *pmap = (uint8_t *) &lvd->maps[0];

	for (i = 0; i < le32toh(lvd->n_pm); i++) {
		ptype = pmap[0];
		psize = pmap[1];
		if (((ptype != 1) && (ptype != 2)) ||
		    ((psize != UDF_PMAP_TYPE1_SIZE) &&
		     (psize != UDF_PMAP_TYPE2_SIZE))) {
			printf("Invalid partition map found\n");
			return (1);
		}

		if (ptype == 1) {
			/* Type 1 map.  We don't care */
			pmap += UDF_PMAP_TYPE1_SIZE;
			continue;
		}

		/* Type 2 map.  Gotta find out the details */
		pmap_id = (struct regid *)&pmap[4];
		bzero(&regid_id[0], UDF_REGID_ID_SIZE);
		bcopy(&pmap_id->id[0], &regid_id[0], UDF_REGID_ID_SIZE);

		if (bcmp(&regid_id[0], "*UDF Sparable Partition",
		    UDF_REGID_ID_SIZE)) {
			printf("Unsupported partition map: %s\n", &regid_id[0]);
			return (1);
		}

		pms = (struct part_map_spare *)pmap;
		pmap += UDF_PMAP_TYPE2_SIZE;
		udfmp->s_table = malloc(le32toh(pms->st_size),
		    M_UDFMOUNT, M_NOWAIT | M_ZERO);
		if (udfmp->s_table == NULL)
			return (ENOMEM);

		/* Calculate the number of sectors per packet. */
		/* XXX Logical or physical? */
		udfmp->p_sectors = le16toh(pms->packet_len) / udfmp->bsize;

		/*
		 * XXX If reading the first Sparing Table fails, should look
		 * for another table.
		 */
		if ((error = udf_readdevblks(udfmp, le32toh(pms->st_loc[0]),
					   le32toh(pms->st_size), &bp)) != 0) {
			if (bp != NULL)
				brelse(bp);
			printf("Failed to read Sparing Table at sector %d\n",
			    le32toh(pms->st_loc[0]));
			free(udfmp->s_table, M_UDFMOUNT);
			return (error);
		}
		bcopy(bp->b_data, udfmp->s_table, le32toh(pms->st_size));
		brelse(bp);

		if (udf_checktag(&udfmp->s_table->tag, 0)) {
			printf("Invalid sparing table found\n");
			free(udfmp->s_table, M_UDFMOUNT);
			return (EINVAL);
		}

		/* See how many valid entries there are here.  The list is
		 * supposed to be sorted. 0xfffffff0 and higher are not valid
		 */
		for (k = 0; k < le16toh(udfmp->s_table->rt_l); k++) {
			udfmp->s_table_entries = k;
			if (le32toh(udfmp->s_table->entries[k].org) >=
			    0xfffffff0)
				break;
		}
	}

	return (0);
}
Ejemplo n.º 7
0
int
udf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
{
	struct buf *bp;
	struct vnode *devvp;
	struct udf_mnt *udfmp;
	struct thread *td;
	struct vnode *vp;
	struct udf_node *unode;
	struct file_entry *fe;
	int error, sector, size;

	error = vfs_hash_get(mp, ino, flags, curthread, vpp, NULL, NULL);
	if (error || *vpp != NULL)
		return (error);

	/*
	 * We must promote to an exclusive lock for vnode creation.  This
	 * can happen if lookup is passed LOCKSHARED.
 	 */
	if ((flags & LK_TYPE_MASK) == LK_SHARED) {
		flags &= ~LK_TYPE_MASK;
		flags |= LK_EXCLUSIVE;
	}

	/*
	 * We do not lock vnode creation as it is believed to be too
	 * expensive for such rare case as simultaneous creation of vnode
	 * for same ino by different processes. We just allow them to race
	 * and check later to decide who wins. Let the race begin!
	 */

	td = curthread;
	udfmp = VFSTOUDFFS(mp);

	unode = uma_zalloc(udf_zone_node, M_WAITOK | M_ZERO);

	if ((error = udf_allocv(mp, &vp, td))) {
		printf("Error from udf_allocv\n");
		uma_zfree(udf_zone_node, unode);
		return (error);
	}

	unode->i_vnode = vp;
	unode->hash_id = ino;
	unode->udfmp = udfmp;
	vp->v_data = unode;

	lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
	error = insmntque(vp, mp);
	if (error != 0) {
		uma_zfree(udf_zone_node, unode);
		return (error);
	}
	error = vfs_hash_insert(vp, ino, flags, td, vpp, NULL, NULL);
	if (error || *vpp != NULL)
		return (error);

	/*
	 * Copy in the file entry.  Per the spec, the size can only be 1 block.
	 */
	sector = ino + udfmp->part_start;
	devvp = udfmp->im_devvp;
	if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) {
		printf("Cannot read sector %d\n", sector);
		vgone(vp);
		vput(vp);
		brelse(bp);
		*vpp = NULL;
		return (error);
	}

	fe = (struct file_entry *)bp->b_data;
	if (udf_checktag(&fe->tag, TAGID_FENTRY)) {
		printf("Invalid file entry!\n");
		vgone(vp);
		vput(vp);
		brelse(bp);
		*vpp = NULL;
		return (ENOMEM);
	}
	size = UDF_FENTRY_SIZE + le32toh(fe->l_ea) + le32toh(fe->l_ad);
	unode->fentry = malloc(size, M_UDFFENTRY, M_NOWAIT | M_ZERO);
	if (unode->fentry == NULL) {
		printf("Cannot allocate file entry block\n");
		vgone(vp);
		vput(vp);
		brelse(bp);
		*vpp = NULL;
		return (ENOMEM);
	}

	bcopy(bp->b_data, unode->fentry, size);
	
	brelse(bp);
	bp = NULL;

	switch (unode->fentry->icbtag.file_type) {
	default:
		vp->v_type = VBAD;
		break;
	case 4:
		vp->v_type = VDIR;
		break;
	case 5:
		vp->v_type = VREG;
		break;
	case 6:
		vp->v_type = VBLK;
		break;
	case 7:
		vp->v_type = VCHR;
		break;
	case 9:
		vp->v_type = VFIFO;
		vp->v_op = &udf_fifoops;
		break;
	case 10:
		vp->v_type = VSOCK;
		break;
	case 12:
		vp->v_type = VLNK;
		break;
	}

	if (vp->v_type != VFIFO)
		VN_LOCK_ASHARE(vp);

	if (ino == udf_getid(&udfmp->root_icb))
		vp->v_vflag |= VV_ROOT;

	*vpp = vp;

	return (0);
}
Ejemplo n.º 8
0
static int
udf_mountfs(struct vnode *devvp, struct mount *mp)
{
	struct buf *bp = NULL;
	struct cdev *dev;
	struct anchor_vdp avdp;
	struct udf_mnt *udfmp = NULL;
	struct part_desc *pd;
	struct logvol_desc *lvd;
	struct fileset_desc *fsd;
	struct file_entry *root_fentry;
	uint32_t sector, size, mvds_start, mvds_end;
	uint32_t logical_secsize;
	uint32_t fsd_offset = 0;
	uint16_t part_num = 0, fsd_part = 0;
	int error = EINVAL;
	int logvol_found = 0, part_found = 0, fsd_found = 0;
	int bsize;
	struct g_consumer *cp;
	struct bufobj *bo;

	dev = devvp->v_rdev;
	dev_ref(dev);
	DROP_GIANT();
	g_topology_lock();
	error = g_vfs_open(devvp, &cp, "udf", 0);
	g_topology_unlock();
	PICKUP_GIANT();
	VOP_UNLOCK(devvp, 0);
	if (error)
		goto bail;

	bo = &devvp->v_bufobj;

	if (devvp->v_rdev->si_iosize_max != 0)
		mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
	if (mp->mnt_iosize_max > MAXPHYS)
		mp->mnt_iosize_max = MAXPHYS;

	/* XXX: should be M_WAITOK */
	udfmp = malloc(sizeof(struct udf_mnt), M_UDFMOUNT,
	    M_NOWAIT | M_ZERO);
	if (udfmp == NULL) {
		printf("Cannot allocate UDF mount struct\n");
		error = ENOMEM;
		goto bail;
	}

	mp->mnt_data = udfmp;
	mp->mnt_stat.f_fsid.val[0] = dev2udev(devvp->v_rdev);
	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
	MNT_ILOCK(mp);
	mp->mnt_flag |= MNT_LOCAL;
	mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED;
	MNT_IUNLOCK(mp);
	udfmp->im_mountp = mp;
	udfmp->im_dev = dev;
	udfmp->im_devvp = devvp;
	udfmp->im_d2l = NULL;
	udfmp->im_cp = cp;
	udfmp->im_bo = bo;

#if 0
	udfmp->im_l2d = NULL;
#endif
	/*
	 * The UDF specification defines a logical sectorsize of 2048
	 * for DVD media.
	 */
	logical_secsize = 2048;

	if (((logical_secsize % cp->provider->sectorsize) != 0) ||
	    (logical_secsize < cp->provider->sectorsize)) {
		error = EINVAL;
		goto bail;
	}

	bsize = cp->provider->sectorsize;

	/* 
	 * Get the Anchor Volume Descriptor Pointer from sector 256.
	 * XXX Should also check sector n - 256, n, and 512.
	 */
	sector = 256;
	if ((error = bread(devvp, sector * btodb(logical_secsize), bsize,
			   NOCRED, &bp)) != 0)
		goto bail;
	if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR)))
		goto bail;

	bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp));
	brelse(bp);
	bp = NULL;

	/*
	 * Extract the Partition Descriptor and Logical Volume Descriptor
	 * from the Volume Descriptor Sequence.
	 * XXX Should we care about the partition type right now?
	 * XXX What about multiple partitions?
	 */
	mvds_start = le32toh(avdp.main_vds_ex.loc);
	mvds_end = mvds_start + (le32toh(avdp.main_vds_ex.len) - 1) / bsize;
	for (sector = mvds_start; sector < mvds_end; sector++) {
		if ((error = bread(devvp, sector * btodb(logical_secsize),
				   bsize, NOCRED, &bp)) != 0) {
			printf("Can't read sector %d of VDS\n", sector);
			goto bail;
		}
		lvd = (struct logvol_desc *)bp->b_data;
		if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) {
			udfmp->bsize = le32toh(lvd->lb_size);
			udfmp->bmask = udfmp->bsize - 1;
			udfmp->bshift = ffs(udfmp->bsize) - 1;
			fsd_part = le16toh(lvd->_lvd_use.fsd_loc.loc.part_num);
			fsd_offset = le32toh(lvd->_lvd_use.fsd_loc.loc.lb_num);
			if (udf_find_partmaps(udfmp, lvd))
				break;
			logvol_found = 1;
		}
		pd = (struct part_desc *)bp->b_data;
		if (!udf_checktag(&pd->tag, TAGID_PARTITION)) {
			part_found = 1;
			part_num = le16toh(pd->part_num);
			udfmp->part_len = le32toh(pd->part_len);
			udfmp->part_start = le32toh(pd->start_loc);
		}

		brelse(bp); 
		bp = NULL;
		if ((part_found) && (logvol_found))
			break;
	}

	if (!part_found || !logvol_found) {
		error = EINVAL;
		goto bail;
	}

	if (fsd_part != part_num) {
		printf("FSD does not lie within the partition!\n");
		error = EINVAL;
		goto bail;
	}


	/*
	 * Grab the Fileset Descriptor
	 * Thanks to Chuck McCrobie <*****@*****.**> for pointing
	 * me in the right direction here.
	 */
	sector = udfmp->part_start + fsd_offset;
	if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) {
		printf("Cannot read sector %d of FSD\n", sector);
		goto bail;
	}
	fsd = (struct fileset_desc *)bp->b_data;
	if (!udf_checktag(&fsd->tag, TAGID_FSD)) {
		fsd_found = 1;
		bcopy(&fsd->rootdir_icb, &udfmp->root_icb,
		    sizeof(struct long_ad));
	}

	brelse(bp);
	bp = NULL;

	if (!fsd_found) {
		printf("Couldn't find the fsd\n");
		error = EINVAL;
		goto bail;
	}

	/*
	 * Find the file entry for the root directory.
	 */
	sector = le32toh(udfmp->root_icb.loc.lb_num) + udfmp->part_start;
	size = le32toh(udfmp->root_icb.len);
	if ((error = udf_readdevblks(udfmp, sector, size, &bp)) != 0) {
		printf("Cannot read sector %d\n", sector);
		goto bail;
	}

	root_fentry = (struct file_entry *)bp->b_data;
	if ((error = udf_checktag(&root_fentry->tag, TAGID_FENTRY))) {
		printf("Invalid root file entry!\n");
		goto bail;
	}

	brelse(bp);
	bp = NULL;

	return 0;

bail:
	if (udfmp != NULL)
		free(udfmp, M_UDFMOUNT);
	if (bp != NULL)
		brelse(bp);
	if (cp != NULL) {
		DROP_GIANT();
		g_topology_lock();
		g_vfs_close(cp);
		g_topology_unlock();
		PICKUP_GIANT();
	}
	dev_rel(dev);
	return error;
};
Ejemplo n.º 9
0
int
udf_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
{
	struct buf *bp;
	struct vnode *devvp;
	struct umount *ump;
	struct proc *p;
	struct vnode *vp;
	struct unode *up;
	struct file_entry *fe;
	int error, sector, size;

	p = curproc;
	bp = NULL;
	*vpp = NULL;
	ump = VFSTOUDFFS(mp);

	/* See if we already have this in the cache */
	if ((error = udf_hashlookup(ump, ino, LK_EXCLUSIVE, vpp)) != 0)
		return (error);
	if (*vpp != NULL)
		return (0);

	/*
	 * Allocate memory and check the tag id's before grabbing a new
	 * vnode, since it's hard to roll back if there is a problem.
	 */
	up = pool_get(&unode_pool, PR_WAITOK);
	bzero(up, sizeof(struct unode));

	/*
	 * Copy in the file entry.  Per the spec, the size can only be 1 block.
	 */
	sector = ino;
	devvp = ump->um_devvp;
	udf_vat_map(ump, &sector);
	if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
		printf("Cannot read sector %d\n", sector);
		pool_put(&unode_pool, up);
		if (bp != NULL)
			brelse(bp);
		return (error);
	}

	fe = (struct file_entry *)bp->b_data;
	if (udf_checktag(&fe->tag, TAGID_FENTRY)) {
		printf("Invalid file entry!\n");
		pool_put(&unode_pool, up);
		brelse(bp);
		return (ENOMEM);
	}

	size = UDF_FENTRY_SIZE + letoh32(fe->l_ea) + letoh32(fe->l_ad);

	up->u_fentry = malloc(size, M_UDFFENTRY, M_NOWAIT);
	if (up->u_fentry == NULL) {
		pool_put(&unode_pool, up);
		brelse(bp);
		return (ENOMEM); /* Cannot allocate file entry block */
	}

	bcopy(bp->b_data, up->u_fentry, size);
	
	brelse(bp);
	bp = NULL;

	if ((error = udf_allocv(mp, &vp, p))) {
		free(up->u_fentry, M_UDFFENTRY);
		pool_put(&unode_pool, up);
		return (error); /* Error from udf_allocv() */
	}

	up->u_vnode = vp;
	up->u_ino = ino;
	up->u_devvp = ump->um_devvp;
	up->u_dev = ump->um_dev;
	up->u_ump = ump;
	vp->v_data = up;
	VREF(ump->um_devvp);

	lockinit(&up->u_lock, PINOD, "unode", 0, 0);

	/*
	 * udf_hashins() will lock the vnode for us.
	 */
	udf_hashins(up);

	switch (up->u_fentry->icbtag.file_type) {
	default:
		vp->v_type = VBAD;
		break;
	case UDF_ICB_TYPE_DIR:
		vp->v_type = VDIR;
		break;
	case UDF_ICB_TYPE_FILE:
		vp->v_type = VREG;
		break;
	case UDF_ICB_TYPE_BLKDEV:
		vp->v_type = VBLK;
		break;
	case UDF_ICB_TYPE_CHRDEV:
		vp->v_type = VCHR;
		break;
	case UDF_ICB_TYPE_FIFO:
		vp->v_type = VFIFO;
		break;
	case UDF_ICB_TYPE_SOCKET:
		vp->v_type = VSOCK;
		break;
	case UDF_ICB_TYPE_SYMLINK:
		vp->v_type = VLNK;
		break;
	case UDF_ICB_TYPE_VAT_150:
		vp->v_type = VREG;
		break;
	}

	*vpp = vp;

	return (0);
}
Ejemplo n.º 10
0
udf_dirent_t *
udf_readdir(udf_dirent_t *p_udf_dirent)
{
  udf_t *p_udf;
  uint8_t* p;

  if (p_udf_dirent->dir_left <= 0) {
    udf_dirent_free(p_udf_dirent);
    return NULL;
  }

  /* file position must be reset when accessing a new file */
  p_udf = p_udf_dirent->p_udf;
  p_udf->i_position = 0;

  if (p_udf_dirent->fid) {
    /* advance to next File Identifier Descriptor */
    /* FIXME: need to advance file entry (fe) as well.  */
    uint32_t ofs = 4 *
      ((sizeof(*(p_udf_dirent->fid)) + p_udf_dirent->fid->u.i_imp_use
	+ p_udf_dirent->fid->i_file_id + 3) / 4);

    p_udf_dirent->fid =
      (udf_fileid_desc_t *)((uint8_t *)p_udf_dirent->fid + ofs);
  }

  if (!p_udf_dirent->fid) {
    uint32_t i_sectors =
      (p_udf_dirent->i_loc_end - p_udf_dirent->i_loc + 1);
    uint32_t size = UDF_BLOCKSIZE * i_sectors;
    driver_return_code_t i_ret;

    if (!p_udf_dirent->sector)
      p_udf_dirent->sector = (uint8_t*) malloc(size);
    i_ret = udf_read_sectors(p_udf, p_udf_dirent->sector,
			     p_udf_dirent->i_part_start+p_udf_dirent->i_loc,
			     i_sectors);
    if (DRIVER_OP_SUCCESS == i_ret)
      p_udf_dirent->fid = (udf_fileid_desc_t *) p_udf_dirent->sector;
    else
      p_udf_dirent->fid = NULL;
  }

  if (p_udf_dirent->fid && !udf_checktag(&(p_udf_dirent->fid->tag), TAGID_FID))
    {
      uint32_t ofs =
	4 * ((sizeof(*p_udf_dirent->fid) + p_udf_dirent->fid->u.i_imp_use
	      + p_udf_dirent->fid->i_file_id + 3) / 4);

      p_udf_dirent->dir_left -= ofs;
      p_udf_dirent->b_dir =
	(p_udf_dirent->fid->file_characteristics & UDF_FILE_DIRECTORY) != 0;
      p_udf_dirent->b_parent =
	(p_udf_dirent->fid->file_characteristics & UDF_FILE_PARENT) != 0;

      {
	const unsigned int i_len = p_udf_dirent->fid->i_file_id;

	if (DRIVER_OP_SUCCESS != udf_read_sectors(p_udf, &p_udf_dirent->fe, p_udf->i_part_start
			 + uint32_from_le(p_udf_dirent->fid->icb.loc.lba), 1)) {
		udf_dirent_free(p_udf_dirent);
		return NULL;
	}

       free_and_null(p_udf_dirent->psz_name);
       p = (uint8_t*)p_udf_dirent->fid->u.imp_use.data + p_udf_dirent->fid->u.i_imp_use;
       p_udf_dirent->psz_name = unicode16_decode(p, i_len);
      }
      return p_udf_dirent;
    }
  udf_dirent_free(p_udf_dirent);
  return NULL;
}
Ejemplo n.º 11
0
/*!
  Get the root in p_udf. If b_any_partition is false then
  the root must be in the given partition.
  NULL is returned if the partition is not found or a root is not found or
  there is on error.

  Caller must free result - use udf_dirent_free for that.
*/
udf_dirent_t *
udf_get_root (udf_t *p_udf, bool b_any_partition, partition_num_t i_partition)
{
  const anchor_vol_desc_ptr_t *p_avdp = &p_udf->anchor_vol_desc_ptr;
  const uint32_t mvds_start =
    uint32_from_le(p_avdp->main_vol_desc_seq_ext.loc);
  const uint32_t mvds_end   = mvds_start +
    (uint32_from_le(p_avdp->main_vol_desc_seq_ext.len) - 1) / UDF_BLOCKSIZE;
  uint32_t i_lba;
  uint8_t data[UDF_BLOCKSIZE];

  /*
     Now we have the joy of finding the Partition Descriptor and the
     Logical Volume Descriptor for the Main Volume Descriptor
     Sequence. Once we've got that, we use the Logical Volume
     Descriptor to get a Fileset Descriptor and that has the Root
     Directory File Entry.
  */
  for (i_lba = mvds_start; i_lba < mvds_end; i_lba++) {
    uint8_t data2[UDF_BLOCKSIZE];

    partition_desc_t *p_partition = (partition_desc_t *) &data2;

    if (DRIVER_OP_SUCCESS != udf_read_sectors (p_udf, p_partition, i_lba, 1) )
      return NULL;

    if (!udf_checktag(&p_partition->tag, TAGID_PARTITION)) {
      const partition_num_t i_partition_check
	= uint16_from_le(p_partition->number);
      if (b_any_partition || i_partition_check == i_partition) {
	/* Squirrel away some data regarding partition */
	p_udf->i_partition = uint16_from_le(p_partition->number);
	p_udf->i_part_start = uint32_from_le(p_partition->start_loc);
	if (p_udf->lvd_lba) break;
      }
    } else if (!udf_checktag(&p_partition->tag, TAGID_LOGVOL)) {
      /* Get fileset descriptor */
      logical_vol_desc_t *p_logvol = (logical_vol_desc_t *) &data2;
      bool b_valid =
	UDF_BLOCKSIZE == uint32_from_le(p_logvol->logical_blocksize);

      if (b_valid) {
	p_udf->lvd_lba = i_lba;
	p_udf->fsd_offset =
	  uint32_from_le(p_logvol->lvd_use.fsd_loc.loc.lba);
	if (p_udf->i_part_start) break;
      }
    }
  }
  if (p_udf->lvd_lba && p_udf->i_part_start) {
    udf_fsd_t *p_fsd = (udf_fsd_t *) &data;

    driver_return_code_t ret =
      udf_read_sectors(p_udf, p_fsd, p_udf->i_part_start + p_udf->fsd_offset,
		       1);

    if (DRIVER_OP_SUCCESS == ret && !udf_checktag(&p_fsd->tag, TAGID_FSD)) {
      udf_file_entry_t *p_udf_fe = (udf_file_entry_t *) &data;
      const uint32_t parent_icb = uint32_from_le(p_fsd->root_icb.loc.lba);

      /* Check partition numbers match of last-read block?  */

      ret = udf_read_sectors(p_udf, p_udf_fe,
			     p_udf->i_part_start + parent_icb, 1);
      if (ret == DRIVER_OP_SUCCESS &&
	  !udf_checktag(&p_udf_fe->tag, TAGID_FILE_ENTRY)) {

	/* Check partition numbers match of last-read block? */

	/* We win! - Save root directory information. */
	return udf_new_dirent(p_udf_fe, p_udf, "/", true, false );
      }
    }
  }

  return NULL;
}
Ejemplo n.º 12
0
/*!
  Open an UDF for reading. Maybe in the future we will have
  a mode. NULL is returned on error.

  Caller must free result - use udf_close for that.
*/
udf_t *
udf_open (const char *psz_path)
{
  udf_t *p_udf = (udf_t *) calloc(1, sizeof(udf_t)) ;
  uint8_t data[UDF_BLOCKSIZE];

  if (!p_udf) return NULL;

  /* Sanity check */
  cdio_assert(sizeof(udf_file_entry_t) == UDF_BLOCKSIZE);

  p_udf->cdio = cdio_open(psz_path, DRIVER_UNKNOWN);
  if (!p_udf->cdio) {
    /* Not a CD-ROM drive or CD Image. Maybe it's a UDF file not
       encapsulated as a CD-ROM Image (e.g. often .UDF or (sic) .ISO)
    */
    p_udf->stream = cdio_stdio_new( psz_path );
    if (!p_udf->stream)
      goto error;
    p_udf->b_stream = true;
  }

  /*
   * Look for an Anchor Volume Descriptor Pointer at sector 256.
   */
  if (DRIVER_OP_SUCCESS != udf_read_sectors (p_udf, &data, 256, 1) )
    goto error;

  memcpy(&(p_udf->anchor_vol_desc_ptr), &data, sizeof(anchor_vol_desc_ptr_t));

  if (udf_checktag((udf_tag_t *)&(p_udf->anchor_vol_desc_ptr), TAGID_ANCHOR))
    goto error;

  /*
   * Then try to find a reference to a Primary Volume Descriptor.
   */
  {
    anchor_vol_desc_ptr_t *p_avdp = &p_udf->anchor_vol_desc_ptr;

    const uint32_t mvds_start =
      uint32_from_le(p_avdp->main_vol_desc_seq_ext.loc);
    const uint32_t mvds_end   = mvds_start +
      (uint32_from_le(p_avdp->main_vol_desc_seq_ext.len) - 1) / UDF_BLOCKSIZE;

    uint32_t i_lba;

    for (i_lba = mvds_start; i_lba < mvds_end; i_lba++) {
      udf_pvd_t *p_pvd = (udf_pvd_t *) &data;

      if (DRIVER_OP_SUCCESS != udf_read_sectors (p_udf, p_pvd, i_lba, 1) )
	goto error;

      if (!udf_checktag(&p_pvd->tag, TAGID_PRI_VOL)) {
	p_udf->pvd_lba = i_lba;
	break;
      }

    }

    /*
     * If we couldn't find a reference, bail out.
     */
    if (i_lba == mvds_end)
      goto error;
  }

  return p_udf;

 error:
  cdio_stdio_destroy(p_udf->stream);
  free(p_udf);
  return NULL;
}
Ejemplo n.º 13
0
udf_dirent_t *
udf_readdir(udf_dirent_t *p_udf_dirent)
{
  udf_t *p_udf;
  
  if (p_udf_dirent->dir_left <= 0) {
    udf_dirent_free(p_udf_dirent);
    return NULL;
  }

  p_udf = p_udf_dirent->p_udf;
  if (p_udf_dirent->fid) { 
    /* advance to next File Identifier Descriptor */
    /* FIXME: need to advance file entry (fe) as well.  */
    uint32_t ofs = 4 * 
      ((sizeof(*(p_udf_dirent->fid)) + p_udf_dirent->fid->i_imp_use 
	+ p_udf_dirent->fid->i_file_id + 3) / 4);
    
    p_udf_dirent->fid = 
      (udf_fileid_desc_t *)((uint8_t *)p_udf_dirent->fid + ofs);
  }
  
  if (!p_udf_dirent->fid) {
    uint32_t i_sectors = 
      (p_udf_dirent->i_loc_end - p_udf_dirent->i_loc + 1);
    uint32_t size = UDF_BLOCKSIZE * i_sectors;
    driver_return_code_t i_ret;

    if (!p_udf_dirent->sector)
      p_udf_dirent->sector = (uint8_t*) malloc(size);
    i_ret = udf_read_sectors(p_udf, p_udf_dirent->sector, 
			     p_udf_dirent->i_part_start+p_udf_dirent->i_loc, 
			     i_sectors);
    if (DRIVER_OP_SUCCESS == i_ret)
      p_udf_dirent->fid = (udf_fileid_desc_t *) p_udf_dirent->sector;
    else
      p_udf_dirent->fid = NULL;
  }
  
  if (p_udf_dirent->fid && !udf_checktag(&(p_udf_dirent->fid->tag), TAGID_FID))
    {
      uint32_t ofs = 
	4 * ((sizeof(*p_udf_dirent->fid) + p_udf_dirent->fid->i_imp_use 
	      + p_udf_dirent->fid->i_file_id + 3) / 4);
      
      p_udf_dirent->dir_left -= ofs;
      p_udf_dirent->b_dir = 
	(p_udf_dirent->fid->file_characteristics & UDF_FILE_DIRECTORY) != 0;
      p_udf_dirent->b_parent = 
	(p_udf_dirent->fid->file_characteristics & UDF_FILE_PARENT) != 0;

      {
	const unsigned int i_len = p_udf_dirent->fid->i_file_id;
	uint8_t data[UDF_BLOCKSIZE] = {0};
	udf_file_entry_t *p_udf_fe = (udf_file_entry_t *) &data;

	if (DRIVER_OP_SUCCESS != udf_read_sectors(p_udf, p_udf_fe, p_udf->i_part_start 
			 + p_udf_dirent->fid->icb.loc.lba, 1))
		return NULL;
      
	memcpy(&(p_udf_dirent->fe), p_udf_fe, 
	       sizeof(udf_file_entry_t) + p_udf_fe->i_alloc_descs 
	       + p_udf_fe->i_extended_attr );

	if (strlen(p_udf_dirent->psz_name) < i_len) 
	  p_udf_dirent->psz_name = (char *)
	    realloc(p_udf_dirent->psz_name, sizeof(char)*i_len+1);
	
	unicode16_decode(p_udf_dirent->fid->imp_use 
			 + p_udf_dirent->fid->i_imp_use, 
			 i_len, p_udf_dirent->psz_name);
      }
      return p_udf_dirent;
    }
  return NULL;
}