/*-
* Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Yevgeny Binder and Dieter Baron.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 THE FOUNDATION OR CONTRIBUTORS
* 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.
*/
/*
* Initialize the vnode associated with a new hfsnode.
*/
void
hfs_vinit(struct mount *mp, int (**specops)(void *), int (**fifoops)(void *),
struct vnode **vpp)
{
struct hfsnode *hp;
struct vnode *vp;
/*
* hfs_libcb_opendev()
*
* hfslib uses this callback to open a volume's device node by name. However,
* by the time this is called here, the device node has already been opened by
* VFS. So we are passed the vnode to this volume's block device and use that
* instead of the device's name.
*/
int
hfs_libcb_opendev(
hfs_volume* vol,
const char* devname,
hfs_callback_args* cbargs)
{
hfs_libcb_data* cbdata = NULL;
hfs_libcb_argsopen* args;
int result, mode;
uint64_t psize;
unsigned secsize;
result = 0;
args = (hfs_libcb_argsopen*)(cbargs->openvol);
if (vol == NULL || devname == NULL) {
result = EINVAL;
goto error;
}
cbdata = malloc(sizeof(hfs_libcb_data), M_HFSMNT, M_WAITOK);
if (cbdata == NULL) {
result = ENOMEM;
goto error;
}
vol->cbdata = cbdata;
cbdata->devvp = NULL;
/* Open the device node. */
mode = vol->readonly ? FREAD : FREAD|FWRITE;
vn_lock(args->devvp, LK_EXCLUSIVE | LK_RETRY);
result = VOP_OPEN(args->devvp, mode, FSCRED);
VOP_UNLOCK(args->devvp);
if (result != 0)
goto error;
/* Flush out any old buffers remaining from a previous use. */
vn_lock(args->devvp, LK_EXCLUSIVE | LK_RETRY);
result = vinvalbuf(args->devvp, V_SAVE, args->cred, args->l, 0, 0);
VOP_UNLOCK(args->devvp);
if (result != 0) {
VOP_CLOSE(args->devvp, mode, FSCRED);
goto error;
}
cbdata->devvp = args->devvp;
/* Determine the device's block size. Default to DEV_BSIZE if unavailable.*/
if (getdisksize(args->devvp, &psize, &secsize) != 0)
cbdata->devblksz = DEV_BSIZE;
else
cbdata->devblksz = secsize;
/*
* Since bread() only reads data in terms of integral blocks, it may have
* read some data before and/or after our desired offset & length. So when
* copying that data into the outgoing buffer, start at the actual desired
* offset and only copy the desired length.
*/
physoffset = offset + vol->offset;
/*
* So it turns out that bread() is pretty shoddy. It not only requires the size
* parameter to be an integral multiple of the device's block size, but also
* requires the block number to be on a boundary of that same block size -- and
* yet be given as an integral multiple of DEV_BSIZE! So after much toil and
* bloodshed, hfs_pread() was written as a convenience (and a model of how sane
* people take their bread()). Returns 0 on success.
*/
int
hfs_pread(struct vnode *vp, void *buf, size_t secsz, uint64_t off,
uint64_t len, kauth_cred_t cred)
{
struct buf *bp;
uint64_t curoff; /* relative to 'start' variable */
uint64_t start;
int error;
if (bp != NULL)
brelse(bp, 0);
if (error != 0)
return error;
curoff += MAXBSIZE;
}
#undef ABSZ
#undef RBSZ
return 0;
}
/* XXX Provide a routine to take a catalog record and return its proper BSD file
* XXX or directory mode value */
/* Convert from HFS+ time representation to UNIX time since epoch. */
void
hfs_time_to_timespec(uint32_t hfstime, struct timespec *unixtime)
{
/*
* HFS+ time is calculated in seconds since midnight, Jan 1st, 1904.
* struct timespec counts from midnight, Jan 1st, 1970. Thus, there is
* precisely a 66 year difference between them, which is equal to
* 2,082,844,800 seconds. No, I didn't count them by hand.
*/
if (hfstime < 2082844800)
unixtime->tv_sec = 0; /* dates before 1970 are bs anyway, so use epoch*/
else
unixtime->tv_sec = hfstime - 2082844800;
unixtime->tv_nsec = 0; /* we don't have nanosecond resolution */
}
/*
* Endian conversion with automatic pointer incrementation.
*/