#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/lock.h>
#include <sys/dirent.h>
#include <sys/disklabel.h>
#include <crypto/siphash.h>
#include <isofs/udf/ecma167-udf.h>
#include <isofs/udf/udf.h>
#include <isofs/udf/udf_extern.h>
int udf_vat_read(struct umount *, uint32_t *);
int
udf_rawnametounicode(u_int len, char *cs0string, unicode_t *transname)
{
unicode_t *origname = transname;
if (len-- == 0)
return (-1);
switch (*cs0string++) {
case 8:
while (len-- != 0)
*transname++ = (unicode_t)*cs0string++;
break;
case 16:
if (len & 1)
return (-1);
len >>= 1;
while (len-- != 0) {
unicode_t tmpchar;
tmpchar = (unicode_t)*cs0string++;
tmpchar = (tmpchar << 8) | (unicode_t)*cs0string++;
*transname++ = tmpchar;
}
break;
default:
return (-1);
}
return (transname - origname);
}
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;
bp = geteblk(bsize);
bp->b_dev = dev;
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;
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 (sector == mvds_end)
goto out;
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);
}
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_magic = DISKMAGIC;
lp->d_magic2 = DISKMAGIC;
lp->d_checksum = dkcksum(lp);
error = 0;
out:
bp->b_flags |= B_INVAL;
brelse(bp);
return (error);
}
int
udf_vat_get(struct umount *ump, uint32_t lb)
{
struct vnode *vp;
struct unode *up;
int error;
error = udf_vget(ump->um_mountp, lb - ump->um_start - 3, &vp);
if (error)
return (error);
up = VTOU(vp);
up->u_vatlen = (letoh64(up->u_fentry->inf_len) - 36) >> 2;
ump->um_vat = malloc(sizeof(struct unode), M_UDFMOUNT, M_WAITOK);
*ump->um_vat = *up;
ump->um_flags &= ~UDF_MNT_FIND_VAT;
ump->um_flags |= UDF_MNT_USES_VAT;
vput(vp);
return (0);
}
int
udf_vat_map(struct umount *ump, uint32_t *sector)
{
if (!(ump->um_flags & UDF_MNT_USES_VAT)) {
*sector += ump->um_start;
return (0);
}
if (*sector >= ump->um_vat->u_vatlen)
return (EINVAL);
return (udf_vat_read(ump, sector));
}
int
udf_vat_read(struct umount *ump, uint32_t *sector)
{
struct buf *bp;
uint8_t *data;
int error, size;
size = 4;
error = udf_readatoffset(ump->um_vat, &size, *sector << 2, &bp, &data);
if (error) {
if (bp != NULL)
brelse(bp);
return (error);
}
if (size < 4) {
if (bp != NULL)
brelse(bp);
return (EINVAL);
}
*sector = letoh32(*(uint32_t *)data) + ump->um_start;
brelse(bp);
return (0);
}