root/src/add-ons/kernel/file_systems/fat/bsd/fs/msdosfs/msdosfs_vnops.c
/* $FreeBSD$ */
/*      $NetBSD: msdosfs_vnops.c,v 1.68 1998/02/10 14:10:04 mrg Exp $   */

/*-
 * SPDX-License-Identifier: BSD-4-Clause
 *
 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
 * All rights reserved.
 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by TooLs GmbH.
 * 4. The name of TooLs GmbH may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/*-
 * Written by Paul Popelka (paulp@uts.amdahl.com)
 *
 * You can do anything you want with this software, just don't say you wrote
 * it, and don't remove this notice.
 *
 * This software is provided "as is".
 *
 * The author supplies this software to be publicly redistributed on the
 * understanding that the author is not responsible for the correct
 * functioning of this software in any circumstances and is not liable for
 * any damages caused by this software.
 *
 * October 1992
 */


// Modified to support the Haiku FAT driver.

#include "sys/param.h"
#include "sys/systm.h"
#include "sys/buf.h"
#include "sys/vnode.h"

#include "fs/msdosfs/bpb.h"
#include "fs/msdosfs/denode.h"
#include "fs/msdosfs/direntry.h"
#include "fs/msdosfs/fat.h"
#include "fs/msdosfs/msdosfsmount.h"


int msdosfs_bmap(struct vnode* a_vp, daddr_t a_bn, struct bufobj** a_bop, daddr_t* a_bnp,
        int* a_runp, int* a_runb);


/*
 * Some general notes:
 *
 * In the ufs filesystem the inodes, superblocks, and indirect blocks are
 * read/written using the vnode for the filesystem. Blocks that represent
 * the contents of a file are read/written using the vnode for the file
 * (including directories when they are read/written as files). This
 * presents problems for the dos filesystem because data that should be in
 * an inode (if dos had them) resides in the directory itself. Since we
 * must update directory entries without the benefit of having the vnode
 * for the directory we must use the vnode for the filesystem. This means
 * that when a directory is actually read/written (via read, write, or
 * readdir, or seek) we must use the vnode for the filesystem instead of
 * the vnode for the directory as would happen in ufs.
 */


/*!
        @param a_vp pointer to the file's vnode
        @param a_bn logical block number within the file (cluster number for us)
        @param a_bop where to return the bufobj of the special file containing the fs
        @param a_bnp where to return the "physical" block number corresponding to a_bn
                (relative to the special file; units are blocks of size DEV_BSIZE)
        @param a_runp where to return the "run past" a_bn. This is the count of logical blocks whose
                physical blocks (together with a_bn's physical block) are contiguous.
        @param a_runb where to return the "run before" a_bn.
*/
int
msdosfs_bmap(struct vnode* a_vp, daddr_t a_bn, struct bufobj** a_bop, daddr_t* a_bnp, int* a_runp,
        int* a_runb)
{
        struct fatcache savefc;
        struct denode* dep;
        struct mount* mp;
        struct msdosfsmount* pmp;
        struct vnode* vp;
        daddr_t runbn;
        u_long cn;
        int bnpercn, error, maxio, maxrun, run;

        vp = a_vp;
        dep = VTODE(vp);
        pmp = dep->de_pmp;
        if (a_bop != NULL)
                *a_bop = &pmp->pm_devvp->v_bufobj;
        if (a_bnp == NULL)
                return 0;
        if (a_runp != NULL)
                *a_runp = 0;
        if (a_runb != NULL)
                *a_runb = 0;
        cn = a_bn;
        if (cn != (u_long)a_bn)
                return EFBIG;
        error = pcbmap(dep, cn, a_bnp, NULL, NULL);
        if (error != 0 || (a_runp == NULL && a_runb == NULL))
                return error;

        /*
         * Prepare to back out updates of the fatchain cache after the one
         * for the first block done by pcbmap() above. Without the backout,
         * then whenever the caller doesn't do i/o to all of the blocks that
         * we find, the single useful cache entry would be too far in advance
         * of the actual i/o to work for the next sequential i/o. Then the
         * FAT would be searched from the beginning. With the backout, the
         * FAT is searched starting at most a few blocks early. This wastes
         * much less time. Time is also wasted finding more blocks than the
         * caller will do i/o to. This is necessary because the runlength
         * parameters are output-only.
         */
        savefc = dep->de_fc[FC_LASTMAP];

        mp = vp->v_mount;
        maxio = mp->mnt_iosize_max / mp->mnt_stat.f_iosize;
        bnpercn = de_cn2bn(pmp, 1);
        if (a_runp != NULL) {
                maxrun = ulmin(maxio - 1, pmp->pm_maxcluster - cn);
                for (run = 1; run <= maxrun; run++) {
                        if (pcbmap(dep, cn + run, &runbn, NULL, NULL) != 0 || runbn != *a_bnp + run * bnpercn)
                                break;
                }
                *a_runp = run - 1;
        }
        if (a_runb != NULL) {
                maxrun = ulmin(maxio - 1, cn);
                for (run = 1; run < maxrun; run++) {
                        if (pcbmap(dep, cn - run, &runbn, NULL, NULL) != 0 || runbn != *a_bnp - run * bnpercn)
                                break;
                }
                *a_runb = run - 1;
        }
        dep->de_fc[FC_LASTMAP] = savefc;
        return 0;
}


/* Global vfs data structures for msdosfs */
struct vop_vector msdosfs_vnodeops;