/// <summary> /// 流写入 /// </summary> /// <param name="cin">待写入的流</param> /// <param name="position">写入起始位置</param> /// <param name="count">需写入的数量</param> protected void WriteStream(byte[] cin, int itemNum, int count, InodeStr dinode) { int pos = _dire.BMap(dinode, itemNum / 512); _diskFile.OpenFile(); _diskFile.SeekFilePosition(pos * 512 + itemNum % 512, System.IO.SeekOrigin.Begin); _diskFile.WriteFile(ref cin, 0, count); _diskFile.CloseFile(); }
/// <summary> /// 构造函数 /// </summary> /// <param name="tsb"></param> /// <param name="tid"></param> /// <param name="tdb"></param> /// <param name="diskInfo"></param> /// <param name="createFilePath"></param> public File(Superblock tsb, InodeBlock tid, DataBlock tdb, Disk diskInfo, string createFilePath) { _superBlock = tsb; _inodeblock = tid; _dataBlock = tdb; _diskFile = diskInfo; _dire = new Directary(tsb, tid, tdb, diskInfo); _fileInode = new InodeStr(); _dirInode = new InodeStr(); _createFilePath = createFilePath; }
/// <summary> /// 写入目录项 /// </summary> protected void WriteDirItem(InodeStr dirInode) { byte[] inodeNo; byte[] cin = new byte[32]; inodeNo = Helper.Struct2Bytes(_fileInodeNo); for (int i = 0; i < 4; ++i) { cin[i] = inodeNo[i]; } //此处的FileName由之前的namei中得来,指的是文件的绝对名,不带路径 for (int i = 0; i < 28; ++i) { cin[i + 4] = Convert.ToByte(_fileName[i]); } WriteStream(cin, _blankDirItem, 32, dirInode); }
/// <summary> /// 创建文件时的目录搜索 /// 本函数共4个出口 /// 出口1:目录搜索完毕,且满足三个条件:1.之前各级目录名都能找到,2.但没有符合的最后一级文件,3.且传入的flag为CREATFILE /// 出口2:目录搜索完毕,但不完全满足上述三个条件 /// 出口3:文件(或目录)在系统中已存在,且传入flag为DELETEFILE /// 出口4:文件(或目录)在系统中已存在,但传入flag不为DELETEFILE /// </summary> /// <param name="path">创建文件的目录</param> /// <param name="DirInodeNo">父目录的inode号</param> /// <returns>目录项的位置</returns> public int NameI(string path, ref int dirInodeNo, ref InodeStr dirInode, ref int fileInodeNo, ref InodeStr fileInode, ref char[] fileName, int flag) { //用于记录在路径字符串中扫描到了哪里 int curPos = 0; //用于记录inode号 dirInodeNo = 0; //首先读入根目录inode _inode.GetInodeFromDisk(dirInode, dirInodeNo); //跳过开始的一个(或者多个)'/'字符 for (; curPos < path.Length; ++curPos) { if (path[curPos] != '/') { break; } } //主循环 while (true) { //获取两个'/'当中的内容,存入dirPath中 char[] tmp = new char[28]; for (int i = 0; curPos < path.Length; ++curPos, ++i) { if (path[curPos] == '/') { break; } tmp[i] = path[curPos]; } tmp.CopyTo(fileName, 0); //跳过下一个(或者多个)'/'字符,为下一次循环(下一级目录,如果有的话)做准备 for (; curPos < path.Length; ++curPos) { if (path[curPos] != '/') { break; } } //用于存储扫描当前目录文件的偏移量 int offset = 0; //用于记录第一个空闲目录项的偏移量 int firstFreeOffset = 0; //记录是否又空闲目录项 int freeFlag = 0; //目录项项数 int dirSize = dirInode._i_size / 32; //用于读取一个磁盘块 byte[] buffer = new byte[512]; //(次循环)在当前目录文件中搜索 while (true) { //出口1:对当前目录搜索完毕(用于查找是否有同名文件存在) if (dirSize == 0) { //若当前目录索搜索完毕(没有找到相应项),且只是路径名的最后一段没有找到(要创建的文件名),则创建文件 if (flag == File.CREATFILE && curPos == path.Length) { //新分配一个inode控制块,返回该inode号 try { fileInodeNo = _inode.FetchFreeInode(); } catch (Exception ex) { Console.WriteLine(ex.Message); } //根据inode号获取对应的inode(搜索到了哪一层就获取哪一层目录的inode) _inode.GetInodeFromDisk(fileInode, fileInodeNo); //若之前扫描途中有空闲项,则返回其偏移,否则就返回当前inode的大小(即要对当前inode进行扩充) if (freeFlag == 0) { return(dirInode._i_size); } else { return(firstFreeOffset); } } //出口2:若当前目录搜索完毕(没有找到相应项),且中间路径没有找到,则出错 else { Error.ErrorType = Error.SEARCHDIR; return(-1); } } //搜索完一块,需要读入新块 if (offset % 512 == 0) { _diskFile.OpenFile(); _diskFile.SeekFilePosition(this.BMap(dirInode, offset / 512) * 512, System.IO.SeekOrigin.Begin); _diskFile.ReadFile(ref buffer, 0, 512); _diskFile.CloseFile(); } bool match = true; for (int j = 0; j < 28; ++j) { if (Convert.ToByte(fileName[j]) != buffer[offset % 512 + j + 4]) { match = false; break; } } //表示不匹配 if (!match) { dirSize--; //如果之前的目录项为空,则将其用first_free_offset标记 //+4是因为每个目录项的前四个字节是inode号 if (buffer[offset % 512 + 4] == '\0' && firstFreeOffset == 0) { firstFreeOffset = offset; freeFlag = 1; } offset += 32; continue; } //在当前目录中找到了和dirPath匹配的目录项 else { break; } } byte[] ino = new byte[4]; for (int k = 0; k < 4; ++k) { ino[k] = buffer[offset % 512 + k]; } /* 出口3: * 删除操作 * pathPoint == path.Length表示:目录项已经搜索完毕*/ if (flag == File.DELETEFILE && curPos == path.Length) { //需删除文件的inode号 fileInodeNo = (int)Helper.Bytes2Struct(ino, typeof(int)); return(offset); } /* 出口4: * 同一目录下的文件名相同,且不是要做删除操作,则出错 * pathPoint == path.Length表示:目录项已经搜索完毕*/ if (flag != File.DELETEFILE && curPos == path.Length) { Error.ErrorType = Error.SAMEFILENAME; return(-1); } //如果还有下级目录,则更新dirInodeNo与dirInode,为当前目录 dirInodeNo = (int)Helper.Bytes2Struct(ino, typeof(int)); _inode.GetInodeFromDisk(dirInode, dirInodeNo); } }
/// <summary> /// 虚实地址转换 /// </summary>\ /// /// <param name="DirInode"></param> /// <param name="no"></param> /// <returns></returns> public int BMap(InodeStr dirInode, int itemNum) { int blockNum; byte[] blockNumBuf = new byte[4]; //直接索引0~5项,一次间接索引6~7项,二次间接索引8~9项 //直接索引所引用的逻辑块号为0~5块,一次间接引用索引项6~261块 //二次间接引用索引项128*2+6~128*128*2+128*2+6-1项 //直接索引 if (itemNum < 6) { blockNum = dirInode._i_addr[itemNum]; //如果该逻辑块还没有相应的物理块与之对应,则分配一个物理块 if (blockNum == 0) { try { blockNum = _dataBlock.GetFreeBlock(); } catch (Exception ex) { Console.WriteLine(ex.Message); } dirInode._i_addr[itemNum] = blockNum; } return(blockNum); } //间接引用bn>=6 else { int firstIndex; //一次间接块 if (itemNum - 262 < 0) { firstIndex = ((itemNum - 6) / 128) + 6; //6或7 } else //二次间接块 { firstIndex = ((itemNum - 262) / (128 * 128)) + 8; //8或9 } //该项为空,则到数据区分配一块空闲块 if (dirInode._i_addr[firstIndex] == 0) { try { dirInode._i_addr[firstIndex] = _dataBlock.GetFreeBlock(); } catch (Exception ex) { Console.WriteLine(ex.Message); } } blockNum = dirInode._i_addr[firstIndex]; //如果是二次间接索引,则再获取二级索引块的块号 if (firstIndex >= 8) { int secondIndex = ((itemNum - 262) / 128) % 128; //0-128 _diskFile.OpenFile(); _diskFile.SeekFilePosition(dirInode._i_addr[firstIndex] * 512 + secondIndex * 4, System.IO.SeekOrigin.Begin); _diskFile.ReadFile(ref blockNumBuf, 0, 4); _diskFile.CloseFile(); blockNum = (int)Helper.Bytes2Struct(blockNumBuf, typeof(int)); if (blockNum == 0) { try { blockNum = _dataBlock.GetFreeBlock(); } catch (Exception ex) { Console.WriteLine(ex.Message); } blockNumBuf = Helper.Struct2Bytes(blockNum); _diskFile.OpenFile(); _diskFile.SeekFilePosition(dirInode._i_addr[firstIndex] * 512 + secondIndex * 4, System.IO.SeekOrigin.Begin); _diskFile.WriteFile(ref blockNumBuf, 0, 4); _diskFile.CloseFile(); } } } int directIndex; //一次间接块 if (itemNum - 262 < 0) { directIndex = ((itemNum - 6) % 128); } else //二次间接块 { directIndex = ((itemNum - 262) % 128); } _diskFile.OpenFile(); _diskFile.SeekFilePosition(512 * blockNum + 4 * directIndex, System.IO.SeekOrigin.Begin); _diskFile.ReadFile(ref blockNumBuf, 0, 4); _diskFile.CloseFile(); int tmpBlockNum = (int)Helper.Bytes2Struct(blockNumBuf, typeof(int)); //若该目录索引项为空,则分配 if (tmpBlockNum == 0) { try { tmpBlockNum = _dataBlock.GetFreeBlock(); } catch (Exception ex) { Console.WriteLine(ex.Message); } blockNumBuf = Helper.Struct2Bytes(tmpBlockNum); _diskFile.OpenFile(); _diskFile.SeekFilePosition(512 * blockNum + 4 * directIndex, System.IO.SeekOrigin.Begin); _diskFile.WriteFile(ref blockNumBuf, 0, 4); _diskFile.CloseFile(); } blockNum = tmpBlockNum; return(blockNum); }