/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* System Use Sharing protocol subroutines for High Sierra filesystem
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <sys/pathname.h>
/* static declarations */
static void free_cont_area(uchar_t *);
/*
* parse_sua()
*
* This is the main SUSP routine, that gets all the SUA areas and
* continuations. It calls parse_signatures() to actually interpret
* the signature fields.
*
* XXX - need to implement signature searching to speed things up and
* which is needed for the api, which isn't done yet.
*/
int
int *name_len_p, /* location to put name len */
int *name_change_p, /* flags to signal name chg */
int search_num) /* n^th sig to search for */
{
/*
* If there is no SUA, just return, no error
*/
if (SUA_len == 0)
return (0);
/*
* Underflow on the length field means there's a mismatch
* between sizes of SUA and ISO directory entry. This entry
* is corrupted, return an appropriate error.
*/
if (SUA_len < 0) {
return (SUA_EINVAL);
}
return (SUA_EINVAL);
}
/*
* Make sure that the continuation lenth is zero, as that is
* the way to tell if we must grab another continuation area.
*/
sig_args.name_flags = 0;
/*
* Get ready to put in a new name. If no "NM" is found, then
* hs_namecopy will come to the rescue. Make sure you don't
* have NULL names, also.
*/
if (name_p)
*(name_p) = '\0';
if (name_len_p)
*(name_len_p) = 0;
while (ret_val == -1) {
search_num)) {
case END_OF_SUA :
ret_val = 1;
goto clean_up;
}
continue;
}
ret_val = 0; /* keep going */
break;
case SUA_NULL_POINTER:
goto clean_up;
case SUA_ENOMEM:
goto clean_up;
case SUA_EINVAL:
goto clean_up;
case RELOC_DIR:
goto clean_up;
}
}
if (ret_val != 0)
goto clean_up;
return (ret_val);
}
/*
* parse_signatures()
*
* Find the correct handling function for the signature string that is
* passed to this function.
*
* signature searching:
*
* The two arguments of search_sig and search_num are for finding the
* search_num^th occurance of the signature search_sig. This will come
* in handy with searching for the "NM" field and is part of the api
* for rrip (which really can be used for any extension).
*/
/*ARGSUSED*/
static int
int SUA_len,
int search_num) /* n^th occurance of search_sig to */
/* search for */
{
int impl_bit_num = 0;
/* remaining to be parsed */
/* This should never happen ... just so we don't panic, literally */
return (SUA_NULL_POINTER);
if (SUA_len < 0)
return (SUA_EINVAL);
/*
* Until the end of SUA, search for the signatures
* (check for end of SUA (2 consecutive NULL bytes)) or the
* remaining length of the SUA is <= 3. The minimum signature
* field is 4.
*/
/*
* Find appropriate extension and signature table
*/
extnp++, impl_bit_num++) {
/*
* look at an extension only if it is implemented
* on the CD-ROM
*/
continue;
/*
* Find the appropriate signature
*/
ext_sigp++) {
if (strncmp((char *)sig_string,
SUF_SIG_LEN) == 0) {
if (SUA_rem < 0)
return (END_OF_SUA);
/*
* The SUA_len parameter specifies the
* length of the SUA that the kernel
* expects. There is also a length
* encoded in the SUA data. If they
* do not agree, bail out.
*/
"parse_signatures: SUA length too big: "
"expected=%d, found=%d",
return (SUA_EINVAL);
}
switch (sig_args_p->flags) {
case END_OF_SUA :
return (END_OF_SUA);
case SUA_ENOMEM :
return (SUA_ENOMEM);
case SUA_EINVAL :
return (SUA_EINVAL);
case RELOC_DIR :
return (RELOC_DIR);
default :
#if NAME_SEARCH
case NAME_CONTINUE :
/* nothing for now */
case NAME_CHANGE :
/* nothing for now */
#endif
break;
}
/* reset to be zero */
sig_args_p->flags = 0;
goto next_signature;
}
/* off to the next signature .... */
} /* for ext_sigp */
} /* for extnp (extension parsing) */
/*
* Opps, did not find this signature. We must
* advance on the the next signature in the SUA
* and pray to persumedly omniscient, omnipresent,
* almighty transcendental being(s) that the next
* record is in the susp format, or we get hosed.
*/
if (SUA_rem < SUF_MIN_LEN)
return (END_OF_SUA);
/*
* Failsafe
*/
if (SUA_rem < SUF_MIN_LEN ||
return (END_OF_SUA);
}
} /* while */
return (END_OF_SUA);
}
/*
* hs_fill_root_dirent()
*
*
* This function reads the root directory extent to get to the SUA of
* the "." entry of the root directory. It the checks to see if the
* susp is implemented.
*/
void
{
int error;
"hs_check_root_dirent: vp (0x%p) not a directory",
(void *)vp);
return;
}
if (error != 0) {
"hs_check_root_dirent: bread: error=(%d)", error);
goto end;
}
/* quick check */
/* keep on going */
}
/*
* Here, we know that the "." entry is the first in the sector
* just read (ISO 9660). Let's now check for the sharing
* protocol and set call the susp sig_handler() if we should.
* Then we run through the hs_parsedir() function to catch all
* the other possibilities of SUSP fields and continuations.
*
* If there is no SUA area, just return, and assume ISO.
*
* If the SUA area length is invalid (negative, due to a mismatch
* between dirent size and SUA size), return and hope for the best.
*/
if (IDE_SUA_LEN(root_ptr) <= 0)
goto end;
SUF_SIG_LEN) == 0) {
/*
* We have a match of the sharing signature, so let's
* call the sig_handler to do what is necessary. We can
* ignore the return value, as implemented bits are set.
*/
goto end;
}
} else {
goto end;
}
/*
* If the "ER" signature in the root directory is past any non SU
* signature, the Rock Ridge signatures will be ignored. This happens
* e.g. for filesystems created by mkisofs. In this case,
* IS_RRIP_IMPLEMENTED(fsp) will return 0 when the "ER" signature is
* parsed. Unfortunately, the results of this run will be cached for
* the root vnode. The solution is to run hs_parsedir() a second time
* for the root directory.
*/
HS_SECTOR_SIZE - secoff) == 0) {
}
/*
* If we did not get at least 1 extension, let's assume ISO and
* NULL out the implementation bits.
*/
fsp->hsfs_ext_impl = 0L;
end:
}
/*
* get_cont_area()
*
* This function allocates a memory block, if necessary, and reads the
* continuation area into the allocated space.
*
* Return value : 0 if the read and allocation went OK.
* 1 if there was an error.
*/
static int
{
int error;
/*
* Guard against invalid continuation area records.
* Both cont_offset and cont_len must be no longer than
* HS_SECTOR_SIZE. If they are, return an error.
*/
return (1);
}
if (error != 0) {
return (1);
}
/*
* This continuation area does not extend into the next sector
* so just copy the data to the buffer.
*/
}
/*
* This continuation area extends into the next sector so we
* need to do some dancing:
*
* - zero the return buffer so nothing random is returned
* - copy the partial data to the *beginning* of the return buffer
* - release the first sector's buffer
* - read the next sector
* - copy the remainder of the data to the return buffer
*/
else {
(char *)*buf_pp, partial_size);
cont_info_p->cont_offset = 0;
if (error != 0) {
error);
return (1);
}
}
return (0);
}
/*
* free_cont_area
*
* simple function to just free up memory, if it exists
*
*/
static void
{
if (cont_p)
}