/**
* ntfs_rl_vcn_to_lcn - convert a vcn into a lcn given a runlist
* @rl: runlist to use for conversion
* @vcn: vcn to convert
*
* Convert the virtual cluster number @vcn of an attribute into a logical
* cluster number (lcn) of a device using the runlist @rl to map vcns to their
* corresponding lcns.
*
* Since lcns must be >= 0, we use negative return values with special meaning:
*
* Return value Meaning / Description
* ==================================================
* -1 = LCN_HOLE Hole / not allocated on disk.
* -2 = LCN_RL_NOT_MAPPED This is part of the runlist which has not been
* inserted into the runlist yet.
* -3 = LCN_ENOENT There is no such vcn in the attribute.
* -4 = LCN_EINVAL Input parameter error.
*/
LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn)
{
int i;
if (vcn < (VCN)0)
return (LCN)LCN_EINVAL;
/*
* If rl is NULL, assume that we have found an unmapped runlist. The
* caller can then attempt to map it and fail appropriately if
* necessary.
*/
if (!rl)
return (LCN)LCN_RL_NOT_MAPPED;
/* Catch out of lower bounds vcn. */
if (vcn < rl[0].vcn)
return (LCN)LCN_ENOENT;
for (i = 0; rl[i].length; i++) {
if (vcn < rl[i+1].vcn) {
if (rl[i].lcn >= (LCN)0)
return rl[i].lcn + (vcn - rl[i].vcn);
return rl[i].lcn;
}
}
/*
* The terminator element is setup to the correct value, i.e. one of
* LCN_HOLE, LCN_RL_NOT_MAPPED, or LCN_ENOENT.
*/
if (rl[i].lcn < (LCN)0)
return rl[i].lcn;
/* Just in case... We could replace this with BUG() some day. */
return (LCN)LCN_ENOENT;
}