#include <sys/param.h>
#include <sys/systm.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/resourcevar.h>
#include <sys/kernel.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/kauth.h>
#include <sys/conf.h>
#include <sys/utfconv.h>
#include <miscfs/specfs/specdev.h>
#include <miscfs/fifofs/fifo.h>
#include <sys/malloc.h>
#include <sys/dir.h>
#include <sys/attr.h>
#include <kern/assert.h>
#include <isofs/cd9660/iso.h>
#include <isofs/cd9660/cd9660_node.h>
#include <isofs/cd9660/iso_rrip.h>
#include <libkern/OSByteOrder.h>
int
isofncmp(u_char *fn, int fnlen, u_char *isofn, int isolen)
{
int i, j;
char c;
while (--fnlen >= 0) {
if (--isolen < 0)
return *fn;
if ((c = *isofn++) == ';') {
switch (*fn++) {
default:
return *--fn;
case 0:
return 0;
case ';':
break;
}
for (i = 0; --fnlen >= 0; i = i * 10 + *fn++ - '0') {
if (*fn < '0' || *fn > '9') {
return -1;
}
}
for (j = 0; --isolen >= 0; j = j * 10 + *isofn++ - '0');
return i - j;
}
if (c != *fn) {
if (c >= 'A' && c <= 'Z') {
if (c + ('a' - 'A') != *fn) {
if (*fn >= 'a' && *fn <= 'z')
return *fn - ('a' - 'A') - c;
else
return *fn - c;
}
} else if (c == '/') {
if (*fn != ':')
return *fn - c;
} else if (c > 0 || *fn != '_')
return *fn - c;
}
fn++;
}
if (isolen > 0) {
switch (*isofn) {
default:
return -1;
case '.':
if (isofn[1] != ';')
return -1;
case ';':
return 0;
}
}
return 0;
}
int
ucsfncmp(u_int16_t *fn, int fnlen, u_int16_t *ucsfn, int ucslen)
{
int i, j;
u_int16_t c;
ucslen /= 2;
fnlen /= 2;
while (--fnlen >= 0) {
if (--ucslen < 0)
return *fn;
if ((c = OSSwapBigToHostInt16(*ucsfn++)) == UCS_SEPARATOR2) {
switch (*fn++) {
default:
return *--fn;
case 0:
return 0;
case UCS_SEPARATOR2:
break;
}
for (i = 0; --fnlen >= 0; i = i * 10 + *fn++ - '0') {
if (*fn < '0' || *fn > '9') {
return -1;
}
}
for (j = 0; --ucslen >= 0; j = j * 10 + OSSwapBigToHostInt16(*ucsfn++) - '0');
return i - j;
}
if (c != *fn)
return *fn - c;
fn++;
}
if (ucslen > 0) {
switch (*ucsfn) {
default:
return -1;
case OSSwapHostToBigConstInt16(UCS_SEPARATOR1):
if (ucsfn[1] != OSSwapHostToBigConstInt16(UCS_SEPARATOR2))
return -1;
case OSSwapHostToBigConstInt16(UCS_SEPARATOR2):
return 0;
}
}
return 0;
}
void
isofntrans(u_char *infn, int infnlen, u_char *outfn, u_short *outfnlen,
int original, int assoc)
{
int fnidx = 0;
if (assoc) {
*outfn++ = ASSOCCHAR1;
*outfn++ = ASSOCCHAR2;
fnidx += 2;
infnlen +=2;
}
for (; fnidx < infnlen; fnidx++) {
char c = *infn++;
if (!original) {
if (c < 0)
c = '_';
else if (c == '/')
c = ':';
else if (c == '.' && *infn == ';')
break;
else if (c == ';')
break;
}
*outfn++ = c;
}
*outfnlen = fnidx;
}
void
ucsfntrans(u_int16_t *infn, int infnlen, u_char *outfn, u_short *outfnlen,
int dir, int assoc)
{
if (infnlen == 1) {
strcpy(outfn, "..");
if (*(u_char*)infn == 0)
*outfnlen = 1;
else if (*(u_char*)infn == 1)
*outfnlen = 2;
} else {
int fnidx;
size_t outbytes;
int flags;
fnidx = infnlen/2;
flags = 0;
if (assoc) {
*outfn++ = ASSOCCHAR1;
*outfn++ = ASSOCCHAR2;
}
if (!dir) {
for (fnidx--; fnidx > 0; fnidx--) {
if (infn[fnidx] == OSSwapHostToBigConstInt16(UCS_SEPARATOR2)) {
if (fnidx > 0 && infn[fnidx-1] == OSSwapHostToBigConstInt16(UCS_SEPARATOR1))
fnidx--;
break;
}
}
if (fnidx <= 0)
fnidx = infnlen/2;
}
flags = UTF_NO_NULL_TERM | UTF_DECOMPOSED | UTF_BIG_ENDIAN;
(void) utf8_encodestr(infn, fnidx * 2, outfn, &outbytes, ISO_JOLIET_NAMEMAX, 0, flags);
*outfnlen = assoc ? outbytes + 2 : outbytes;
}
}
static int
isochildcount(struct vnode *vdp, int *dircnt, int *filcnt)
{
struct iso_node *dp;
struct buf *bp = NULL;
struct iso_mnt *imp;
struct iso_directory_record *ep;
uint32_t bmask;
int error = 0;
int reclen;
int dirs, files;
int blkoffset;
int logblksize;
int32_t diroffset;
dp = VTOI(vdp);
imp = dp->i_mnt;
bmask = imp->im_sector_size - 1;
logblksize = imp->im_sector_size;
blkoffset = diroffset = 0;
dirs = files = 0;
while (diroffset < dp->i_size) {
if ((diroffset & bmask) == 0) {
if (bp != NULL)
buf_brelse(bp);
if ( (error = cd9660_blkatoff(vdp, SECTOFF(imp, diroffset), NULL, &bp)) )
break;
blkoffset = 0;
}
ep = (struct iso_directory_record *)
(buf_dataptr(bp) + blkoffset);
reclen = isonum_711(ep->length);
if (reclen == 0) {
diroffset =
(diroffset & ~bmask) + logblksize;
continue;
}
if ((reclen < ISO_DIRECTORY_RECORD_SIZE) ||
(blkoffset + reclen > logblksize) ||
(reclen < ISO_DIRECTORY_RECORD_SIZE + isonum_711(ep->name_len))){
break;
}
if ((diroffset == 0) && (isonum_733(ep->size) > dp->i_size)) {
dp->i_size = isonum_733(ep->size);
}
if ( isonum_711(ep->flags) & directoryBit )
dirs++;
else if ((isonum_711(ep->flags) & associatedBit) == 0)
files++;
diroffset += reclen;
blkoffset += reclen;
}
if (bp)
buf_brelse (bp);
*dircnt = dirs;
*filcnt = files;
return (error);
}
static uint32_t
DerivePermissionSummary(uid_t owner, gid_t group, mode_t obj_mode, __unused struct iso_mnt *imp)
{
kauth_cred_t cred = kauth_cred_get();
uint32_t permissions;
int is_member;
if (!suser(cred, NULL)) {
permissions = R_OK | X_OK;
goto Exit;
};
if (owner == kauth_cred_getuid(cred)) {
permissions = ((uint32_t)obj_mode & S_IRWXU) >> 6;
goto Exit;
}
if (kauth_cred_ismember_gid(cred, group, &is_member) == 0 && is_member) {
permissions = ((uint32_t)obj_mode & S_IRWXG) >> 3;
goto Exit;
}
permissions = (uint32_t)obj_mode & S_IRWXO;
Exit:
return permissions & ~W_OK;
}