1
0
Files
irix-657m-src/eoe/cmd/mountcdda/cdda.c
2022-09-29 17:59:04 +03:00

1184 lines
30 KiB
C

/*
* cdda.c
*
* Description:
* Routines called from nfs_server that fake Unix into thinking the CD
* is in some file system format.
*
* Notes:
* I present the CD tracks as .aiff files. This enables a bunch of utilities
* like soundplayer and cp to "just work". To my knowledge, the cdda format is
* not used on disk. The subcode info becomes nonsense in that context.
*
*/
#include <dslib.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <limits.h>
#include <sys/types.h>
#include <time.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <sys/schedctl.h>
#include <sys/socket.h>
#include <sys/sysmacros.h>
#include <rpc/rpc.h>
#include <rpc/svc.h>
#include <rpcsvc/ypclnt.h>
#include <stdio.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <filehdr.h>
#include <ctype.h>
#include <exportent.h>
#include <netdb.h>
#include <elf.h>
#include <ulocks.h>
#include "key.h"
#include "cdda.h"
#include "util.h"
#include "main.h"
#define TERM_COOKIE (-1)
#define ROOT_DIR() getfd(cd->dsp)
#define PERM_RALL 0444
#define PERM_XALL 0111
#define PERM_RXALL 0555
#define max(a,b) ((a) < (b) ? (b) : (a))
#define CHARSTOLONG(chars) ((chars)[0] << 24 | (chars)[1] << 16 \
| (chars)[2] << 8 | (chars)[3])
#define CHARSTOSHORT(chars) ((chars)[0] << 8 | (chars)[1])
/* #define CDDADBG(x) {x;} */
#define CDDADBG(x) {}
#define MAX_INFO_STRING_SIZE 200
#define AIFF_HEADER_SIZE 54
/*
* Sometimes we need to differentiate between iso9660 and high sierra
*/
typedef enum cdtype { CDDA, ISO, HSFS } cdtype_t;
static char dot[] = ".";
static char dotdot[] = "..";
static char disctrackname[] = "info.disc";
/*
* if notranslate == 1, user will see raw, ugly file names
*/
static int notranslate = 0;
/*
* if setx == 1, we'll blindly set execute permissions for every file.
*/
static int setx = 0;
static int def_num_blocks = 256;
/* These are internal to player.c so I need to copy them here. */
enum drivetype { UNKNOWN, TOSHIBA, SONY, TOSHIBA_SCSI2 };
typedef struct {
int min, sec, frame;
} TRACK;
struct cdplayer {
unsigned int paused : 1; /* For Sony; drive automatically pauses,
* so we use this to tell if we should set
* pause state or not
*/
int track; /* Current track being played */
int index;
int first; /* Number of first track on CD */
int last; /* Number of last track on CD */
int min; /* Minutes of current track */
int sec; /* Seconds of current track */
int frame; /* Frame of current track */
int abs_min; /* Minutes of CD */
int abs_sec; /* Seconds of CD */
int abs_frame; /* Frames of CD */
int total_min; /* Total minutes on CD */
int total_sec; /* Total seconds on CD */
int total_frame;/* Total frames on CD */
int scsi_audio; /* Player can do SCSI audio transfer */
unsigned long cur_block; /* Logical block no. of current location */
struct dsreq *dsp; /* Struct for doing SCSI requests */
int excl_id; /* Exclusive use id from mediad */
int state; /* State of player */
enum drivetype type; /* Type of the CDROM drive */
TRACK *toc; /* Table of contents */
char *dev; /* name of dev scsi device */
};
/* extern CDPLAYER *cd; */
int cdFirst, cdLast;
CDTRACKINFO cdInfo[100];
/*
* Number of blocks in the mounted file system
*/
static int fsBlocks;
/*
* Type of file system - iso9660 or high sierra
*/
static cdtype_t fsType;
/*
* The root file handle of the mounted file system
*/
static fhandle_t rootfh;
/*
* The path name of the mount point of the file system
*/
static char* mountPoint;
/* The name of the scsi device */
static char* devName;
/* These guys are used for our own attr (semi)caching. */
int cachedFno;
fattr* cachedFattr;
char keyString[KEY_SIZE];
char infoFileString[MAX_NFS_BUFFER_SIZE];
/* This function is a blackbox to me. I don't dare change anything, because if the
key generated any differently, then the existing SGI cd database would be invalid.
*/
void set_key()
{
int i;
int nCDTracks = cd->last - cd->first + 1;
int len = 0;
int min = 0;
int sec = 0;
CDTRACKINFO info;
int nIDTracks;
char* tmpStr = keyString;
/* map defined in key.h is a macro which produces a side effect on keyString */
map(tmpStr, len, ((nCDTracks>>4)&0xf) );
map(tmpStr, len, (nCDTracks&0xf) );
if (nCDTracks <= DB_ID_NTRACKS) {
nIDTracks = nCDTracks;
}
else {
nIDTracks = DB_ID_NTRACKS - 1;
for (i = cd->first; i <= cd->last; i++) {
CDgettrackinfo(cd, i, &info );
min += info.total_min;
sec += info.total_sec;
}
min+= sec / 60;
sec = sec % 60;
map(tmpStr, len, min);
map(tmpStr, len, sec);
}
for (i = 0; i < nIDTracks; i++) {
if (cd->first+i <= cd->last) {
CDgettrackinfo( cd, cd->first+i, &info );
map(tmpStr, len, info.total_min );
map(tmpStr, len, info.total_sec );
}
}
*tmpStr++ = '\0';
}
/*
* Forward declarations of static functions
*/
/* static int set_blocks(); */
static void add_entry(entry *entries, int fd, char *name, int
name_len, int cookie);
/*
* int
* cdda_numblocks(unsigned int *blocks)
*
* Description:
* Fill in blocks with the number of blocks in the file system
*
* Parameters:
* blocks receives # of blocks
*
* Returns:
* 0 if successful, error code otherwise
*/
int cdda_numblocks(unsigned int *blocks)
{
int error, changed;
*blocks = (unsigned int)fsBlocks;
CDDADBG(fprintf(stderr, "cdda_numblocks() == %d\n", *blocks));
return 0;
}
/*
* int
* cdda_isfd(int fd)
*
* Description:
* Determine whether fd is a file descriptor that we care about, so
* that the caller knows not to close it
*
* Parameters:
* fd file descriptor
*
* Returns:
* 1 if we care, 0 if we don't
*/
int
cdda_isfd(int fd)
{
return (cd->dsp && getfd( cd->dsp ) == fd);
}
void virtual_info_file(char* data)
{
char tmpString[MAX_INFO_STRING_SIZE];
int fill, i, n;
fill = 0;
bzero(infoFileString, MAX_NFS_BUFFER_SIZE);
set_key();
sprintf(tmpString, "album.key: %s\n", keyString);
n = strlen(tmpString);
strncpy(data,tmpString, n);
fill += n;
sprintf(tmpString, "album.duration: %02d:%02d:%02d\n",
cd->total_min, cd->total_sec, cd->total_frame);
n = strlen(tmpString);
strncpy(data + fill,tmpString, n);
fill += n;
sprintf(tmpString, "album.tracks: %d\n", cd->last);
n = strlen(tmpString);
strncpy(data + fill,tmpString, n);
fill += n;
for (i = cd->first; i <= cd->last; i++) {
sprintf(tmpString, "track%d.start: %02d:%02d:%02d\ntrack%d.duration: %02d:%02d:%02d\n",
i,cdInfo[i].start_min, cdInfo[i].start_sec, cdInfo[i].start_frame,
i,cdInfo[i].total_min, cdInfo[i].total_sec, cdInfo[i].total_frame);
n = strlen(tmpString);
strncpy(data + fill,tmpString, n);
fill += n;
}
}
/* Used primarily to give files new modification times across ejects.
*/
int openTime;
/* This our hack to prevent multiple reads. Zero means ok-to-read, one means
don't.
*/
int readLock;
/*
* void
* cdda_removefs()
*
* Description:
* CDDA 9660 specific removal of a generic file system
*
* Parameters:
*/
void cdda_removefs()
{
if (cd) {
CDclose(cd);
cd = NULL;
cdLast = 0;
}
}
/* link the frames together for seamless buffering
*/
int frameBufferIndex, frameAudioIndex, readFrameCount;
int bufferMinOffset, bufferMaxOffset, offsetCache;
int trackNumCache;
unsigned long initialTrackBlock;
/*
* int
* cdda_openfs(char *dev, char *mntpnt, int flags, int partition)
*
* description:
* Get ready to mount the dev on mntpnt
*
* Parameters:
* dev Device for CD-ROM drive
* mntpnt The mount point
* root gets root file handle
*
* Returns:
* 0 if successful, error code otherwise
*/
int cdda_openfs(char *dev, char *mntpnt, fhandle_t *root)
{
int error = 0;
int i;
static dev_t fakedev = 1;
struct stat sb;
struct dsreq* dsp2;
CDDADBG(fprintf(stderr, "cdda_openfs(%s)\n", dev));
cachedFno = -1;
cachedFattr = (fattr*)malloc(sizeof(fattr));
frameBufferIndex = frameAudioIndex = readFrameCount = 0;
bufferMinOffset = bufferMaxOffset = offsetCache = 0;
trackNumCache = 0;
initialTrackBlock = 0;
if (cd) {
CDclose(cd);
}
cd = CDopen(dev, "r");
devName = dev;
if (!cd) {
fprintf(stderr,"fstat failed...\n");
return (errno);
}
CDpreventremoval(cd);
if (fstat( getfd( cd->dsp), &sb ) < 0) {
fprintf(stderr,"fstat failed...\n");
return (errno);
}
rootfh.fh_dev = S_ISREG(sb.st_mode) ? 0xff00 | (fakedev++ & 0xff)
: sb.st_rdev;
mountPoint = strdup(mntpnt);
fsType = CDDA;
CDDADBG(fprintf(stderr, " cdda_openfs: Disc is in CDDA format\n"));
fsBlocks = cd->total_frame + (cd->total_sec * 75) + (cd->total_min * 60 *75);
rootfh.fh_fno = ROOT_DIR();
rootfh.fh_fid.lfid_len = sizeof rootfh.fh_fid -
sizeof rootfh.fh_fid.lfid_len;
/*
* We need to do this so that the user can eject.
*/
if (error) {
CDclose(cd);
} else {
bcopy(&rootfh, root, sizeof *root);
}
cdFirst = cd->first;
cdLast = cd->last;
bzero(cdInfo, 99*sizeof(CDTRACKINFO));
for (i = cdFirst; i <= cdLast; i++)
CDgettrackinfo( cd, i, &cdInfo[i]);
/* "make" the info.disc" file */
virtual_info_file(infoFileString);
CDclose(cd); /* prevents removal too */
free(cd);
cd = NULL;
openTime = time(NULL);
readLock = 0;
return error;
}
/*
* int
* cdda_lookup(fhandle_t *fh, char *name, fhandle_t *fh_ret)
*
* Description:
* Look for name in fh (a directory); if found, fill in fh_ret
*
* Parameters:
* fh file handle of directory in which to look
* name name of file we're looking for
* fh_ret Receive handle for name
*
* Returns:
* 0 if successful, error code otherwise
*/
int cdda_lookup(fhandle_t *fh, char *name, fhandle_t *fh_ret)
{
int blksize;
int trackNum;
int retval;
CDDADBG(fprintf(stderr, "cdda_lookup(%d, %s)\n", fh->fh_fno, name));
if (fh->fh_fno != rootfh.fh_fno) { /* this is the only directory we got */
retval= ENOTDIR;
}
else if (strcmp(name, dot) == 0) {
*fh_ret = *fh;
retval = 0;
}
else if (strcmp(name, disctrackname) == 0) {
bzero(fh_ret, sizeof *fh_ret);
fh_ret->fh_dev = fh->fh_dev;
fh_ret->fh_fid.lfid_fno = rootfh.fh_fno + cdLast + 1;
sizeof fh_ret->fh_fid - sizeof fh_ret->fh_fid.lfid_len;
retval = 0;
}
else {
/* Names are easy. They're just track numbers.*/
sscanf(name, "Track%02d.aiff", &trackNum);
if (cdLast && trackNum >= cdFirst && trackNum <= cdLast) {
bzero(fh_ret, sizeof *fh_ret);
fh_ret->fh_dev = fh->fh_dev;
fh_ret->fh_fid.lfid_fno = rootfh.fh_fno + trackNum;
fh_ret->fh_fid.lfid_len =
sizeof fh_ret->fh_fid - sizeof fh_ret->fh_fid.lfid_len;
retval = 0;
}
else
retval = ENOENT;
}
return retval;
}
/* This is very cute. Its the byte pattern to represent 44.1k in IEEE 754
(Apple SANE).
*/
char IEEEfor44_1k[10] = { 0x40, 0x0e, 0xac, 0x44, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00 };
int mfs_to_bytes(int m, int s, int f)
{
return CDDA_DATASIZE * (f + (s*75) + (m*75*60));
}
/* Writes an integer a byte at a time into "data" and updates the pointer into "data"
*/
void byte_write(char* data, int* fill, int value, int numBytes)
{
int i;
for (i = numBytes-1; i >= 0; i--, (*fill)++)
data[*fill] = (char)(value >> (8*i));
}
unsigned long offset_to_cdblock(unsigned long offset, int* audioIndex)
{
unsigned long dataOffset = offset - AIFF_HEADER_SIZE;
/* The modulus 4 term is to get the pointer back on a stereo sample */
/* boundary. */
*audioIndex = (dataOffset % CDDA_DATASIZE) - (dataOffset % 4);
return dataOffset / CDDA_DATASIZE;
}
int cdblock_to_offset(unsigned long blockNum)
{
return ((int)(blockNum-initialTrackBlock))*CDDA_DATASIZE + AIFF_HEADER_SIZE;
}
/* double buffering data structures */
#define CDFRAMEBUFFERSIZE 12
CDFRAME cdFrameBuffer[CDFRAMEBUFFERSIZE];
/* these get carried across calls to cdda_read()
*/
int dataSize, fileSize;
/* Fake the aiff header
*/
void virtual_aiff_header(char* data, int* fill)
{
int i;
/* Form Chunk */
strcpy(data,"FORM");
*fill += 4;
byte_write(data, fill, (fileSize - 8), 4);
strcpy(data+(*fill),"AIFF");
*fill += 4;
/* Common Chunk */
strcpy(data+(*fill),"COMM");
*fill += 4;
byte_write(data, fill, 18, 4); /* ckDataSize */
byte_write(data, fill, (short)2, 2); /* numChannels */
byte_write(data, fill, (dataSize / 4), 4); /* numSampleFrames */
byte_write(data, fill, (short)16, 2); /* SampleSize */
for (i = 0; i < 10; i++)
data[*fill+i] = IEEEfor44_1k[i]; /* SampleRate (hard-wired float) */
*fill += 10;
/* Sound Data Chunk */
strcpy(data+(*fill), "SSND");
*fill += 4;
byte_write(data, fill, (dataSize + 8), 4);
byte_write(data, fill, 0, 4);
byte_write(data, fill, 0, 4);
}
bool_t readingCdBuffer = FALSE;
pid_t bufferingThread = NULL;
void FillCdFrameBuffer()
{
int i;
bufferMinOffset = cdblock_to_offset(cd->cur_block);
readFrameCount =
CDreadda(cd, cdFrameBuffer, CDFRAMEBUFFERSIZE);
bufferMaxOffset = cdblock_to_offset(cd->cur_block);
CDDADBG(fprintf(stderr,"filling %d blocks: minOffset = %d, maxOffset = %d, cur_block = %d\n",
readFrameCount, bufferMinOffset, bufferMaxOffset, (int)cd->cur_block));
if (readFrameCount != CDFRAMEBUFFERSIZE)
CDDADBG(fprintf(stderr,"warning: asked for %d blocks, got %d blocks.\n",
CDFRAMEBUFFERSIZE, readFrameCount));
frameBufferIndex = frameAudioIndex = 0;
}
/*
* int
* cdda_read(fhandle_t *fh, int offset, int count, char *data,
* unsigned int *amountRead)
*
* Description:
* Read count bytes from file fh into buffer data
*
* Parameters:
* fh file handle of file from which to read
* offset offset into file to start reading
* count number of bytes to read including aiff header
* data buffer to read bytes into
* amountRead Amount of data actually read
*
* Returns:
* 0 if successful, error code otherwise
*/
int cdda_read(fhandle_t* fh, int offset, int count, char* data,
unsigned int* amountRead)
{
int i, fill, trackNum, frames;
bool_t initBuffer = FALSE;
TRACK* trackPtr;
int statptr;
*amountRead = 0;
CDDADBG(fprintf(stderr, "cdda_read(%d, %d, %d)\n", fh->fh_fno, offset, count));
if (readLock) /* block multiple reads from cdrom */
return EBUSY;
else
readLock++;
trackNum = fh->fh_fno - rootfh.fh_fno;
fill = 0; /* fill is the byte-pointer into the file. */
/* handle the info file */
if (trackNum == cdLast+1) {
if ((offset != 0) || (count < KEY_SIZE)) {
fprintf(stderr,"Not handling key file...\n");
readLock = 0;
return EIO;
}
strcpy(data, infoFileString);
*amountRead = strlen(infoFileString);
readLock = 0;
return 0;
}
if (!cd)
cd = CDopen(devName, "r");
if (!cd) {
readLock = 0; /* Busy, but not because of NFS read. */
return (EBUSY);
}
schedctl(NDPRI, 0, NDPHIMAX);
if (offset == 0 && count <= AIFF_HEADER_SIZE) {
fprintf(stderr,"Read smaller than AIFF header size (%d bytes)...\n", count);
readLock = 0;
return EIO;
}
if (offset == 0 || trackNum != trackNumCache ) {
initBuffer = TRUE;
dataSize = mfs_to_bytes(cdInfo[trackNum].total_min,cdInfo[trackNum].total_sec,
cdInfo[trackNum].total_frame);
fileSize = dataSize + AIFF_HEADER_SIZE;
CDseektrack(cd, trackNum);
initialTrackBlock = cd->cur_block;
frameAudioIndex = 0;
/* when the offset is 0 we write an aiff header */
if (offset == 0)
virtual_aiff_header(data, &fill);
else
CDseekblock(cd, initialTrackBlock + offset_to_cdblock((unsigned long)offset,
&frameAudioIndex));
} else if (offset >= fileSize) {
/* The offset overshot the file end */
CDDADBG(fprintf(stderr, "cdda_read: offset(%d) > filesize(%d); returning 0", offset,
fileSize));
*amountRead = 0;
readLock = 0;
return 0;
} else if (offset < bufferMinOffset || offset >= bufferMaxOffset) {
/* The offset came back out of the buffer's range */
initBuffer = TRUE;
CDseekblock(cd, initialTrackBlock + offset_to_cdblock((unsigned long)offset,
&frameAudioIndex));
} else if (offset != offsetCache) {
/* offset is off but still in the buffer */
frameBufferIndex = offset_to_cdblock(offset-bufferMinOffset, &frameAudioIndex) ;
CDDADBG(fprintf(stderr,
"offset is off but still in buffer: offsetCache = %d, offset = %d, bufferMinOffset = %d, bufferMaxOffset = %d\n",
offsetCache, offset, bufferMinOffset, bufferMaxOffset));
}
/*
* FIGURE out where the end of the file is, and adjust count
* accordingly.
*/
count = MIN(count, fileSize - offset);
if (initBuffer) {
CDDADBG(fprintf(stderr,
"initializing CD buffer: offset = %d, bufferMinOffset = %d, bufferMaxOffset = %d\n",
offset, bufferMinOffset, bufferMaxOffset));
bufferMinOffset = bufferMaxOffset = offset;
/* buffer up a mess 'o audio data */
FillCdFrameBuffer();
if (readFrameCount < 0) {
printf("bogus readFrameCount of %d...\n", readFrameCount);
readLock = 0;
return oserror();
}
}
for (; frameBufferIndex < readFrameCount && fill < count;
frameBufferIndex++) {
for (; fill < count && frameAudioIndex < CDDA_DATASIZE; fill += 2, frameAudioIndex += 2) {
data[fill+1] = cdFrameBuffer[frameBufferIndex].audio[frameAudioIndex];
data[fill] = cdFrameBuffer[frameBufferIndex].audio[frameAudioIndex+1];
if ((frameAudioIndex >= CDDA_DATASIZE-2 &&
frameBufferIndex >= readFrameCount-1)
|| (offset + fill >= bufferMaxOffset)) {
/* we ran off the end of the cd buffer */
/* we are empty, fill the buffer synchronously */
FillCdFrameBuffer();
frameBufferIndex = 0;
frameAudioIndex = -2;
if (readFrameCount == 0) /* CDreadda() returned 0. No more frames. */
break;
}
if (offset+fill > bufferMaxOffset)
CDDADBG(fprintf(stderr, "offset + fill %d > bufferMaxOffset %d.\n",
offset+fill, bufferMaxOffset));
}
if (frameAudioIndex == CDDA_DATASIZE)
frameAudioIndex = 0;
}
frameBufferIndex--;
*amountRead = fill;
offsetCache = offset+fill;
trackNumCache = trackNum;
if (offsetCache > bufferMaxOffset)
CDDADBG(fprintf(stderr, "offsetCache %d > bufferMaxOffset %d.\n", offsetCache, bufferMaxOffset));
CDDADBG(fflush(stderr));
schedctl(NDPRI, 0, 0);
readLock = 0;
return 0;
}
/*
* static void
* add_entry(entry *entries, int fd, char *name, int name_len, int cookie)
*
* Description:
* Helper function for cdda_readdir(). Puts fd and name into an entry,
* and sets entries->nextentry to point to the place for the next
* entry.
*
* Parameters:
* entries buffer for entries
* fd file descriptor to add to entries
* name name of file to add to entries
* name_len lengthe of name
* cookie cookie for next entry
*/
static void
add_entry(entry *entries, int fd, char *name, int name_len, int cookie)
{
char *ptr;
entries->fileid = fd;
/*
* We copy the name to the memory immediately following this entry.
* We'll set entries->nextentry to the first byte afterwards that we
* can use, taking alignment into consideration.
*/
entries->name = (char *)(entries + 1);
strncpy(entries->name, name, name_len);
entries->name[name_len] = '\0';
*(int *)entries->cookie = cookie;
entries->nextentry = (entry *)((char *)(entries + 1) + name_len + 1);
ptr = (char *)entries->nextentry;
/*
* Fix alignment problems
*/
if ((int)ptr % 4) {
ptr = ptr + 4 - ((int)ptr % 4);
entries->nextentry = (entry *)ptr;
}
}
/*
* int
* cdda_readdir(fhandle_t *fh, entry *entries, int count, int cookie,
* bool_t *eof, int *nread)
*
* Description:
* Read up to count byes worth of directory entries from the directory
* described by fd
*
* Parameters:
* fh file handle of directory whose entries we want
* entries Buffer to receive entries
* count Maximum # of bytes to read into entries
* cookie offset into directory entry from which to start
* eof set to 1 if we've read the last entrie
* nread set to the number of entries read
*
* Returns:
* 0 if successful, error code otherwise
*/
int cdda_readdir(fhandle_t *fh, entry *entries, int count, int cookie,
bool_t *eof, int *nread)
{
dir_t *dirp, *contents, *dp, *newdirp;
int error, fileid, len, newfd;
char uname[NFS_MAXNAMLEN];
entry *lastentry = 0, *entrybase = entries;
int blksize;
CDDADBG(fprintf(stderr, "cdda_readdir(%d, %d) == \n", fh->fh_fno, cookie));
if (fh->fh_fno != rootfh.fh_fno) { /* this is the only directory we got */
return ENOTDIR;
}
/*
* We do this to clue the nfs_server module into the fact that there
* are no entries left to be read. It turns out that the NFS client
* won't listen to us when we set *eof == 0; the nfs_server module
* has to actually return a NULL entry pointer in order to convince
* the client that there are no more entries.
*/
*nread = 0;
if (cookie == TERM_COOKIE) {
/* closeDsp(cd); */
return 0;
}
blksize = cdda_getblksize();
/* handle "./" */
add_entry(entries, fh->fh_fno, dot, strlen(dot), 0);
lastentry = entries;
*nread = 1;
/*
* Now do the rest
*/
for (; *nread <= cdLast; (*nread)++) {
entries = entries->nextentry;
fileid = rootfh.fh_fno + *nread;
sprintf(uname,"Track%02d.aiff", *nread);
CDDADBG(fprintf(stderr,"readdir of %s\n", uname));
add_entry(entries, fileid, uname, strlen (uname), 0);
lastentry = entries;
}
/* handle "../" and the keyfile */
(*nread)++;
entries = entries->nextentry;
add_entry(entries, fh->fh_fno, dotdot, strlen(dotdot), 0);
lastentry = entries;
(*nread)++;
entries = entries->nextentry;
add_entry(entries, fh->fh_fno, disctrackname, strlen(disctrackname), 0);
lastentry = entries;
*eof = 1;
if (lastentry) {
lastentry->nextentry = 0;
if (*eof) {
*(int *)lastentry->cookie = TERM_COOKIE;
}
}
return 0;
}
/*
* int
* cdda_readraw(unsigned long block, void *buf, unsigned long count)
*
* Description:
* Read raw data from the CD. This is here for debugainging support
* for the testcd test program.
*
* Parameters:
* block block on the CD to read from
* buf memory to read into
* count number of bytes to read
*
* Returns:
* 0 if successful, error code if error
*/
int cdda_readraw(unsigned long offset, void *buf, unsigned long count)
{
/*
* If the test program is trying to read the volume descriptor,
* the block number will be 16, and we should use CDROM_BLKSIZE.
* Otherwise, it's asking for data, and we should use the
* block size we got from the volume descriptor.
*/
/* return cd_read(cd, offset == 16 ? 16 * CDDA_BLOCKSIZE : */
/* offset * cd_getblksize(), buf, count, 0); */
printf("In readraw...\n");
return 0;
}
/*
* void
* cdda_disable_name_translations(void)
*
* Description:
* Make it so we don't muck with the filenames on the CD at all. This
* results in very ugly file names in all caps, sometimes ending with
* a semi-colon and then a number
*/
void cdda_disable_name_translations(void)
{
notranslate = 1;
}
/*
* void
* cdda_setx(void)
*
* Description:
* Make it so we automatically set execute permission on every
* file. This speeds up attribute checking and enables execution
* of files that our algorithm may not give execute permission to.
*/
void cdda_setx(void)
{
setx = 1;
}
/*
* int
* cdda_getfs(char *path, fhandle_t *fh, struct svc_req *rq )
*
* Description:
* Get a file handle given its mount point. Also, if rq is
* non-NULL, perform check to see if path should be exported to
* the requestor represented by rq.
*
* Parameters:
* path Mount point in which we're interested
* fh receives file handle
* rq NFS service request
*
* Returns:
* 0 if successful, error code otherwise
*/
int cdda_getfs(char *path, fhandle_t *fh, struct svc_req *rq)
{
FILE *fp;
struct exportent *xent;
int error;
struct sockaddr_in *sin;
struct hostent *hp;
char *access, **aliases, *host;
/*
* Make sure they're asking about the file system that we've got
* mounted.
*/
if (strcmp(path, mountPoint) != 0) {
return ENOENT;
}
/*
* Check to see if letting the requestor see this file system is
* allowed (someone must run exportfs(1M).
*
* Note: this code is derived from code found in cmd/sun/rpc.mountd.c
*/
fp = setexportent();
if (!fp) {
return EACCES;
}
error = EACCES;
while (error && (xent = getexportent(fp))) {
if (strcmp(path, xent->xent_dirname) == 0) {
sin = svc_getcaller(rq->rq_xprt);
hp = gethostbyaddr(&sin->sin_addr, sizeof sin->sin_addr,
AF_INET);
/*
* Derived from cmd/sun/rpc.mountd.c
*/
access = getexportopt(xent, ACCESS_OPT);
if (!access) {
error = 0;
} else {
while ((host = strtok(access, ":")) != NULL) {
access = NULL;
if (strcasecmp(host, hp->h_name) == 0
|| innetgr(host, hp->h_name, NULL, _yp_domain))
error = 0;
else
for (aliases = hp->h_aliases; *aliases && error;
aliases++)
if (strcasecmp(host, *aliases) == 0
|| innetgr(access, *aliases, NULL,
_yp_domain))
error = 0;
}
}
if (error) {
access = getexportopt(xent, ROOT_OPT);
}
if (access) {
while ((host = strtok(access, ":")) != NULL) {
access = NULL;
if (strcasecmp(host, hp->h_name) == 0)
error = 0;
}
}
if (error) {
access = getexportopt(xent, RW_OPT);
}
if (access) {
while ((host = strtok(access, ":")) != NULL) {
access = NULL;
if (strcasecmp(host, hp->h_name) == 0)
error = 0;
}
}
}
}
endexportent(fp);
if (!error) {
bcopy(&rootfh, fh, sizeof *fh);
}
return error;
}
/*
* int
* cdda_getblksize(void)
*
* Description:
* Get the CD block size for the nfs_server module (which does
* not have access to the cd pointer)
*
* Returns:
* block size of our file system
*/
int cdda_getblksize(void)
{
return CDDA_DATASIZE ;
}
/*
* int
* cdda_getattr(fhandle_t *fh, fattr *fa)
*
* Description:
* Fill in fa with the attributes of fh
*
* Parameters:
* fh file handle whose attributes we want
* fa Buffer to receive attributes
*
* Returns:
* 0 if successful, error code otherwise
*/
int cdda_getattr(fhandle_t* fh, fattr* fa)
{
int blksize, changed;
char* dev;
CDDADBG(fprintf(stderr, "cdda_getattr(%d)...\n", fh->fh_fno));
if (cachedFno == fh->fh_fno) {
memcpy(fa, cachedFattr, sizeof(fattr));
return 0;
}
else {
cachedFno = fh->fh_fno;
}
/* CDtestready(cd, &changed); */
/* if (changed) { */
/* CDDADBG(fprintf(stderr,"CD has changed...\n")); */
/* dev = cd->dev; */
/* if (cd) */
/* CDclose(cd); */
/* cd = CDopen(dev, "r"); */
/* virtual_info_file(infoFileString); */
/* } */
/* Attributes common to both regular files and directories */
fa->blocksize = blksize = cdda_getblksize();
fa->fsid = fh->fh_dev;
fa->fileid = fh->fh_fno;
fa->nlink = 1;
fa->uid = 0;
fa->gid = 0;
/* fa->uid = NFS_UID_NOBODY; */
/* fa->gid = NFS_GID_NOBODY; */
fa->ctime.seconds = fa->ctime.useconds = 0;
fa->atime.useconds = fa->mtime.useconds = 0;
fa->mtime.seconds = fa->atime.seconds = openTime;
if (fh->fh_fno == rootfh.fh_fno) { /* we are THE directory */
fa->blocks = 0;
fa->type = NFDIR;
fa->mode = S_IFDIR | PERM_RXALL;
fa->size = cdLast;
}
else {
fa->type = NFREG;
fa->mode = (setx) ? PERM_RXALL : PERM_RALL;
if (fh->fh_fno == rootfh.fh_fno + cdLast + 1) { /* the info.disc file */
fa->blocks = 1;
fa->size = strlen(infoFileString);
}
else {
int trackNum = fh->fh_fno - rootfh.fh_fno;
/* CDgettrackinfo(cd, fh->fh_fno - ROOT_DIR(), &info); */
fa->blocks = (cdInfo[trackNum].total_frame
+ (75 * cdInfo[trackNum].total_sec)
+ (75 * 60 * cdInfo[trackNum].total_min));
/* total size in bytes */
fa->size = (fa->blocks * CDDA_DATASIZE) + AIFF_HEADER_SIZE;
}
}
memcpy(cachedFattr, fa, sizeof(fattr));
return 0;
}
/*
* int
* cdda_readlink(fhandle_t *fh, char **link)
*
* Description:
* Get the value of a symbolic link from the Rock Ridge
* extensions.
*
* Parameters:
* fh File handle to get link for
* link Gets link value
*
* Returns:
* 0 if successful, errno otherwise.
*/
int
cdda_readlink(fhandle_t *fh, char **link)
{
printf("shouldn't call cdda_readlink...\n");
return ENXIO;
}
/*
* static int
* get_parent_fd(int dir, int *fdp)
*
* Description:
* Get the file descriptor of this directory's parent
*
* Parameters:
* dir File descriptor of directory we want parent of
* fdp receives file descriptor of parent
*
* Returns:
* 0 if successful, error code otherwise
*/
static int get_parent_fd(int dir, int *fdp)
{
*fdp = rootfh.fh_fno;
return 0;
}