📄 rt11fslib.c
字号:
LOCAL RT_FILE_DESC *rt11FsFd; /* pointer to list of file descriptors */LOCAL int rt11FsMaxFiles; /* max RT-11 files that can be open at once */LOCAL SEM_ID rt11FsFdSemId; /* interlock file descriptor list access */LOCAL int rt11FsDay = 0; /* day of month, default is 0 */LOCAL int rt11FsMonth = 0; /* month of year, default is 0 */LOCAL int rt11FsYear = 72; /* year, default is '72 (stored as 0) *//* forward static functions */static STATUS rt11FsClose (RT_FILE_DESC *pFd);static void rt11FsCoalesce (RT_VOL_DESC *vdptr, int entryNum);static RT_FILE_DESC *rt11FsCreate (RT_VOL_DESC *vdptr, char *name, int mode);static int rt11FsDate (int year, int month, int day);static STATUS rt11FsDelete (RT_VOL_DESC *vdptr, char *name);static STATUS rt11FsDirEntry (RT_VOL_DESC *vdptr, REQ_DIR_ENTRY *rdeptr);static STATUS rt11FsDirRead (RT_FILE_DESC *pFd, DIR *pDir);static STATUS rt11FsFileStatGet (RT_FILE_DESC *pFd, struct stat *pStat);static int rt11FsFindEntry (RT_VOL_DESC *vdptr, char *name, int *pstart);static STATUS rt11FsFlush (RT_FILE_DESC *pFd);static void rt11FsFreeFd (RT_FILE_DESC *pFd);static RT_FILE_DESC *rt11FsGetFd (void);static void rt11FsGetEntry (RT_VOL_DESC *vdptr, int entryNum, RT_DIR_ENTRY *pEntry);static void rt11FsInsEntry (RT_VOL_DESC *vdptr, int entryNum, RT_DIR_ENTRY *pEntry);static STATUS rt11FsIoctl (RT_FILE_DESC *pFd, int function, int arg);static void rt11FsNameR50 (char *string, RT_NAME *pName);static int rt11FsR50out (char *string);static void rt11FsNameString (RT_NAME name, char *string);static void rt11FsR50in (unsigned int r50, char *string);static RT_FILE_DESC *rt11FsOpen (RT_VOL_DESC *vdptr, char *name, int mode);static void rt11FsPutEntry (RT_VOL_DESC *vdptr, int entryNum, RT_DIR_ENTRY *pEntry);static int rt11FsRead (RT_FILE_DESC *pFd, char *pBuf, int maxBytes);static STATUS rt11FsRename (RT_FILE_DESC *pFd, char *newName);static STATUS rt11FsSeek (RT_FILE_DESC *pFd, int position);static STATUS rt11FsVolFlush (RT_VOL_DESC *vdptr);static STATUS rt11FsVolInit (RT_VOL_DESC *vdptr);static STATUS rt11FsVolMount (RT_VOL_DESC *vdptr);static int rt11FsWhere (RT_FILE_DESC *pFd);static int rt11FsWrite (RT_FILE_DESC *pFd, char *pBuf, int nbytes);static int rt11FsNewBlock (RT_FILE_DESC *pFd);static STATUS rt11FsRdBlock (RT_VOL_DESC *vdptr, int blockNum, int numBlocks, char *pBuf);static STATUS rt11FsWrtBlock (RT_VOL_DESC *vdptr, int blockNum, int numBlocks, char *pBuf);static int rt11FsAbsSector (ULONG secPerTrack, int sector);static STATUS rt11FsCheckVol (RT_VOL_DESC *vdptr, BOOL doMount);static STATUS rt11FsReset (RT_VOL_DESC *vdptr);static STATUS rt11FsVolMode (RT_VOL_DESC *vdptr);static STATUS rt11FsSqueeze (RT_VOL_DESC *vdptr);/********************************************************************************* rt11FsClose - close an RT-11 file** This routine closes the specified RT-11 file.* The end of the buffer beyond the end of file is cleared out,* the buffer is flushed, and the directory is updated if necessary.** RETURNS:* OK, or* ERROR if directory couldn't be flushed or* entry couldn't be found.*/LOCAL STATUS rt11FsClose ( FAST RT_FILE_DESC *pFd /* file descriptor pointer */ ) { FAST RT_DIR_ENTRY *pEntry = &pFd->rfd_dir_entry; FAST int remaining_blocks; FAST int nblocks; int buf_index; STATUS status; char name[RT_NAME_LEN]; /* file name gets unpacked into here */ int entryNum; /* file's entry number in directory */ int start; /* for receiving rt11FsFindEntry side-effect */ /* if current buffer has been written to and contains end of file, * clear out end of buffer that lies beyond end of file. */ if (pFd->rfd_modified && ((pFd->rfd_curptr / RT_BYTES_PER_BLOCK) == (pFd->rfd_endptr / RT_BYTES_PER_BLOCK))) { buf_index = pFd->rfd_endptr - pFd->rfd_curptr; bzero (&pFd->rfd_buffer[buf_index], RT_BYTES_PER_BLOCK - buf_index); } status = rt11FsFlush (pFd); /* if file is new, update directory */ if (pEntry->de_status == DES_TENTATIVE) { /* update directory entry to be permanent with actual size */ nblocks = ((pFd->rfd_endptr - 1) / RT_BYTES_PER_BLOCK) + 1; remaining_blocks = pEntry->de_nblocks - nblocks; pEntry->de_status = DES_PERMANENT; pEntry->de_nblocks = nblocks; semTake (pFd->rfd_vdptr->vd_semId, WAIT_FOREVER); /* unpack name and find entry number */ rt11FsNameString (pFd->rfd_dir_entry.de_name, name); entryNum = rt11FsFindEntry (pFd->rfd_vdptr, name, &start); if (entryNum == ERROR) status = ERROR; else { rt11FsPutEntry (pFd->rfd_vdptr, entryNum, pEntry); /* if unused blocks are left over, insert EMPTY entry in directory*/ if (remaining_blocks != 0) { pEntry->de_status = DES_EMPTY; pEntry->de_nblocks = remaining_blocks; rt11FsInsEntry (pFd->rfd_vdptr, entryNum + 1, pEntry); rt11FsCoalesce (pFd->rfd_vdptr, entryNum + 1); } /* make sure directory is written out */ if (rt11FsVolFlush (pFd->rfd_vdptr) != OK) status = ERROR; } semGive (pFd->rfd_vdptr->vd_semId); /* release volume */ } rt11FsFreeFd (pFd); /* mark fd not in use */ return (status); }/********************************************************************************* rt11FsCoalesce - merge empty directory entries** This routine merges a directory entry with its empty neighbors, if any.* It stops when there are no more empty neighbors, or when adding* another empty file would cause it to have more than RT_MAX_BLOCKS_PER_FILE* blocks in an empty file.* The directory will be updated.** Possession of the volume descriptor's semaphore must have been secured* before this routine is called.*/LOCAL void rt11FsCoalesce ( RT_VOL_DESC *vdptr, /* pointer to volume descriptor */ int entryNum /* number of empty entry to coalesce */ ) { RT_DIR_ENTRY entry; /* 1st of 1-3 empty directory entries */ RT_DIR_ENTRY nentry; /* next entry */ int n = 0; /* number of entries to merge into first */ rt11FsGetEntry (vdptr, --entryNum, &entry); if ((entryNum < 0) || (entry.de_status != DES_EMPTY)) rt11FsGetEntry (vdptr, ++entryNum, &entry); rt11FsGetEntry (vdptr, entryNum + 1, &nentry); /* get next entry */ /* start coalescing -- don't coalesce 2 files if the new file would have more than RT_MAX_BLOCKS_PER_FILE */ while (nentry.de_status == DES_EMPTY) { if ((entry.de_nblocks + nentry.de_nblocks) > RT_MAX_BLOCKS_PER_FILE) { /* These two files can't be merged. The new file would be too big */ if (n > 0) /* don't change entry ptr w.o. coalescing */ break; else { /* Can't coalesce current empty entry. Point to next one */ entryNum++; entry = nentry; } } else { entry.de_nblocks += nentry.de_nblocks; /* seize empty blocks */ ++n; } rt11FsGetEntry (vdptr, entryNum + 1 + n, &nentry);/* get next entry */ } if (n > 0) /* any entries coalesced? */ { rt11FsPutEntry (vdptr, entryNum, &entry); /* put empty entry */ rt11FsPutEntry (vdptr, ++entryNum, &nentry); /* put nonempty entry */ /* move rest of entries up by n places */ while (nentry.de_status != DES_END) { rt11FsGetEntry (vdptr, ++entryNum + n, &nentry); rt11FsPutEntry (vdptr, entryNum, &nentry); } } }/********************************************************************************* rt11FsCreate - create an RT-11 file** This routine creates the file <name> with the specified <mode>.* If the file already exists, it is first deleted then recreated.* The largest empty space on the device is allocated to the new file.* Excess space will be recovered when the file is closed.* An RT-11 file descriptor is initialized for the file.** A file <name> of zero length (i.e., "" is used to open an entire "raw" disk).* In this case, no attempt is made to access the disk's directory, so that* even un-initialized disks may be accessed.** RETURNS* Pointer to RT-11 file descriptor, or* ERROR if error in create.*/LOCAL RT_FILE_DESC *rt11FsCreate ( RT_VOL_DESC *vdptr, /* pointer to volume descriptor */ char *name, /* RT-11 string (ffffff.ttt) */ int mode /* file mode (O_RDONLY/O_WRONLY/O_RDWR) */ ) { RT_DIR_ENTRY entry; int start; FAST int e_num; RT_DIR_ENTRY max_entry; int max_start = 0; /* used only if max_e_num != NONE */ int max_e_num; /* maximum entry number */ FAST int nEntries; /* number of entries that will fit in segment */ FAST RT_FILE_DESC *pFd; /* file descriptor pointer */ /* Call driver check-status routine, if any */ if (vdptr->vd_pBlkDev->bd_statusChk != NULL) { if ((* vdptr->vd_pBlkDev->bd_statusChk) (vdptr->vd_pBlkDev) != OK) { return ((RT_FILE_DESC *) ERROR); } } /* Set up for re-mount if no disk change notification */ if (vdptr->vd_changeNoWarn == TRUE) rt11FsReadyChange (vdptr); pFd = rt11FsGetFd (); /* get file descriptor */ if (pFd == NULL) return ((RT_FILE_DESC *) ERROR); /* no free file descriptors */ nEntries = (vdptr->vd_nSegBlocks * RT_BYTES_PER_BLOCK - (sizeof (RT_DIR_SEG) - sizeof (RT_DIR_ENTRY))) / sizeof (RT_DIR_ENTRY); /* check for create of raw device (null filename) */ if (name [0] == EOS) { /* check that volume is available */ semTake (vdptr->vd_semId, WAIT_FOREVER); if (rt11FsCheckVol (vdptr, FALSE) != OK) { semGive (vdptr->vd_semId); rt11FsFreeFd (pFd); errnoSet (S_rt11FsLib_VOLUME_NOT_AVAILABLE); return ((RT_FILE_DESC *) ERROR); } /* disk must be writable to create file */ if (rt11FsVolMode (vdptr) == O_RDONLY) { semGive (vdptr->vd_semId); rt11FsFreeFd (pFd); errnoSet (S_ioLib_WRITE_PROTECTED); return ((RT_FILE_DESC *) ERROR); } semGive (vdptr->vd_semId); /* null name is special indicator for "raw" disk; * fabricate a bogus directory entry covering entire volume */ pFd->rfd_dir_entry.de_status = DES_BOGUS; pFd->rfd_dir_entry.de_date = rt11FsDate (rt11FsYear, rt11FsMonth, rt11FsDay); pFd->rfd_dir_entry.de_nblocks = vdptr->vd_nblocks; rt11FsNameR50 ("device.raw", &pFd->rfd_dir_entry.de_name); pFd->rfd_start = 0; pFd->rfd_endptr = vdptr->vd_nblocks * RT_BYTES_PER_BLOCK; } else { /* Ignore any leading "/" or "\"'s in file name */ while ((*name == '/') || (*name == '\\')) name++; /* first delete any existing file with the specified name */ (void) rt11FsDelete (vdptr, name); /* check that volume is available */ semTake (vdptr->vd_semId, WAIT_FOREVER); if ((rt11FsCheckVol (vdptr, TRUE) != OK) || (vdptr->vd_status != OK)) { semGive (vdptr->vd_semId); /* release volume */ rt11FsFreeFd (pFd); errnoSet (S_rt11FsLib_VOLUME_NOT_AVAILABLE); return ((RT_FILE_DESC *) ERROR); } /* disk must be writable to create file */ if (rt11FsVolMode (vdptr) == O_RDONLY) { semGive (vdptr->vd_semId); /* release volume */ rt11FsFreeFd (pFd); errnoSet (S_ioLib_WRITE_PROTECTED); return ((RT_FILE_DESC *) ERROR); } /* search entire directory for largest empty entry. * keep track of start block by accumulating entry lengths. */ start = vdptr->vd_dir_seg->ds_start; max_e_num = NONE; for (e_num = 0; e_num < nEntries; e_num++) { rt11FsGetEntry (vdptr, e_num, &entry); /* if this is the end of the directory, then quit. */ if (entry.de_status == DES_END) break; /* check if create already in progress */ if (entry.de_status == DES_TENTATIVE) { semGive (vdptr->vd_semId); /* release volume */ rt11FsFreeFd (pFd); errnoSet (S_rt11FsLib_NO_MORE_FILES_ALLOWED_ON_DISK); return ((RT_FILE_DESC *) ERROR); } /* check if this is largest empty file so far */ if ((entry.de_status == DES_EMPTY) && ((max_e_num == NONE) || (entry.de_nblocks > max_entry.de_nblocks))) { max_e_num = e_num; max_entry = entry; max_start = start; } /* add file length to get start of next file */ start += entry.de_nblocks; } /* check for running out of room for file entries * (the last entry is a terminating entry) */ if (e_num >= nEntries - 1) { semGive (vdptr->vd_semId); /* release volume */ rt11FsFreeFd (pFd); errnoSet (S_rt11FsLib_NO_MORE_FILES_ALLOWED_ON_DISK); return ((RT_FILE_DESC *) ERROR); } /* check for no empty holes found */ if (max_e_num == NONE) { semGive (vdptr->vd_semId); /* release volume */ rt11FsFreeFd (pFd); errnoSet (S_rt11FsLib_DISK_FULL); return ((RT_FILE_DESC *) ERROR); } /* found an empty hole; initialize entry */ max_entry.de_status = DES_TENTATIVE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -