📄 rt11fslib.c
字号:
max_entry.de_date = rt11FsDate (rt11FsYear, rt11FsMonth, rt11FsDay); rt11FsNameR50 (name, &max_entry.de_name); rt11FsPutEntry (vdptr, max_e_num, &max_entry); (void) rt11FsVolFlush (vdptr); semGive (vdptr->vd_semId); /* release volume */ pFd->rfd_dir_entry = max_entry; pFd->rfd_start = max_start; pFd->rfd_endptr = 0; } /* initialize rest of file descriptor */ pFd->rfd_mode = mode; pFd->rfd_vdptr = vdptr; pFd->rfd_curptr = NONE; pFd->rfd_newptr = 0; pFd->rfd_modified = FALSE; return (pFd); }/********************************************************************************* rt11FsDate - generate RT-11 encoded date** This routine encodes the specified date into RT-1 format.** RETURNS: Encoded date.*/LOCAL int rt11FsDate ( int year, /* 72, or 72...03 */ int month, /* 0, or 1...12 */ int day /* 0, or 1...31 */ ) { if ((year -= 72) < 0) year += 100; return ((month << 10) | (day << 5) | (year & 0x1f)); }/********************************************************************************* rt11FsDelete - delete RT-11 file** This routine deletes the file <name> from the specified RT-11 volume.** RETURNS:* OK, or* ERROR if file not found or volume not available.**/LOCAL STATUS rt11FsDelete ( RT_VOL_DESC *vdptr, /* pointer to volume descriptor */ char *name /* RT-11 filename (ffffff.ttt) */ ) { int entryNum; int start; RT_DIR_ENTRY entry; /* Set up for re-mount if no disk change notification */ if (vdptr->vd_changeNoWarn == TRUE) rt11FsReadyChange (vdptr); semTake (vdptr->vd_semId, WAIT_FOREVER); /* check that volume is available */ if ((rt11FsCheckVol (vdptr, TRUE) != OK) || (vdptr->vd_status != OK)) { semGive (vdptr->vd_semId); errnoSet (S_rt11FsLib_VOLUME_NOT_AVAILABLE); return (ERROR); } if (rt11FsVolMode (vdptr) == O_RDONLY) { semGive (vdptr->vd_semId); errnoSet (S_ioLib_WRITE_PROTECTED); return (ERROR); } /* search for entry with specified name */ if ((entryNum = rt11FsFindEntry (vdptr, name, &start)) == ERROR) { semGive (vdptr->vd_semId); /* release volume */ return (ERROR); } rt11FsGetEntry (vdptr, entryNum, &entry); entry.de_status = DES_EMPTY; entry.de_date = 0; rt11FsPutEntry (vdptr, entryNum, &entry); rt11FsCoalesce (vdptr, entryNum); /* merge with empty neighbors */ /* make sure directory is written out */ if (rt11FsVolFlush (vdptr) != OK) { semGive (vdptr->vd_semId); /* release volume */ return (ERROR); } semGive (vdptr->vd_semId); /* release volume */ return (OK); }/********************************************************************************* rt11FsDevInit - initialize the rt11Fs device descriptor** This routine initializes the device descriptor. The <pBlkDev> parameter is* a pointer to an already-created BLK_DEV device structure. This structure* contains definitions for various aspects of the physical device format,* as well as pointers to the sector read, sector write, ioctl(), status check,* and reset functions for the device.** The <rt11Fmt> parameter is TRUE if the device is to be accessed using* standard RT-11 skew and interleave.** The device directory will consist of one segment able to contain at* least as many files as specified by <nEntries>.* If <nEntries> is equal to RT_FILES_FOR_2_BLOCK_SEG, strict RT-11* compatibility is maintained.** The <changeNoWarn> parameter is TRUE if the disk may be changed without* announcing the change via rt11FsReadyChange(). Setting <changeNoWarn> to* TRUE causes the disk to be regularly remounted, in case it has been* changed. This results in a significant performance penalty.** NOTE* An ERROR is returned if <rt11Fmt> is TRUE and the `bd_blksPerTrack'* (sectors per track) field in the BLK_DEV structure is odd.* This is because an odd number of sectors per track is incompatible with the* RT-11 interleaving algorithm.** INTERNAL* The semaphore in the device is given, so the device is available for* use immediately.** RETURNS:* A pointer to the volume descriptor (RT_VOL_DESC), or* NULL if invalid device parameters were specified,* or the routine runs out of memory.*/RT_VOL_DESC *rt11FsDevInit ( char *devName, /* device name */ FAST BLK_DEV *pBlkDev, /* pointer to block device info */ BOOL rt11Fmt, /* TRUE if RT-11 skew & interleave */ FAST int nEntries, /* no. of dir entries incl term entry */ BOOL changeNoWarn /* TRUE if no disk change warning */ ) { FAST RT_VOL_DESC *vdptr; /* pointer to volume descriptor */ FAST int segmentLen; /* segment length in bytes */ FAST int i; /* Return error if no BLK_DEV */ if (pBlkDev == NULL) { errnoSet (S_rt11FsLib_NO_BLOCK_DEVICE); return (NULL); } /* Don't allow odd number of sectors/track if RT-11 interleave specified */ if (rt11Fmt && (pBlkDev->bd_blksPerTrack & 1)) { errnoSet (S_rt11FsLib_INVALID_DEVICE_PARAMETERS); return (NULL); } /* Allocate an RT-11 volume descriptor for device */ if ((vdptr = (RT_VOL_DESC *) calloc (sizeof (RT_VOL_DESC), 1)) == NULL) return (NULL); /* no memory */ /* Add device to system device table */ if (iosDevAdd ((DEV_HDR *) vdptr, devName, rt11FsDrvNum) != OK) { free ((char *) vdptr); return (NULL); /* can't add device */ } /* Initialize volume descriptor */ vdptr->vd_pBlkDev = pBlkDev; vdptr->vd_rtFmt = rt11Fmt; vdptr->vd_status = OK; vdptr->vd_state = RT_VD_READY_CHANGED; vdptr->vd_secBlock = RT_BYTES_PER_BLOCK / pBlkDev->bd_bytesPerBlk; vdptr->vd_nblocks = pBlkDev->bd_nBlocks / vdptr->vd_secBlock; /* Set flag for disk change without warning (removable disks only) */ if (pBlkDev->bd_removable) /* if removable device */ vdptr->vd_changeNoWarn = changeNoWarn; /* get user's flag */ else vdptr->vd_changeNoWarn = FALSE; /* always FALSE for fixed disk*/ /* how many bytes of space are needed for the segment? */ segmentLen = sizeof (RT_DIR_SEG) + (nEntries - 1) * sizeof (RT_DIR_ENTRY); /* Allocate blocks for the segment. * The smallest segment is 2 blocks long */ if ((i = 1 + (segmentLen / RT_BYTES_PER_BLOCK)) < 2) vdptr->vd_nSegBlocks = 2; else vdptr->vd_nSegBlocks = i; /* allocate segment blocks */ vdptr->vd_dir_seg = (RT_DIR_SEG *) malloc ((unsigned) (vdptr->vd_nSegBlocks * RT_BYTES_PER_BLOCK)); if (vdptr->vd_dir_seg == NULL) return (NULL); vdptr->vd_semId = semMCreate (rt11FsVolMutexOptions); if (vdptr->vd_semId == NULL) return (NULL); /* could not create semaphore */ return (vdptr); }/********************************************************************************* rt11FsDirEntry - get info from a directory entry** This routine returns information about a particular directory entry into* the REQ_DIR_ENTRY structure whose pointer is passed as a parameter.* The information put there is the name of the file, its size (in bytes),* and its creation date. If the specified entry is an empty (keeps* track of empty space on the disk), the name will be an empty string,* the size will be correct, and the date will be meaningless.** Before this routine is called, the field `entryNum' must set in* the REQ_DIR_ENTRY structure pointed to by rdeptr. That is the entry* whose information will be returned. Typically, the entries are accessed* sequentially starting with 0 until the terminating entry is reached* (indicated by a return code of ERROR).** RETURNS:* OK, or* ERROR if no such entry.*/LOCAL STATUS rt11FsDirEntry ( RT_VOL_DESC *vdptr, /* pointer to volume descriptor */ REQ_DIR_ENTRY *rdeptr /* ptr to structure into which to put info */ ) { RT_DIR_ENTRY *deptr; /* pointer to directory entry in question */ FAST int maxEntries; /* max number of entries allowed in directory */ /* Set up for re-mount if no disk change notification */ if (vdptr->vd_changeNoWarn == TRUE) rt11FsReadyChange (vdptr); semTake (vdptr->vd_semId, WAIT_FOREVER); if (rt11FsCheckVol (vdptr, TRUE) != OK) { semGive (vdptr->vd_semId); errnoSet (S_rt11FsLib_VOLUME_NOT_AVAILABLE); return (ERROR); } /* what is the maximum number of entries allowed in this directory? */ maxEntries = (vdptr->vd_nSegBlocks * RT_BYTES_PER_BLOCK - (sizeof (RT_DIR_SEG) - sizeof (RT_DIR_ENTRY))) / sizeof (RT_DIR_ENTRY); if (rdeptr->entryNum >= maxEntries) { semGive (vdptr->vd_semId); errnoSet (S_rt11FsLib_ENTRY_NUMBER_TOO_BIG); return (ERROR); } deptr = &(vdptr->vd_dir_seg->ds_entries[rdeptr->entryNum]); switch (deptr->de_status) { case DES_TENTATIVE: /* - should indicate tentative somehow? */ case DES_PERMANENT: rt11FsNameString (deptr->de_name, rdeptr->name); break; case DES_EMPTY: rdeptr->name[0] = EOS; /* empty, no name */ break; default: semGive (vdptr->vd_semId); /* release volume */ errnoSet (S_rt11FsLib_FILE_NOT_FOUND); return (ERROR); /* no such entry */ } rdeptr->nChars = deptr->de_nblocks * RT_BYTES_PER_BLOCK; rdeptr->day = (deptr->de_date >> 5) & 0x001f; rdeptr->month = (deptr->de_date >> 10) & 0x000f; rdeptr->year = (deptr->de_date & 0x001f) + 1972; semGive (vdptr->vd_semId); /* release volume */ return (OK); }/********************************************************************************* rt11FsDirRead - read directory and return next file name** This routine support POSIX directory searches. The directory is read,* and the name of the next file is returned in a "dirent" structure.* This routine is called via an ioctl() call with a function code of* FIOREADDIR.** RETURNS: OK, or ERROR if end of dir (errno = OK) or real error (errno set).*/LOCAL STATUS rt11FsDirRead ( FAST RT_FILE_DESC *pFd, /* ptr to RT-11 file descriptor */ FAST DIR *pDir /* ptr to directory descriptor */ ) { FAST int entryNum; /* position within dir */ FAST int maxEntries; /* number of entries in dir */ FAST char *pChar; /* ptr to char in filename string */ int nameLen; /* length of filename string */ FAST RT_DIR_ENTRY *pEntry; /* ptr to directory entry in memory */ FAST RT_VOL_DESC *vdptr = pFd->rfd_vdptr; /* ptr to volume descriptor */ semTake (vdptr->vd_semId, WAIT_FOREVER); if (rt11FsCheckVol (vdptr, TRUE) != OK) { semGive (vdptr->vd_semId); errnoSet (S_rt11FsLib_VOLUME_NOT_AVAILABLE); return (ERROR); } /* Check if cookie (entry number) is past end of directory */ entryNum = pDir->dd_cookie; /* get marker from DIR */ maxEntries = (vdptr->vd_nSegBlocks * RT_BYTES_PER_BLOCK - (sizeof (RT_DIR_SEG) - sizeof (RT_DIR_ENTRY))) / sizeof (RT_DIR_ENTRY); /* Read an entry, keep going if empty */ do { if (entryNum >= maxEntries) { semGive (vdptr->vd_semId); return (ERROR); /* end of directory */ } pEntry = &(vdptr->vd_dir_seg->ds_entries[entryNum]); /* find entry within dir */ if (pEntry->de_status == DES_END) { semGive (vdptr->vd_semId); return (ERROR); /* end of directory */ } entryNum++; } while (pEntry->de_status == DES_EMPTY); /* Copy name to dirent struct */ rt11FsNameString (pEntry->de_name, pDir->dd_dirent.d_name); /* Cancel trailing blanks or "." */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -