+ *bnp = daddr == 0 ? UNASSIGNED : daddr;
+ return (0);
+}
+
+/*
+ * Create an array of logical block number/offset pairs which represent the
+ * path of indirect blocks required to access a data block. The first "pair"
+ * contains the logical block number of the appropriate single, double or
+ * triple indirect block and the offset into the inode indirect block array.
+ * Note, the logical block number of the inode single/double/triple indirect
+ * block appears twice in the array, once with the offset into the i_ib and
+ * once with the offset into the page itself.
+ */
+int
+lfs_getlbns(vp, bn, ap, nump)
+ struct vnode *vp;
+ register daddr_t bn;
+ INDIR *ap;
+ int *nump;
+{
+ struct lfs *fs;
+ long metalbn, realbn;
+ int j, numlevels, off, sh;
+
+ if (nump)
+ *nump = 0;
+ numlevels = 0;
+ realbn = bn;
+ if ((long)bn < 0)
+ bn = -(long)bn;
+
+ /* The first NDADDR blocks are direct blocks. */
+ if (bn < NDADDR)
+ return (0);
+
+ /*
+ * Determine the number of levels of indirection. After this loop
+ * is done, sh indicates the number of data blocks possible at the
+ * given level of indirection, and NIADDR - j is the number of levels
+ * of indirection needed to locate the requested block.
+ */
+ bn -= NDADDR;
+ fs = VTOI(vp)->i_lfs;
+ sh = 1;
+ for (j = NIADDR; j > 0; j--) {
+ sh *= NINDIR(fs);
+ if (bn < sh)
+ break;
+ bn -= sh;
+ }
+ if (j == 0)
+ return (EFBIG);
+
+ /* Calculate the address of the first meta-block. */
+ if (realbn >= 0)
+ metalbn = -(realbn - bn + NIADDR - j);
+ else
+ metalbn = -(-realbn - bn + NIADDR - j);
+
+ /*
+ * At each iteration, off is the offset into the bap array which is
+ * an array of disk addresses at the current level of indirection.
+ * The logical block number and the offset in that block are stored
+ * into the argument array.
+ */
+ ++numlevels;
+ ap->in_lbn = metalbn;
+ ap->in_off = off = NIADDR - j;
+ ap++;
+ for (; j <= NIADDR; j++) {
+ /* If searching for a meta-data block, quit when found. */
+ if (metalbn == realbn)
+ break;
+
+ sh /= NINDIR(fs);
+ off = (bn / sh) % NINDIR(fs);
+
+ ++numlevels;
+ ap->in_lbn = metalbn;
+ ap->in_off = off;
+ ++ap;
+
+ metalbn -= -1 + off * sh;
+ }
+ if (nump)
+ *nump = numlevels;