/* * Note. 根據一個block號可以計算出他所表示的地址來,這就行了。 */ #ifndef _SIMULFS_OBJECTS_H_ #define _SIMULFS_OBJECTS_H_ #include "simulfs_marcos.h" typedef struct _simulfs_Dev { __u32 devId:4; int devTags; // 僅僅是一個標記而已,有待擴充,可以用配置文件擴充,其實就是一塊內存 simulfs_Block* blockChain; // 該設備中所有的block隊列 simulfs_CheckPoint dev_cp; }simulfs_Dev; typedef struct _simulfs_Block { __u32 devId:4; __u32 blockId:16; // 塊號 simulfs_BlockState currentState; // 塊當前狀態 __u32 nextChunkId:12; // 塊內當前可以分配的頁號 simulfs_Chunk* chunkChain; // 該block中所有chunk的鏈表s } simulfs_Block; typedef struct _simulfs_Chunk { __u32 devId:4; __u32 blockId:16; // 所屬塊號 __u32 chunkId:12; // 頁號 /* 下面幾個屬性是在上層中被改寫的 */ __u32 objectId:10; // 該頁內存儲的對象號 __u32 chunIdinObj:12; // 該chunk在對象內的表示 __u32 offset:10; // 該頁共存儲了多少比特,這個很重要,不論是那個chunk在文件中,只要偏移是0,就表示這個塊已經不用了 // 所以一般應該先檢查偏移 __u8 isDirty:1; // 是否是髒頁?需要回寫 __u8 needEarse:1; // 是否是新頁?一點東西都沒有 __u32 lowestLevelWriteNextChunk:12; // 底層寫的時候下一個分配的塊,沒有下一個的時候就是 // }simulfs_Chunk; typedef enum _simulfs_ECCResult { SIMULFS_ECC_RESULT_UNKNOWN, SIMULFS_ECC_RESULT_NO_ERROR, SIMULFS_ECC_RESULT_FIXED, SIMULFS_ECC_RESULT_UNFIXED } simulfs_ECCResult; typedef enum _simulfs_ObjectType { SIMULFS_OBJECT_TYPE_UNKNOWN, SIMULFS_OBJECT_TYPE_FILE, SIMULFS_OBJECT_TYPE_SYMLINK, SIMULFS_OBJECT_TYPE_DIRECTORY, SIMULFS_OBJECT_TYPE_HARDLINK, SIMULFS_OBJECT_TYPE_SPECIAL } simulfs_ObjectType; /* * 塊狀態有個狀態轉換圖,可以借鑑一下 */ typedef enum _simulfs_BlockState { SIMULFS_BLOCK_STATE_UNKNOWN = 0, SIMULFS_BLOCK_STATE_SCANNING, SIMULFS_BLOCK_STATE_NEEDS_SCANNING, /* The block might have something on it (ie it is allocating or full, perhaps empty) * but it needs to be scanned to determine its true state. * This state is only valid during yaffs_Scan. * NB We tolerate empty because the pre-scanner might be incapable of deciding * However, if this state is returned on a YAFFS2 device, then we expect a sequence number */ SIMULFS_BLOCK_STATE_EMPTY, /* This block is empty */ SIMULFS_BLOCK_STATE_ALLOCATING, /* This block is partially allocated. * At least one page holds valid data. * This is the one currently being used for page * allocation. Should never be more than one of these */ SIMULFS_BLOCK_STATE_FULL, /* All the pages in this block have been allocated. */ SIMULFS_BLOCK_STATE_DIRTY, /* All pages have been allocated and deleted. * Erase me, reuse me. */ SIMULFS_BLOCK_STATE_CHECKPOINT, /* This block is assigned to holding checkpoint data. */ SIMULFS_BLOCK_STATE_COLLECTING, /* This block is being garbage collected */ SIMULFS_BLOCK_STATE_DEAD /* This block has failed and is not in use */ } simulfs_BlockState; /* typedef struct _simulfs_CheckPoint{ simulfs_MixedId checkIds; // 檢查點把當前頁面地址傳過來 }simulfs_CheckPoint; */ /* * 這裏是ID的整合,即:設備ID,blockId,chunkId,來確定一個地址 * Note. 位數都比可能用到的要多,便於以後擴展 */ typedef struct _simulfs_MixedId { __u32 devId:4; __u32 blockId:16; // 所屬塊號 __u32 chunkId:12; // 頁號 }simulfs_MixedId; /* * 這是一個檢查點,檢查點也是地址,就用chunk做地址行嗎? * 否則怎麼找到這個結點唉?? */ typedef simulfs_MixedId simulfs_CheckPoint; /* * 文件系統初始化,形成文件系統內存分配格局 */ int simulfs_mount(void* Space_ROOT); simulfs_MixedId simulfs_AllocBlock(simulfs_Dev* myDev); // 掃描尋找一個新塊 simulfs_MixedId simulfs_AllocChunk(simulfs_Dev* myDev); int simulfs_PortChunk(simulfs_Dev* myDev, const simulfs_MixedId Ids); // 怎樣通過bId和cId索引該chunk?? int simulfs_ScanningBlock(void); int simulfs_EarseBlock(simulfs_Block blk); int simulfs_GarbageCollection(simulfs_Dev* myDev); int simulfs_WritePerChunk(simulfs_Dev* myDev, void* buf, __u32 size); int simulfs_Write(simulfs_Dev* myDev, void* buf, __u32 size); int simulfs_ReadPerChunk(simulfs_Dev* myDev, simulfs_MixedId thisChunk, void* buf, __u32 size); int simulfs_Read(simulfs_Dev* myDev, void* buf, __u32 size); /* * Id 和 地址 之間相互轉換的函數,寫成宏比較好。 * Id號神馬的都是從零開始的。 * such as: * devId = 0; * blockId = 0; * chunkId = 3; * * point = 3*512; */ __inline__ void* simulfs_IdtoPoint(simulfs_MixedId suchId) { void* resPoint = 0; resPoint += suchId.devId*SIMULFS_MAX_DEV_SIZE + suchId.blockId*SIMULFS_CHUNKS_PER_BLOCK + suchId.chunkId*SIMULFS_BYTES_PER_CHUNK + SIMULFS_DATA_OFFSET; return resPoint; } __inline__ simulfs_MixedId simulfs_PointtoId(void* point) { simulfs_MixedId resMixedId; resMixedId.devId = point/SIMULFS_MAX_DEV_SIZE; resMixedId.blockId = ((point%SIMULFS_MAX_DEV_SIZE)-SIMULFS_DATA_OFFSET)/SIMULFS_BYTES_PER_BLOCK; resMixedId.chunkId = ((point%SIMULFS_MAX_DEV_SIZE)-SIMULFS_DATA_OFFSET)%SIMULFS_BYTES_PER_BLOCK; return resMixedId; } __inline__ void SetMixedIdInvailed(simulfs_MixedId* myId) { myId->blockId = SIMULFS_UNUSED_BLOCK_ID; myId->chunkId = SIMULFS_UNUSED_CHUNK_ID; myId->devId = SIMULFS_UNUSED_DEV_ID; } /* * return * 0 Id is valid * 1 Id's DEV Id is invalid * 2 Id's BLOCK Id is invalid * 3 Id's CHUNK Id is invalid */ __inline__ int IsMixedIdInvailed(simulfs_MixedId myId) { if(myId.blockId == SIMULFS_UNUSED_BLOCK_ID) return 2; if(myId.chunkId == SIMULFS_UNUSED_CHUNK_ID) return 3; if(myId.devId == SIMULFS_UNUSED_DEV_ID) return 1; return 0; } #endif //_SIMULFS_OBJECTS_H_
#include "simulfs_objects.h" #include <sys/mman.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> /* * This is the first function of simulfs, we use it to build a formatted * RAM memory structure. */ simulfs_Dev ControlInformationInitilization(void) { int i = 0, j = 0; simulfs_Dev myDev; // I am on this device now myDev.devId = 0; myDev.devTags = 0; myDev.dev_cp.blockId = 0; myDev.dev_cp.chunkId = 0; myDev.dev_cp.devId = myDev.devId; /* * 整個DEV信息的空間申請以及初始化。 * 如果沒有指定,就是這種方式生成。 * 如果指定了,就按照原有的方式不變或者按照指定的方式生成 * 這個RAM信息最終是要放到flash中 */ myDev.blockChain = (simulfs_Block*)calloc(SIMULFS_MAX_BLOCK_COUNT,sizeof(simulfs_Block)); for(i=0; i<=SIMULFS_MAX_BLOCK_ID; ++i) { myDev.blockChain[i]->blockId = i; myDev.blockChain[i]->chunkId = 0; myDev.blockChain[i]->currentState = SIMULFS_BLOCK_STATE_EMPTY; myDev.blockChain[i]->chunkChain = (simulfs_Chunk*)calloc(SIMULFS_MAX_CHUNK_COUNT,sizeof(simulfs_Chunk)); for(j=0; j<=SIMULFS_MAX_CHUNK_ID; ++j) { myDev.blockChain[i]->chunkChain[j]->blockId = myDev.blockChain[i].blockId; myDev.blockChain[i]->chunkChain[j]->chunkId = j; myDev.blockChain[i]->chunkChain[j]->isDirty = 0; myDev.blockChain[i]->chunkChain[j]->needEarse = 0; myDev.blockChain[i]->chunkChain[j]->objectId = SIMULFS_UNUSED_OBJECT_ID; myDev.blockChain[i]->chunkChain[j]->offset = 0; } } return myDev; } /* * It is just like mount command in Linux. * I can use a shell to wrapper it later. */ int simulfs_mount(void* Space_ROOT) { /* * 0. 讀取配置文件 打開相應的映射文件 */ int config_fd = open("simulfs.config", O_READ); int mem_fd = open("simulfs.testMemory",O_RDWR | O_CERATE, 00700); if(mem_fd == -1) perror("open Memory File failed! Please check your system./n"); exit(1); /* * 1. 申請內存空間 */ // mmap Space_ROOT = mmap(NULL,SIMULFS_BYTES_INITIAL,PROT_READ | PORT_WRITE, MAP_SHARED,mem_fd,0); /* * 2. 初始化頂部控制區 */ // 無配置文件,查看第一個bit,0 ==》直接運行0填充; 1 ==》 不改動原內存映射。 if(config_fd == -1) { bzero(Space_ROOT, SIMULFS_BYTES_INITIAL); simulfs_Dev myDev = ControlInformationInitilization(); } else { // 有配置文件,直接按配置文件決定初始化方式。 } /* * 3. 讀取文件系統頂部的控制數據到內存,決定文件分配等信息 */ } /* * Similar, unmount here * Note. 寫回我們的數據 * 釋放分配的空間 */ int simulfs_unmount() { } /* * This function is used to Allocate a new chunk for an object. * If success , return the Ids. * */ simulfs_MixedId simulfs_AllocChunk(simulfs_Dev* myDev) { simulfs_MixedId resIds = SIMULFS_FAIL; // 如果chunk達到最大值,在這裏設置塊的信息 if(myDev->dev_cp.chunkId == SIMULFS_MAX_CHUNK_ID) { myDev->blockChain[myDev->dev_cp.blockId]->currentState = SIMULFS_BLOCK_STATE_FULL; if(simulfs_AllocBlock(myDev) == SIMULFS_FAIL) { return SIMULFS_FAIL; // 如果沒有新的block可以分配了,就返回錯誤,沒有空間了。 } } /* * Note. Chunk地址的計算方式要注意 */ resIds.blockId = (*myDev).dev_cp.blockId; resIds.chunkId = ++(*myDev).dev_cp.chunkId; resIds.devId = (*myDev).dev_cp.devId; return resIds; } /* * This function is used to searching a new block to use. * If search failed, call garbage collection return a new one. * If failed, failed too. * Note. checkpoint will be changed, attention! */ simulfs_MixedId simulfs_AllocBlock(simulfs_Dev* myDev) { int i = (*myDev).dev_cp.blockId; int j = i; /* * Note. 搜索的時候先向後搜,後向前搜 */ for(i; i<SIMULFS_MAX_BLOCK_COUNT; ++i) { if((*myDev).blockChain[i]->currentState == SIMULFS_BLOCK_STATE_EMPTY) { (*myDev).dev_cp.blockId = i; myDev->dev_cp.chunkId = 0; return SIMULFS_OK; } } for(i=0; i<j; ++i) { if((*myDev).blockChain[i]->currentState == SIMULFS_BLOCK_STATE_EMPTY) { (*myDev).dev_cp.blockId = i; myDev->dev_cp.chunkId = 0; return SIMULFS_OK; } } // 上兩步都搜不到合適的塊,那就調用垃圾回收器 if(simulfs_GarbageCollection(myDev) == SIMULFS_FAIL) return SIMULFS_FAIL; return SIMULFS_OK; } /* * This function is used to collecting garbage, free some block to use. * I ignored the efficiency. ^_^, it is just a simula file system. */ int simulfs_GarbageCollection(simulfs_Dev* myDev) { int i=0; for(i; i<SIMULFS_MAX_BLOCK_COUNT; ++i) { if(myDev->blockChain[i]->currentState == SIMULFS_BLOCK_STATE_DIRTY) { // do garbage collection simulfs_MixedId Ids; Ids.blockId = myDev->blockChain[i]->blockId; Ids.chunkId = 0; Ids.devId = myDev.devId; simulfs_EarseBlock(myDev, Ids); myDev->dev_cp.blockId = i; myDev->dev_cp.chunkId = 0; } return SIMULFS_OK; } return SIMULFS_FAIL; } /* * This function is used to scanning all blocks and set some values. * I don't whether it goes well or not, but I really need it. * But now , it just used for setting flag --->> * SIMULFS_BLOCK_STATE_DIRTY */ int DEV_Scanning(simulfs_Dev* myDev) { int i=0,j=0; int sum = 0; for(i; i<SIMULFS_MAX_BLOCK_COUNT; ++i) { sum = 0; for(j; j<SIMULFS_MAX_CHUNK_COUNT; ++j) { sum += myDev->blockChain[i]->chunkChain[j]->needEarse; } if(sum == SIMULFS_MAX_CHUNK_COUNT) myDev->blockChain[i]->currentState = SIMULFS_BLOCK_STATE_DIRTY; } } /* * This function is used to port data of a chunk to another. * Of course, they are on the different blocks. */ int simulfs_PortChunk(simulfs_Dev* myDev, const simulfs_MixedId Ids) { if(simulfs_AllocChunk(myDev) == SIMULFS_FAIL) return SIMULFS_FAIL; // 通過這個函數,當前的檢查點中存的已經是新申請到的chunk了。 // 下面的內容是chunk之間的數據轉移 memcpy(simulfs_IdtoPoint(myDev->dev_cp), simulfs_IdtoPoint(Ids), SIMULFS_BYTES_PER_CHUNK); // 原chunk設置 myDev->blockChain[myDev->dev_cp.blockId]-> chunkChain[myDev->dev_cp.chunkId]->needEarse = 1; // 檢查點更新 if(myDev->dev_cp.chunkId == SIMULFS_MAX_CHUNK_ID) { myDev->blockChain[myDev->dev_cp.blockId]->currentState = SIMULFS_BLOCK_STATE_FULL; simulfs_AllocBlock(myDev); // 分配新塊,分完後cp已經是設置好的了。 } else { myDev->dev_cp.chunkId++; } } /* * This function is used to erase a block * @param: * simulfs_MixedId to implicitly store address */ int simulfs_EarseBlock(simulfs_Dev* myDev, simulfs_MixedId blk) { // 1. 清除空間 void* point = simulfs_IdtoPoint(blk); bzero(point,SIMULFS_BYTES_PER_BLOCK); // 2. 設置相關值 myDev->blockChain[blk.blockId]->currentState = SIMULFS_BLOCK_STATE_EMPTY; myDev->blockChain[blk.blockId]->nextChunkId = 0; int i=0; for(i=0; i<SIMULFS_CHUNKS_PER_BLOCK; ++i) { myDev->blockChain[blk.blockId]->chunkChain[i]->isDirty = 0; myDev->blockChain[blk.blockId]->chunkChain[i]->needEarse = 0; myDev->blockChain[blk.blockId]->chunkChain[i]->objectId = SIMULFS_UNUSED_OBJECT_ID; myDev->blockChain[blk.blockId]->chunkChain[i]->offset = 0; } return SIMULFS_OK; } /* * This function is used to set chunk-info, * Now just used in the above function. */ void SetChunkAttrAfterWrite(simulfs_Dev* myDev, simulfs_MixedId chkIds, __u32 offset) { myDev->blockChain[chkIds.blockId]->chunkChain[chkIds.chunkId]->isDirty = 1; myDev->blockChain[chkIds.blockId]->chunkChain[chkIds.chunkId]->offset = offset; /* * ObjectID 由高層函數來管理,暫時不知到這個項目填什麼。 */ //myDev->blockChain[chkIds.blockId]->chunkChain[chkIds.chunkId]->objectId = ??? } /* * 更新ckp,可能會有很多函數用到 * 返回值爲舊的ckp * 傳入值爲新的ckp */ simulfs_MixedId ResetCheckPoint(simulfs_Dev* myDev, simulfs_MixedId newChkPoint) { myDev->dev_cp.blockId = newChkPoint.blockId; myDev->dev_cp.chunkId = newChkPoint.chunkId; myDev->dev_cp.devId = newChkPoint.devId; } void SetNextLowestLevelWriteChunk(simulfs_Dev* myDev, simulfs_MixedId newChkPoint) { myDev->blockChain[myDev->dev_cp.blockId]-> chunkChain[myDev->dev_cp.chunkId]->lowestLevelWriteNextChunk = chkIds; } // 該函數設置下一個無用。唉~這裏就能看出OOB的好處了,但是這裏用的還是面向過程的語言 void SetNextLowestLevelWriteChunkZero(simulfs_Dev* myDev) { simulfs_MixedId zeroChunk; /* * 其他的不用管了,只要這個devId不合法,就判斷出來了。 */ zeroChunk.devId = SIMULFS_UNUSED_DEV_ID; myDev->blockChain[myDev->dev_cp.blockId]-> chunkChain[myDev->dev_cp.chunkId]->lowestLevelWriteNextChunk = zeroChunk; } /* * --------------------------------------------------------------------------------------------------------- * -------------------An array functions of write----------------------------------------------------------- */ /* * This function is used to write data in the lowest mode. * Every other like-write function call this one. * If a chunk is not enough, it will call for a new one. * Note. 相應的數據結構會被修改 * 默認情況下是隻開放下一個函數的,這個函數是系統使用的。 * 這裏只用普通鏈表的方法鏈接吧,在高層的函數中就會有二叉樹的鏈接方式了。 */ int WriteLowestLevelPerChunk(simulfs_Dev* myDev, simulfs_MixedId chkIds, void* buf, __u32 size) { // 相當於重新設置checkpoint,不推薦直接使用。 ResetCheckPoint(myDev, chkIds); // 轉換地址 void* dest = simulfs_IdtoPoint(chkIds); memcpy(dest,buf,size<SIMULFS_BYTES_PER_CHUNK?size:SIMULFS_BYTES_PER_CHUNK); SetChunkAttrAfterWrite(myDev, chukIds,size<SIMULFS_BYTES_PER_CHUNK?size:SIMULFS_BYTES_PER_CHUNK); SetNextLowestLevelWriteChunkZero(myDev); /* * 爲什麼這裏不用重新設置ckp了?因爲我的ckp代表的是當前正寫着東西的那一頁,上面已經修改過了,所以這裏不用修改了。 */ } int simulfs_WritePerChunk(simulfs_Dev* myDev, void* buf, __u32 size) { return WriteLowestLevelPerChunk(myDev, myDev->dev_cp,buf,size); } // 這個函數在高層可能沒有必要 int WriteLowestLevel(simulfs_Dev* myDev, simulfs_MixedId chkIds, void* buf, __u32 size) { // 轉換地址 void* dest = simulfs_IdtoPoint(chkIds); // 直接寫開始 int i=0; do { ResetCheckPoint(myDev, chkIds); if(size > SIMULFS_BYTES_PER_CHUNK) { memcpy(dest+i*SIMULFS_BYTES_PER_CHUNK, buf+i*SIMULFS_BYTES_PER_CHUNK, SIMULFS_BYTES_PER_CHUNK); // 設置相應的chunk信息 SetChunkAttrAfterWrite(myDev, chukIds, SIMULFS_BYTES_PER_CHUNK); // 該chunk使用完畢 申請一個新的chunk if((chkIds = simulfs_AllocChunk(myDev)) == SIMULFS_FAIL) { // 分配失敗 perror("Error occur, AllocChunk failed!" "in function simulfs_AllocChunk()" "in function WriteLowestLevel()."); } else { // 分配新的chunk成功 SetNextLowestLevelWriteChunk(myDev, chkIds); dest = simulfs_IdtoPoint(chkIds); } } else { memcpy(dest+i*SIMULFS_BYTES_PER_CHUNK, buf+i*SIMULFS_BYTES_PER_CHUNK, size); // 設置相應的chunk信息 SetChunkAttrAfterWrite(myDev, chukIds, size); SetNextLowestLevelWriteChunkZero(myDev); break; } size -= SIMULFS_BYTES_PER_CHUNK; ++i; }while(1); return SIMULFS_OK; } int simulfs_Write(simulfs_Dev* myDev, void* buf, __u32 size) { return WriteLowestLevel(myDev, myDev->dev_cp,buf,size); } /* * --------------------------------------------------------------------------------------------------------- * -------------------An array functions of read----------------------------------------------------------- */ /* * This is the READ function in the lowest level,like the above function. * The buffer should be calloced in user's application, not in me. * Note. 底層的讀函數不同於寫函數,只能按chunk讀,沒有ObjectID,東西是連不在一起的。只能根據chunk中的鏈表查找 * 爲什麼高層函數會比底層函數塊呢??囧啊~ * 讀的時候注意檢查size是否在合適的範圍內,否則拒絕返回 */ // 用戶自己要保證傳入的緩衝內存是夠大的,否則會溢出 int ReadLowestLevelPerChunk(simulfs_Dev* myDev, simulfs_MixedId thisChunk, void* buf, __u32 size) { // 1. 判斷size大小是否合適 if(myDev->blockChain[thisChunk.blockId]->chunkChain[thisChunk.chunkId]->offset >= size) { const void* src = simulfs_IdtoPoint(thisChunk); memcpy(buf, src, size); return SIMULFS_OK; } else { perror("Size are ambition, I think you should change a function, such as simulfs_Read" "Error occur in simulfs_ReadPerChunk()" "in ReadLowestLevelPerChunk()"); return SIMULFS_FAIL; } } int simulfs_ReadPerChunk(simulfs_Dev* myDev, simulfs_MixedId thisChunk, void* buf, __u32 size) { return ReadLowestLevelPerChunk(myDev, thisChunk, buf, size); } int ReadLowestLevel(simulfs_Dev* myDev, simulfs_MixedId startChunk, void* buf, __u32 size) { } int simulfs_Read(simulfs_Dev* myDev, void* buf, __u32 size) { return WriteLowestLevel(myDev, buf, size); }
/* * This page is designed to implement a double link. * The structure is used in simulfs_fs.h/.c to implement a * high level object manipulation. * Copyright @ Xusen Yin, Dep. IS, BISTU */ #ifndef _SIMULFS_DLINK_H_ #define _SIMULFS_DLINK_H_ #include "simulfs_objects.h" #include "simulfs_marcos.h" /* * Dir 00000001 0x01 * File 00000010 0x02 * Symlnk 00000100 0x04 * hrdlnk 00001000 0x08 * special 00010000 0x10 * unknow 00100000 0x20 */ typedef struct _similfs_Flags{ __u8 isDir:1; __u8 isFile:1; __u8 isSymlnk:1; __u8 isHrdlnk:1; __u8 isSpecial:1; __u8 isUnknow:1; __u8 alignData:1; // 最後兩個數據是用來填充用的 __u8 alignData:1; }similfs_Flags; typedef struct _simulfs_ListNode { void* dataPtr; // 這個可以傳入simulfs_FileTree的指針。 int objectNumber; // 如果是目錄,記錄他的對象個數 similfs_Flags thisFlag; simulfs_MixedId thisId; simulfs_Object obj; struct _simulfs_ListNode* priorSlibing; struct _simulfs_ListNode* nextSlibing; struct _simulfs_ListNode* leftChild; struct _simulfs_ListNode* parent; }simulfs_ListNode,*simulfs_List; /* 下面這個函數可能是用不到的 */ /* int simulfs_CreateList(); */ int simulfs_TraverseList(simulfs_List lst, int (*Visit)(simulfs_List lst)); int simulfs_DestoryList(simulfs_List lst); simulfs_List simulfs_PriorSlibing(simulfs_List lst); simulfs_List simulfs_NextSlibing(simulfs_List lst); simulfs_List simulfs_LeftChild(simulfs_List lst); simulfs_List simulfs_Parent(simulfs_List lst); /* * 在lstLeft下面的結點插入 */ int simulfs_InsertListNodeAfter(simulfs_List lstLeft, simulfs_List lstSrc); /* * 在lstRight之前插入 */ int simulfs_InsertListNodeBefore(simulfs_List lstRight, simulfs_List lstSrc); /* * 在頭上插入 */ int simulfs_InsertListNodeonBegin(simulfs_List lstSrc); /* * 在尾部插入 */ int simulfs_InsertListNodeonEnd(simulfs_List lstSrc); int simulfs_DeleteListNode(simulfs_List lst); #endif //_SIMULFS_DLINK_H_
/* * Maybe it will be used later */ #include "simulfs_dlink.h" #include "simulfs_fs.h" #include "simulfs_FileTree.h" /* * Dir 00000001 0x01 * File 00000010 0x02 * Symlnk 00000100 0x04 * hrdlnk 00001000 0x08 * special 00010000 0x10 * unknow 00100000 0x20 */ int VisitAndDestoryAllLinkNode(simulfs_List lst) { if((lst->thisFlag)&(0x01)) { /* * 如果是文件夾的釋放,要先釋放其下的各個文件夾,然後再釋放它自己 */ simulfs_DestoryList(lst->leftChild); } else if((lst->thisFlag)&(0x02)) { /* * 如果是文件,則要調用文件刪除函數 */ 啊啊啊啊 FileDelete(lst->dataPtr); // 這裏的dataPtr指向的就是Tree Node } else if((lst->thisFlag)&(0x04)) { /* * 如果是軟鏈接,就只是一個字符串,搞掉它!! */ free(((simulfs_SymLinkStructure*)lst->dataPtr)->alias); } else if((lst->thisFlag)&(0x08)) { /* * 如果是硬鏈接 */ free(((simulfs_HardLinkStructure*)lst->dataPtr)->equivalentObject); } else if((lst->thisFlag)&(0x10)) { /* * 如果是特殊設備,我也不知道怎麼辦 */ // UnDO. } else if((lst->thisFlag)&(0x20)) { /* * 如果是未知文件 */ //UnDO. } else { } free(lst); } int simulfs_TraverseList(simulfs_List lst, int (*Visit)(simulfs_List lst)) { // 怎麼走呢? 先向後走,再向前走 simulfs_List lstTmp = lst->priorSlibing; int res = SIMULFS_OK; while(lst->nextSlibing != NULL) { res = Visit(lst); lst = lst->nextSlibing; } while(lstTmp->priorSlibing != NULL) { res = Visit(lstTmp); lstTmp = lstTmp->priorSlibing; } return res; } /* * 只要給出這條鏈子的一個點,就能全部刪除之,注意中途出現的其他Dir */ int simulfs_DestoryList(simulfs_List lst) { return simulfs_TraverseList(lst, VisitAndDestoryAllLinkNode(lst)); } /* * 返回之前的那個兄弟結點 */ simulfs_List simulfs_PriorSlibing(simulfs_List lst) { return lst->priorSlibing; } simulfs_List simulfs_NextSlibing(simulfs_List lst) { return lst->nextSlibing; } simulfs_List simulfs_LeftChild(simulfs_List lst) { return lst->leftChild; } simulfs_List simulfs_Parent(simulfs_List lst) { return lst->parent; } /* * 在lstLeft後面的結點插入,記得記錄目錄中對象的個數 */ int simulfs_InsertListNodeAfter(simulfs_List lstLeft, simulfs_List lstSrc) { if(lstSrc == NULL || lstLeft == NULL) { return SIMULFS_FAIL; } lstSrc->parent = lstLeft->parent; if(lstLeft->nextSlibing == NULL) { lstLeft->nextSlibing = lstSrc; lstSrc->priorSlibing = lstLeft; lstSrc->nextSlibing = NULL; } else { lstSrc->priorSlibing = lstLeft; lstSrc->nextSlibing = lstLeft->nextSlibing; lstLeft->nextSlibing->priorSlibing = lstSrc; lstLeft->nextSlibing = lstSrc; } ++lstSrc->parent->objectNumber; return SIMULFS_OK; } /* * 在lstRight之前插入 */ int simulfs_InsertListNodeBefore(simulfs_List lstRight, simulfs_List lstSrc) { if(lstSrc == NULL || lstRight == NULL) { return SIMULFS_FAIL; } lstSrc->parent = lstRight->parent; if(lstRight->priorSlibing == NULL) { lstSrc->nextSlibing = lstRight; lstSrc->priorSlibing = NULL; lstRight->priorSlibing = lstSrc; } else { lstSrc->nextSlibing = lstRight; lstSrc->priorSlibing = lstRight->priorSlibing; lstRight->priorSlibing->nextSlibing = lstSrc; lstRight->priorSlibing = lstSrc; } ++lstSrc->parent->objectNumber; return SIMULFS_OK; } /* * 在頭上插入,只要提供這條連上任意一個結點就行 */ int simulfs_InsertListNodeonBegin(simulfs_List lst, simulfs_List lstSrc) { while(lst->priorSlibing != NULL) lst = lst->priorSlibing; return simulfs_InsertListNodeBefore(lst, lstSrc); } /* * 在尾部插入 */ int simulfs_InsertListNodeonEnd(simulfs_List lst, simulfs_List lstSrc) { while(lst->nextSlibing != NULL) lst = lst->nextSlibing; return simulfs_InsertListNodeAfter(lst, lstSrc); } int simulfs_DeleteListNode(simulfs_List lst) { return VisitAndDestoryAllLinkNode(lst); }
#ifndef _SIMULFS_TREE_H_ #define _SIMULFS_TREE_H_ #include "simulfs_marcos.h" #include "simulfs_dlink.h" // 該樹是父親——兄弟樹,因爲文件夾的存儲方式嗎^_^ typedef struct _simulfs_CSNode { simulfs_ListNode ln; }simulfs_CSNode, *simulfs_CSTree; int simulfs_InitCSTreeNode(simulfs_CSNode* CSNode); int simulfs_CreateCSTreeNode(simulfs_CSNode** CSNode, similfs_Flags thisFlag); int simulfs_CreateCSTree(simulfs_CSTree* CSTreeROOT); int simulfs_DestoryCSTree(simulfs_CSTree CSTreeROOT); #endif // _SIMULFS_TREE_H_
a/* * This file is used to realize a parent-slibing tree * to record the directory structure. */ #include "simulfs_CSTree.h" #include <stdlib.h> #include "simulfs_objects.h" #include "simulfs_dlink.h" /* * 想要修改CSTreeROOT指向的那個結點,所以要傳入他的指針 * 但是估計到我們要生成一個指針,所以傳入指針的指針是不錯的選擇 */ int simulfs_InitCSTreeNode(simulfs_CSNode* CSNode) { CSNode->ln.dataPtr = NULL; CSNode->ln.leftChild = NULL; CSNode->ln.nextSlibing = NULL; CSNode->ln.parent = NULL; CSNode->ln.priorSlibing = NULL; CSNode->ln.thisFlag = 0x20; // 預設爲UNKNOW CSNode->ln.objectNumber = 0; SetMixedIdInvailed(&(CSNode->ln.thisId)); } // 初始化普通的結點要根據標記創建成不同的結點 int simulfs_CreateCSTreeNode(simulfs_CSNode** CSNode, similfs_Flags thisFlag) { *CSNode = (simulfs_CSNode*)calloc(1, sizeof(simulfs_CSNode)); simulfs_InitCSTreeNode(*CSNode); *CSNode->ln.thisFlag = thisFlag; } int simulfs_CreateCSTree(simulfs_CSTree* CSTreeROOT) { // 開始定義它爲文件夾,創建了一棵樹,必須是主目錄啊。 simulfs_CreateCSTreeNode(CSTreeROOT, 0x01); } int simulfs_DestoryCSTree(simulfs_CSTree CSTreeROOT) { return simulfs_DestoryList(CSTreeROOT->ln); }
/* * This file is used to record the file tree. * File tree is different from the directory. * It used some levels and slots to store file contents. * The first chunk stored file meta data. * Copyright @ Xusen Yin, Dept. IS, BISTU. * Note. union 的作用是指向統同一個內存地址的兩個不同類型的變量 */ #ifndef _SIMULFS_FILETREE_H_ #define _SIMULFS_FILETREE_H_ #include "simulfs_objects.h" #include "simulfs_marcos.h" /* * 下面兩個是每層不同的槽數目,爲了索引用的。性能不好的時候可以修改。 * 隨着文件的增長,樹的結點增加。當這些結點已經不夠用的時候,層次增加。 * 文件的修改要反映到樹的變化中。文件的截斷,增長,修改要反映到樹中。 * Note. 只有最後一層葉子結點纔有資格帶文件數據 */ #define SIMULFS_FILETREE_SLOTS_ON_ABOVE_LEVEL_ONE 8 #define SIMULFS_FILETREE_SLOTS_ON_LEVEL_ZERO 16 typedef struct _simulfs_FileNode { /* 樹深,葉子結點是level 0,其他的根據需要調整*/ int level; /* nextChild 主要用途是指向非葉結點的指針 */ struct _simulfs_FileNode* nextChild[SIMULFS_FILETREE_SLOTS_ON_ABOVE_LEVEL_ONE]; /* Ids主要用途是指向各個chunk,這種情況下就是上面的是NULL,這就是葉結點 */ simulfs_MixedId Ids[SIMULFS_FILETREE_SLOTS_ON_LEVEL_ZERO]; struct _simulfs_FileNode* parent; /* 下面這個是給非葉結點用的,來判斷它已經分配了哪些槽了。 */ int nextTobeAllocateNumber; // 下一個在父結點中的位置(數組的位置),如果這個位置已經超出上限 // SIMULFS_FILETREE_SLOTS_ON_ABOVE_LEVEL_ONE // 那就申請新結點,注意上溯到爺爺結點 // 如果有葉子結點,那就是掛滿8個葉子結點的,不會少 }simulfs_FileNode; typedef struct { simulfs_FileNode* fileTreeROOTNode; // 指向根結點 int nextChunkIdinObject; // 下一個可以用的chunkID,也是chunk計數 }simulfs_FileTree; /* * 這個不用傳遞指針的指針 * 傳遞指針的指針只存在一種情況:你要修改這個指針的值,但是不方便把修改後的指針的值當成結果返回 * 如果值修改指針指向的內容,那就只傳指針就行了。 * 這個Create函數存在兩種情況: * 1. 這個fileTreeROOT已經有內容讓他指向了,這樣就傳指針 * 2. 這個fileTreeROOT只是一個指針,還沒有讓他指向任何東西,那就傳遞指針的指針 * 我先在存在第二種情況,嘿嘿~ */ int simulfs_CreateFileNode(simulfs_FileTree* fileTreeNode); int simulfs_CreateFileTree(simulfs_FileTree* fileTreeROOT); int simulfs_TraverseFileTree(simulfs_FileTree thisROOT, int (*Visit)(simulfs_FileNode* csnode)); int simulfs_DestoryFileTree(simulfs_FileTree thisROOT); int simulfs_InsertFileNode(simulfs_FileTree fileTreeROOT, simulfs_FileNode* myNode); int simulfs_DeleteFileNode(simulfs_FileTree fileTreeROOT, simulfs_FileNode* myNode); #endif //_SIMULFS_FILETREE_H_
/* * This file is used to record the file tree. * File tree is different from the directory. * It used some levels and slots to store file contents. * The first chunk stored file meta data. * Copyright @ Xusen Yin, Dept. IS, BISTU. * Note. union 的作用是指向統同一個內存地址的兩個不同類型的變量 */ /* * 關鍵問題是怎樣分配chunk * 要不每次一層增加時,把所有的非葉結點都申請了算了,省得麻煩,可以提高效率,缺點就是浪費點空間 * */ #include "simulfs_FileTree.h" #include "simulfs_objects.h" #include "simulfs_marcos.h" #include <stdlib.h> const int maxNumberofTree[SIMULFS_MAX_POS_ARRAY] = { 0x0010, 0x0080, 0x0400, 0x2000, 0x10000, 0x80000, 0x400000, 0x2000000 }; /* * 一個函數只幹一件事,不能多幹,纔好管理 */ simulfs_FileNode* simulfs_CreateFileNode(void) { simulfs_FileNode* fileTreeNode = (simulfs_FileNode*)calloc(1, sizeof(simulfs_FileNode)); return fileTreeNode; } /* * 初始化內部迭代結點 * Note. 傳入的時候必須保證fileTreeNode不是NULL * arguments: * 1. 要初始化結點的雙親結點 * 2. 自身結點的指針 * 3. 自身的層次=雙親結點層次-1 */ int simulfs_InitIteralFileNode(simulfs_FileNode* parent, simulfs_FileNode* fileTreeNode, int level) { if(fileTreeNode == NULL) { return SIMULFS_FAIL; } int i = 0; fileTreeNode->parent = parent; for(i = 0; i<SIMULFS_FILETREE_SLOTS_ON_LEVEL_ZERO; ++i) { SetMixedIdInvailed(&(fileTreeNode->Ids[i])); } for(i = 0; i<SIMULFS_FILETREE_SLOTS_ON_ABOVE_LEVEL_ONE; ++i) { fileTreeNode->nextChild[i] == NULL; } fileTreeNode->level = level; fileTreeNode->nextTobeAllocateNumber = 0; return SIMULFS_OK; } /* * 初始化葉子結點,注意初始化葉子結點的時候不用申請新的可用的結點,暫時當作沒用就可以了, * 申請真正的結點可以稍後進行 * 每個葉子結點都有16個槽呢,邊用邊申請得了 * arguments: * 1. 要初始化結點的雙親結點 * 2. 自身結點的指針 */ int simulfs_InitFileLeafNode(simulfs_FileNode* parent, simulfs_FileNode* fileTreeNode) { return simulfs_InitIteralFileNode(parent, fileTreeNode, 0); } /* * 要求傳入預設的chunk的個數,默認的情況下每個文件暫時分配8個chunk * If only level 0 8*512B * level 1 4*8*512B * level 2 4*4*8*512B * level 3 4*4*4*8*512B * ... ... * How to create the tree??? * 這樣把,create只做建立初始化樹這樣的事情,其他的事情交給resize函數去做 * Note. 每次分配都是8個,都是滿的,不要搞錯 */ /* * 不用傳入參數,直接申請一個新的樹就行了 * return: * 樹根的值(注意不是指針) * 樹根和普通的結點不同,封裝了一些東西 * Note. 如果創建失敗,那麼返回的值中的樹結點的指針就是空就可以了 */ simulfs_FileTree simulfs_CreateFileTree(void) { simulfs_FileTree fileTreeROOT; fileTreeROOT.fileTreeROOTNode = simulfs_CreateFileNode(); simulfs_InitFileLeafNode(NULL, simulfs_InitFileLeafNode); fileTreeROOT.nextChunkIdinObject = 0; return fileTreeROOT; } /* int simulfs_CreateFileTree(simulfs_Dev* myDev, simulfs_FileTree* fileTreeROOT) { if(simulfs_CreateFileNode(&(fileTreeROOT->fileTreeROOTNode)) == SIMULFS_FAIL) return SIMULFS_FAIL; int i = 0; simulfs_InitFileLeafNode(myDev, fileTreeROOT->fileTreeROOTNode); fileTreeROOT->totalChunkNumber = SIMULFS_DEFAULT_FILE_CHUNK; fileTreeROOT->remainChunkNumber = SIMULFS_DEFAULT_FILE_CHUNK; // 樹建立後,文件參數要做部分修改 // 不過不在這裏修改,是樹的部分,就只管樹的情況,每次只考慮一層 return SIMULFS_OK; } */ /* * 根據postion尋找某個槽的指針,嘿嘿,精華所在啊 * 返回一個simulfs_MixedId* * 自己收拾去吧。 * Note. 原始的那個chunk要有所標記奧 */ simulfs_MixedId* simulfs_seekAddrofASlot(simulfs_Dev* myDev, simulfs_FileTree* fileTreeROOT, int pos) { simulfs_MixedId* resId = NULL; int pos_ary[SIMULFS_MAX_POS_ARRAY] = {0}; int i=0; for(i=0; (i<SIMULFS_MAX_POS_ARRAY)&&(pos!=0) ;++i) { if(i==0) { // 第一次的偏移是4bit pos_ary[i] = pos >> 4; pos >>= 4; }else { pos_ary[i] = pos >> 3; pos >>=3; } } simulfs_FileNode* iteral = NULL; iteral = fileTreeROOT->fileTreeROOTNode; if(iteral == NULL) { perror("No tree is found, please create tree first" "Error found in simulfs_FileTree.c" "in function simulfs_skCrtAddrofASlot()"); return resId; } while(iteral->level > 0) { iteral = iteral->nextChild[pos_ary[iteral->level]]; // 說明pos有誤,立即返回 if(iteral == NULL) { perror("Position is error" "Please check your input" "Error found in simulfs_seekAddrofASlot()"); return resId; } } // 如果原來有chunk設在裏面,那就把它設爲待擦除 if((resId->blockId != SIMULFS_UNUSED_BLOCK_ID)&& (resId->chunkId != SIMULFS_UNUSED_CHUNK_ID)&& (resId->devId != SIMULFS_UNUSED_DEV_ID)) { myDev->blockChain[resId->blockId]->chunkChain[resId->chunkId]->needEarse = 1; } resId = &(iteral->Ids[pos_ary[0]]); return resId; } /* * 向特定的位置加入一個chunk,當然,這個特定位置必須是當前樹形結構中已經有了的 * 所以不存在樹形結構的拓展 * pos 的值需要用戶自行注意,否則會出現大問題,嘿嘿 * 最好不要直接使用這個函數 */ int simulfs_PutAChunkInTreeSlot(simulfs_Dev* myDev, simulfs_FileTree* fileTreeROOT, int pos) { // 1. 找到那個位置 simulfs_MixedId* thisId = simulfs_seekAddrofASlot(fileTreeROOT,pos); // 2. 分配空間 *thisId = simulfs_AllocChunk(myDev); return SIMULFS_OK; } /* * 該死的樹形大結構 * 只有零層: 0x0010 * 1 0x0080 * 2 0x0400 * 3 0x2000 * 4 0x10000 * 5 0x80000 * 6 0x400000 * 7 0x2000000 * 8 0x10000000 * 9 0x80000000 * 10 ==! 已經算不出來了 * 看來把最大樹深改爲8即可,模擬,模擬 */ simulfs_MixedId* simulfs_skCrtAddrofASlot(simulfs_FileTree* fileTreeROOT, int pos) { int i=0; for(i=0; i<SIMULFS_MAX_POS_ARRAY;++i) { // 如果有相等的,需要調整樹深 if(pos == maxNumberofTree[i]) { simulfs_FileNode* newRoot = simulfs_CreateFileNode(); simulfs_InitIteralFileNode(NULL, newRoot, fileTreeROOT->fileTreeROOTNode->level+1); fileTreeROOT->fileTreeROOTNode->parent = newRoot; fileTreeROOT->fileTreeROOTNode = newRoot; break; } else if(pos < maxNumberofTree[i]) { break; } } simulfs_MixedId* resId = NULL; int pos_ary[SIMULFS_MAX_POS_ARRAY] = {0}; for(i=0; (i<SIMULFS_MAX_POS_ARRAY)&&(pos!=0) ;++i) { if(i==0) { // 第一次的偏移是4bit pos_ary[i] = pos >> 4; pos >>= 4; }else { pos_ary[i] = pos >> 3; pos >>=3; } } simulfs_FileNode *iteral = NULL, *iteral_parent = NULL; iteral = fileTreeROOT->fileTreeROOTNode; if(iteral == NULL) { perror("No tree is found, please create tree first" "Error found in simulfs_FileTree.c" "in function simulfs_skCrtAddrofASlot()"); return resId; } while(iteral->level > 0) { iteral_parent = iteral; iteral = iteral->nextChild[pos_ary[iteral->level]]; // 如果發現迭代器變成了NULL,那麼就說明要創建新的結點 嗯嗯 if(iteral == NULL) { simulfs_FileNode* newNode = simulfs_CreateFileNode(); simulfs_InitIteralFileNode(iteral_parent, newNode, iteral_parent->level-1); iteral_parent->nextChild[pos_ary[iteral_parent->level]] = newNode; } } resId = &(iteral->Ids[pos_ary[0]]); return resId; } /* * 向當前位置插入一個結點 * 這樣的話,當前位置要做+1運算 */ int simulfs_PutAChunkInCurTreeSlot(simulfs_Dev* myDev, simulfs_FileTree* fileTreeROOT) { // 1. 找到那個位置,這回的找到和上次的不同了 // 這次如果找不到就是要創建的了 simulfs_MixedId* thisId = simulfs_skCrtAddrofASlot(fileTreeROOT, fileTreeROOT->nextChunkIdinObject++); // 2. 分配空間 *thisId = simulfs_AllocChunk(myDev); return SIMULFS_OK; } /* * 遍歷所有結點,調用visit函數 * 這個,遍歷Interal結點恐怕沒什麼作用啊 * 就先寫個遍歷葉子結點的吧 * 那個以後用到了再說。 * Note. 這玩意兒遍歷還得用個隊列,要不真麻煩 */ int simulfs_TraverseFileTree(simulfs_FileTree thisROOT, int (*Visit)(simulfs_FileNode* csnode)) { 123 } /* * 刪除一個文件的時候,擦除所有的結點,釋放所有的chunk去擦除 */ int simulfs_DestoryFileTree(simulfs_FileTree thisROOT) { } /* * 從某結點開始到level1 自動生成 * 唉,不知到這個遞歸能不能順利進行??? * 真是鬱悶,寫的不好,到時候再改吧。 */ int InitParentAndChildrenToLeaf(simulfs_FileNode* myNode) { if(myNode->level <= 1) { return SIMULFS_FAIL; } else { simulfs_FileNode* newNodes[SIMULFS_FILETREE_SLOTS_ON_ABOVE_LEVEL_ONE]; int i=0; for(i=0; i< SIMULFS_FILETREE_SLOTS_ON_ABOVE_LEVEL_ONE; ++i) { // 1. 創建4個結點 simulfs_CreateFileNode(&newNodes[i]); // 2. 初始化4個結點 simulfs_InitFileNode(newNodes[i]); // 3. 掛載到當前結點上 newNodes[i]->parent = myNode; myNode->nextChild[i] = newNodes[i]; // 4. 做一些設置 newNodes[i]->level = myNode->level -1; InitParentAndChildrenToLeaf(newNodes[i]); } return SIMULFS_OK; } } /* * 主要用於找不到新的可用的葉子結點時,擴大樹的深度,深度一次增一 * Note. 不改變原樹的結構,原樹現在成爲一支,我們重新申請一個根結點,把原樹掛上就行了 * 記得生成其他樹level1(包含)以上的結點 */ int simulfs_ResizeFileTreeDepth(simulfs_FileTree fileTreeROOT) { simulfs_FileNode* newRootNode; simulfs_CreateFileNode(&newRootNode); simulfs_InitFileNode(newRootNode); newRootNode->level = fileTreeROOT.fileTreeROOTNode->level+1; newRootNode->nextChild[0] = fileTreeROOT.fileTreeROOTNode; // 掛載新根 fileTreeROOT.fileTreeROOTNode = newRootNode; // 生成其他結點 simulfs_FileNode* newNodes[SIMULFS_FILETREE_SLOTS_ON_ABOVE_LEVEL_ONE-1]; int i=0; for(i=0; i< SIMULFS_FILETREE_SLOTS_ON_ABOVE_LEVEL_ONE-1; ++i) { // 1. 創建3個結點 simulfs_CreateFileNode(&newNodes[i]); // 2. 初始化3個結點 simulfs_InitFileNode(newNodes[i]); // 3. 掛載到當前結點上 newNodes[i]->parent = newRootNode; newRootNode->nextChild[i] = newNodes[i]; // 4. 做一些設置 newNodes[i]->level = newRootNode->level -1; InitParentAndChildrenToLeaf(newNodes[i]); } return SIMULFS_OK; } /* * 主要用於申請更多的chunk數目時,在一定的樹深度下尋找新的可用葉子結點。 * 可不可以做到透明的調整樹的形狀??? */ int simulfs_ResizeFileTreeGrowth(simulfs_Dev* myDev, simulfs_FileTree fileTreeROOT, int ChunkNumber) { /* 如果剩餘的塊數還夠,就不用再申請了 */ if(ChunkNumber <= fileTreeROOT.remainChunkNumber) return SIMULFS_AMBIGOUS; do { if(fileTreeROOT.currentLevelOneNode->nextTobeAllocateNumber == SIMULFS_FILETREE_SLOTS_ON_ABOVE_LEVEL_ONE) { // 如果中間一步出錯還要考慮原來步驟撤銷的事情,暫時沒考慮寫這部分回滾代碼 if(fileTreeROOT.currentLevelOneNode->parent->nextTobeAllocateNumber == SIMULFS_FILETREE_SLOTS_ON_ABOVE_LEVEL_ONE) { // 這步如果出錯了,就要考慮增加樹深了。 return SIMULFS_FILETREENEEDMOREDEEP; } // 1. 把當前結點改到下一個 fileTreeROOT.currentLevelOneNode = fileTreeROOT.currentLevelOneNode->parent-> nextChild[fileTreeROOT.currentLevelOneNode->parent->nextTobeAllocateNumber++]; } // 1. 申請8個當前chunk,即把這八個新的結點初始化 if(simulfs_InitFileLeafNode(myDev, fileTreeROOT.currentLevelOneNode-> nextChild[fileTreeROOT.currentLevelOneNode->nextTobeAllocateNumber++]) == SIMULFS_FAIL) { // 如果這步不成功,那就是真的錯了。 return SIMULFS_FAIL; } // 2. 下面可用的chunk大小加 8 fileTreeROOT.remainChunkNumber += SIMULFS_FILETREE_SLOTS_ON_LEVEL_ZERO; fileTreeROOT.totalChunkNumber += SIMULFS_FILETREE_SLOTS_ON_LEVEL_ZERO; chunkNumber %= SIMULFS_DEFAULT_FILE_CHUNK; } while(chunkNumber%SIMULFS_DEFAULT_FILE_CHUNK != 0); return SIMULFS_OK; }
#ifndef _SIMULFS_FS_H_ #define _SIMULFS_FS_H_ #include "simulfs_objects.h" #include "simulfs_dlink.h" /* -------------------------- Object structure -------------------------------*/ /* object header ,used on RAM to search etc.*/ /* 這是用來在RAM上搜索的,暫時不用了 */ typedef struct _simulfs_ObjectHeader { __u32 objectId; // 原來的代碼中怎麼沒有objectId呢?很是不解 simulfs_ObjectType type; /* Apply to everything */ int parentObjectId; char name[SIMULFS_MAX_NAME_LENGTH + 1]; __u32 simulfs_object_tags; /* File size applies to files only */ int fileSize; } simulfs_ObjectHeader; /*------------------------ Object -----------------------------*/ /* An object can be one of: * - a directory (no data, has children links * - a regular file (data.... not prunes :->). * - a symlink [symbolic link] (the alias). * - a hard link */ typedef struct _simulfs_FileStructure { __u32 fileSize; int topLevel; // 文件的樹形結構頭層次 simulfs_FileTree top; // 指向頭的指針 } simulfs_FileStructure; /* * 使用一個雙端鏈表存儲文件夾內容 */ typedef struct _simulfs_DirectoryStructure { simulfs_List children; /* 鏈表中首個孩子結點,這個鏈表應該是既能連目錄也能文件 */ } simulfs_DirectoryStructure; typedef struct _simulfs_SymLinkStructure { char *alias; } simulfs_SymLinkStructure; typedef struct _simulfs_HardLinkStructure { struct simulfs_ObjectStruct *equivalentObject; __u32 equivalentObjectId; } simulfs_HardLinkStructure; typedef union _simulfs_ObjectVariant { simulfs_FileStructure fileVariant; simulfs_DirectoryStructure directoryVariant; simulfs_SymLinkStructure symLinkVariant; simulfs_HardLinkStructure hardLinkVariant; } simulfs_ObjectVariant; struct simulfs_ObjectStruct { __u8 dirty:1; /* the object needs to be written to flash */ /* Where's my object header in NAND? */ int chunkId; int nDataChunks; /* Number of data chunks attached to the file. */ __u32 objectId; /* the object id value */ simulfs_ObjectType variantType; simulfs_ObjectVariant variant; __u8 hasNewChunk:1; // 是否已經分配了新的chunk simulfs_Chunk newChunk; }; typedef struct simulfs_ObjectStruct simulfs_Object; /* * 這是文件句柄,返回的時候返回文件句柄 * 文件句柄存着很多東西 */ typedef struct _simulfs_fileHandler { simulfs_MixedId Ids; __u32 offset; // 利用Ids和offset找到文件當前偏移位置 simulfs_FileStructure* fileStructure; }simulfs_fileHandler; /* * ------------------------------------------------------------------------------------ * next are file system core interfaces * 1. directory * ----------------------------------------------------------------------------------- */ int directory_create(); int directory_parent(); int directory_child(); int directory_this(); int directory_retry(); int directory_delete(); /* * ------------------------------------------------------------------------------- * 2. file * ------------------------------------------------------------------------------- */ int file_create(); int file_truncate(); int file_increase(); int file_read(); int file_write(); int file_delete(); /* * ------------------------------------------------------------------------------- * 3. Symbol link * ------------------------------------------------------------------------------ */ int symlink_create(); int symlink_link(); int symlink_relink(); int symlink_delete(); /* * ---------------------------------------------------------------------------------- * 4. Hard link * --------------------------------------------------------------------------------- */ int hardlink_create(); int hardlink_link(); int hardlink_relink(); int hardlink_delete(); #endif //_SIMULFS_FS_H_
/* * This file is the core implementation of the file system. * main : * 1. file * 2. directory */ #include <stdlib.h> #include <string.h> #include "simulfs_fs.h" #include "simulfs_dlink.h" #include "simulfs_CSTree.h" #include "simulfs_FileTree.h" #include "simulfs_objects.h" #include "simulfs_marcos.h" /* * ------------------------------------------------------------------------------------ * next are file system core interfaces * 1. directory * ----------------------------------------------------------------------------------- */ // 傳入的是當前目錄,要得到的值是在這個目錄下的一個新目錄的指針 // 整個文件系統初始化的時候應該自動建立一個根目錄 simulfs_DirectoryStructure* directory_create(simulfs_DirectoryStructure* thisDir) { simulfs_DirectoryStructure* newDir = (simulfs_DirectoryStructure*)calloc(1, sizeof(simulfs_DirectoryStructure)); // 設置新目錄屬性 newDir->children->dataPtr = NULL; newDir->children->leftChild = NULL; newDir->children->nextSlibing = NULL; newDir->children->parent = thisDir->children; newDir->children->priorSlibing = NULL; newDir->children->thisFlag = 0x01; newDir->children->objectNumber = 0; SetMixedIdInvailed(newDir->children->thisId); // 設置當前目錄屬性 simulfs_InsertListNodeonEnd(thisDir->children, newDir->children); // 返回新目錄 return newDir; } // 尋找其父目錄 simulfs_DirectoryStructure* directory_parent(simulfs_DirectoryStructure* thisDir) { simulfs_DirectoryStructure* newDir = (simulfs_DirectoryStructure*)calloc(1,sizeof(simulfs_DirectoryStructure)); newDir->children = thisDir->children; return newDir; } // 列出其孩子 simulfs_DirectoryStructure** directory_child(simulfs_DirectoryStructure* thisDir) { simulfs_DirectoryStructure** newObjs = (simulfs_DirectoryStructure**) calloc(thisDir->children->objectNumber,sizeof(simulfs_DirectoryStructure*)); simulfs_ListNode* newLND; newLND = thisDir->children->leftChild; // 指向了他的左孩子 int i = 0; for(i=0; i< thisDir->children->objectNumber; ++i) { newObjs[i] = (simulfs_DirectoryStructure*)calloc(1,sizeof(simulfs_DirectoryStructure)); newObjs[i]->children = newLND; newLND = newLND->nextSlibing; } return newObjs; } // 檢索目錄,這個應該遞歸到各個目錄直至底層 int directory_retry(simulfs_DirectoryStructure* thisDir, int (*Visit)(simulfs_DirectoryStructure* dir)) { simulfs_ListNode* newLnd = thisDir->children->leftChild; simulfs_DirectoryStructure ADir; while(newLnd != NULL) { if(newLnd->obj.variantType == SIMULFS_OBJECT_TYPE_DIRECTORY) { ADir.children = newLnd; directory_retry(&ADir, Visit(simulfs_DirectoryStructure* dir)); } else { // 檢測到一個文件呢 具體要做什麼麼? } } } // 刪除掉這個目錄,既要刪除這個目錄的所有東西 // 先刪除該目錄的其他文件、文件夾,最後再刪除該文件加自身 int directory_delete(simulfs_DirectoryStructure* thisDir) { // 1. 刪除掉該文件夾的其他部分,可以使用retry函數嗎?先不用了 simulfs_ListNode* newLnd = thisDir->children->leftChild; simulfs_ListNode* newLndTmp = NULL; simulfs_DirectoryStructure ADir; while(newLnd != NULL) { if(newLnd->obj.variantType == SIMULFS_OBJECT_TYPE_DIRECTORY) { ADir.children = newLnd; // 1.1 遞歸下去刪除 directory_delete(&ADir); // 1.2 刪除自身 newLndTmp = newLnd->nextSlibing; free(newLnd); newLnd = newLndTmp; } else { // 檢測到一個文件 刪除之 simulfs_DestoryFileTree(*((simulfs_FileTree*)newLnd->dataPtr)); newLndTmp = newLnd->nextSlibing; free(newLnd); newLnd = newLndTmp; } } } /* * ------------------------------------------------------------------------------- * 2. file * ------------------------------------------------------------------------------- */ /* * 創建文件,很簡單,就是申請一個相應的文件結構,掛載到目錄下就行了。char* path * 這裏的路徑就先不用字符串了,直接用這個指針不就行了。 * 乾脆就不要文件名了 */ int file_create(simulfs_DirectoryStructure* path) { simulfs_FileStructure* newFile = (simulfs_FileStructure*)calloc(1, sizeof(simulfs_FileStructure)); newFile->topLevel = 0; newFile->fileSize = 0; return simulfs_CreateFileTree(&(newFile->top)); } /* * 打開函數應該是最終要的,但是是否要再創建一個句柄結構? * 返回值應該是一個句柄,打開就先用句柄模擬吧 */ simulfs_fileHandler file_open(simulfs_DirectoryStructure* path,__u32 objectId) { simulfs_fileHandler resHandle; resHandle.Ids = 0; resHandle.fileStructure = NULL; resHandle.offset = 0; simulfs_List* next = path->children->leftChild; while(next != NULL) { // 如果找到這樣一個文件,製造並返回句柄 if(next->obj.objectId == objectId) { resHandle.Ids = next->obj.chunkId; // 這個chunkId是元數據所在的id resHandle.fileStructure = &(next->obj.variant.fileVariant); resHandle.offset = 0; // 首個偏移位置設爲0 return resHandle; } next = next->nextSlibing; } return resHandle; // 如果查找失敗,就返回一個空句柄 } /* * 截斷的這個很難做,不知道到底要做成什麼樣子的 * 要不就只留出接口來吧,其他的再說。 */ int file_truncate(char* path, char* filename) { } /* * 同上 不知道怎麼入手 */ int file_increase(char* path, char* filename) { } /* * 文件讀操作,當然是直接寫到緩衝區內,大小要分配出來 * 傳入的buf要由應用程序保證空間區域的可靠,大小要大於等於size */ int file_read(simulfs_fileHandler fHandle, void* buf, __u32 size) { if(buf == NULL || fHandle.fileStructure == NULL) return SIMULFS_FAIL; simulfs_ReadPerChunk()使用這個函數 需要的filetree提供下一個塊的函數,即nextChunk } /* * 文件的寫操作,傳入的也是句柄 */ int file_write(simulfs_fileHandler fHandle, void* buf, __u32 size) { } /* * 文件的刪除,其實在simulfs_DestoryFileTree() 函數中已經有了,這裏直接調用就可以 */ int file_delete(simulfs_fileHandler fHandle) { } /* * ------------------------------------------------------------------------------- * 3. Symbol link * ------------------------------------------------------------------------------ */ int symlink_create(); int symlink_link(); int symlink_relink(); int symlink_delete(); /* * ---------------------------------------------------------------------------------- * 4. Hard link * --------------------------------------------------------------------------------- */ int hardlink_create(); int hardlink_link(); int hardlink_relink(); int hardlink_delete();
繼續運行 🥋 回憶上次內容 上上次 真寫了 萬行 代碼 這 萬行 代碼 都是寫在 明面 上的 這次 使用git命令 下載了 github上面的倉庫
Java將List結果分成3份執行 在Java編程中,有時候我們需要將一個List集合中的元素分成幾部分進行處理。這種情況下,我們可以使用Java的相關類庫和API來實現這一需求。在本文中,我們將介紹如何使用Java將List結果分成3份執
前端面試題 - vue的雙向綁定原理是什麼? vue2的雙向數據綁定是通過數據劫持結合發佈者訂閱者模式的方式來實現。 通過object.defineProperty來劫持各個屬性的setter,getter,在數據變化時發佈消息給訂閱者,
原方法 /** * 動態更新form * @param form */ updateForm(form) { this.form.manholeId = form.manholeId; this.form
這個其實是一個特別高頻的面試題,松哥也一直很想和大家仔細來聊一聊這個話題,網上關於這塊的文章很多,但是我一直覺得要把這個問題講清楚還有點難度,今天我來試一試,看能不能和小夥伴們把這個問題梳理清楚,當然,如果小夥伴們覺得看文章不過癮,松哥也有
分享8個開箱即用的API,方便日常處理集合。 1. 快速過濾空值:Stream.ofNullable 該方法是在 Java 9 中引入的,有助於過濾集合中的所有空值,從而可能使我們避免空指針異常。 在下面的示例中,有一個包含 null 的L
一、背景 在日常部門OpsReview過程中,部門內多次遇到應用容器所在的宿主機磁盤繁忙導致的接口響應緩慢,TP99增高等影響服務性能的問題,其中比較有效的解決方案是開啓日誌的異步打印,可以有效避免同步日誌打印在磁盤IO高起的情況下拖慢業
本文分享自華爲雲社區《【MySQL技術專欄】MySQL8.0直方圖介紹》,作者:GaussDB 數據庫。 背景 數據庫查詢優化器負責將SQL查詢轉換爲儘可能高效的執行計劃,但因爲數據環境不斷變化導致優化器對查詢數據瞭解的不夠充足,可能無法
每篇一句 大魔王張怡寧:女兒,這堆金牌你拿去玩吧,但我的銀牌不能給你玩。你要想玩銀牌就去找你王浩叔叔吧,他那銀牌多 前言 爲了講述好Spring MVC最爲複雜的數據綁定這塊,我前面可謂是做足了功課,對此部分知識此處給小夥伴留一個學
作者:vivo 互聯網數據庫團隊- Qiu Xinbo 本文主要通過圖示介紹了用主鍵進行分片查詢的過程,介紹了主鍵分頁查詢存在SQL性能問題,如何去創建高效的索引去優化主鍵分頁查詢的SQL性能問題 對於數據分佈不均
JSON簡介: JSON(Java Script Object Notation)是一種輕量級的數據交換格式,通常用於在不同系統之間傳輸數據。它基於 JavaScript 對象語法,但已成爲一種獨立於語言的格式。JSON 數據以鍵值對的形式
一、簡單介紹: CaffeineCache和Guava的Cache是應用廣泛的本地緩存。 在開發中,爲了達到降低依賴、提高訪問速度的目的。會使用它存儲一些維表接口的返回值和數據庫查詢結果,在有些場景下也會在分佈式緩存上再加上一層本地緩存,
作者:vivo 互聯網大前端團隊 - Ma Lian 本文主要描述了FileProvider,startAnyWhere實現,Parcel不對稱漏洞以及這三者結合產生的漏洞利用實戰,另外闡述了漏洞利用的影響和修復預防措施,這個漏洞波及了
本文分享自華爲雲社區《GaussDB SQL基本語法示例-CASE表達式》,作者:Gauss松鼠會小助手2。 一、前言 SQL是用於訪問和處理數據庫的標準計算機語言。GaussDB支持SQL標準(默認支持SQL2、SQL3和SQL4的主要
Impala目前支持Hadoop中幾種常見的文件格式 Parquet 、 ORC 、 Text 、 Avro 、 RCFile 和 SequenceFile 。下面簡要說明各種格式的使用、限制和一些注意事項。 不同的文件格式有着不同的適用場