디렉토리
날새게 날려가요 햄토리
챗바퀴를 돌려봐요 햄토리
제일 좋아하는건~ 닭도리
아싸라비야 고도리
맨손으로 때려잡은 북경오리
이건 너와 나의 연결고리
....
디렉토리 공부를 시작하자
/* A directory. */
struct dir
{
struct inode *inode; /* Backing store. */
off_t pos; /* Current position. */
};
directory 구조체이다. 이것만 봐서는 뭘 말하는건지 모르겟다.
단지 inode를 가지고 있을 뿐이다. inode_sector가 아니라 inode를 가리키는 거 보니 이것도 memory에 올리는 놈인가?
/* A single directory entry. */
struct dir_entry
{
disk_sector_t inode_sector; /* Sector number of header. */
char name[NAME_MAX + 1]; /* Null terminated file name. */
bool in_use; /* In use or free? */
};
이것은 directory의 entry이다.
inode_sector와 (file) name 을 가지고 있다.
얘가 file을 직접적으로 가리키고 있을 것이다.
/* Creates a directory with space for ENTRY_CNT entries in the
* given SECTOR. Returns true if successful, false on failure. */
bool dir_create(disk_sector_t sector, size_t entry_cnt)
{
return inode_create(sector, entry_cnt * sizeof(struct dir_entry));
}
주어진 sector와 entry_cnt로 directory를 하나 만든다.
실제로 실행하는 것은 inode_create()가 실행한다. 이 말은, 주어진 sector부터 entry 개수 * entry 사이즈 만큼을 할당받는다는 것이다. 아직은 감이 잘 안온다. 이것을 어떻게 읽어오는 것일까.
/* Opens and returns the directory for the given INODE, of which
* it takes ownership. Returns a null pointer on failure. */
struct dir *
dir_open(struct inode *inode)
{
struct dir *dir = calloc(1, sizeof *dir);
if (inode != NULL && dir != NULL)
{
dir->inode = inode;
dir->pos = 0;
return dir;
}
else
{
inode_close(inode);
free(dir);
return NULL;
}
}
인자로 받은 inode가 속해있는 directory를 연다.
dir만큼의 메모리 공간을 할당받고, 성공했다면 이 dir에 inode를 기입한다.
pos는 무엇을 말하는 것일까?
/* Opens the root directory and returns a directory for it.
* Return true if successful, false on failure. */
struct dir *
dir_open_root(void)
{
return dir_open(inode_open(ROOT_DIR_SECTOR));
}
루트 디렉토리를 열고, 이에 해당하는 dir을 반환한다. 즉, 이 파일을 실행하면 dir를 가지고, 이 dir은 ROOT_DIR_SECTOR를 열 수 있다.
이 말인 즉슨, ROOT_DIR_SECTOR 에는 inode가 있고, dir은 이 inode를 가지게된다는 것인데, 나는 아직 ROOT_DIR_SECTOR 에 뭘 한 적이 없다. 이 친구가 어떤식으로 구성되는 것일까.
/* Opens and returns a new directory for the same inode as DIR.
* Returns a null pointer on failure. */
struct dir *
dir_reopen(struct dir *dir)
{
return dir_open(inode_reopen(dir->inode));
}
dir를 다시 연다.
inode_reopen은 인자로 받은 inode에서 inode->open_cnt만 올려준다. 이러면 다른 곳에서 inode_close()를 실행해도 별 영향 없을 것이다.
/* Destroys DIR and frees associated resources. */
void dir_close(struct dir *dir)
{
if (dir != NULL)
{
inode_close(dir->inode);
free(dir);
}
}
dir를 닫는다.
실제로는 dir이 가지고 있는 inode를 닫는 것이다.
/* Returns the inode encapsulated by DIR. */
struct inode *
dir_get_inode(struct dir *dir)
{
return dir->inode;
}
dir가 가지고 있는 inode를 가지고온다.
/* Searches DIR for a file with the given NAME.
* If successful, returns true, sets *EP to the directory entry
* if EP is non-null, and sets *OFSP to the byte offset of the
* directory entry if OFSP is non-null.
* otherwise, returns false and ignores EP and OFSP. */
static bool
lookup(const struct dir *dir, const char *name,
struct dir_entry *ep, off_t *ofsp)
{
struct dir_entry e;
size_t ofs;
ASSERT(dir != NULL);
ASSERT(name != NULL);
for (ofs = 0; inode_read_at(dir->inode, &e, sizeof e, ofs) == sizeof e;
ofs += sizeof e)
if (e.in_use && !strcmp(name, e.name))
{
if (ep != NULL)
*ep = e;
if (ofsp != NULL)
*ofsp = ofs;
return true;
}
return false;
}
인자로 받은 name을 가지고 있는 dir를 찾는 것이다.
만약 찾는 것에 성공했다면 ep를 해당 dir_entry로 지정한다.
함수를 뜯어보자. 우선 빈 dir_entry를 하나 마들고, dir의 inode에서 (정확히는 inode_disk가 가리키는 곳) 읽는다.
그곳에는 dir_entry가 차곡차곡 쌓여져 있을 것이기 때문에, 가장 밑에서부터 dir_entry를 읽는다. (ofs이 현재 위치이다.)
그래서 한개씩 꺼내본다. 만약 사용되고 있는 dir_entry이고, strcmp()로 dir_entry의 name과 인자name이 같은지 비교해본다.
그래서 같다면 ep는 현재 e를 가리키게 하고, ofsp가 현재 ofs를 가리키게 한다.
/* Searches DIR for a file with the given NAME
* and returns true if one exists, false otherwise.
* On success, sets *INODE to an inode for the file, otherwise to
* a null pointer. The caller must close *INODE. */
bool dir_lookup(const struct dir *dir, const char *name,
struct inode **inode)
{
struct dir_entry e;
ASSERT(dir != NULL);
ASSERT(name != NULL);
if (lookup(dir, name, &e, NULL))
*inode = inode_open(e.inode_sector);
else
*inode = NULL;
return *inode != NULL;
}
이 친구도 file을 찾는 것인데 위와 뭐가 다를까.
lookup은 현 dir에 name을 가진 file이 있는지 bool을 반환하지만,
dir_lookup은 현 dir에 해당 file이 있는지를 보고 있으면, 인자 inode에 해당 inode를 새긴다.
/* Adds a file named NAME to DIR, which must not already contain a
* file by that name. The file's inode is in sector
* INODE_SECTOR.
* Returns true if successful, false on failure.
* Fails if NAME is invalid (i.e. too long) or a disk or memory
* error occurs. */
bool dir_add(struct dir *dir, const char *name, disk_sector_t inode_sector)
{
printf("---DEBUG // dir_add // inode_sector : %d\n", inode_sector);
struct dir_entry e;
off_t ofs;
bool success = false;
ASSERT(dir != NULL);
ASSERT(name != NULL);
/* Check NAME for validity. */
if (*name == '\0' || strlen(name) > NAME_MAX)
return false;
/* Check that NAME is not in use. */
if (lookup(dir, name, NULL, NULL))
goto done;
/* Set OFS to offset of free slot.
* If there are no free slots, then it will be set to the
* current end-of-file.
* inode_read_at() will only return a short read at end of file.
* Otherwise, we'd need to verify that we didn't get a short
* read due to something intermittent such as low memory. */
for (ofs = 0; inode_read_at(dir->inode, &e, sizeof e, ofs) == sizeof e;
ofs += sizeof e)
{
if (!e.in_use)
{
break;
}
}
/* Write slot. */
e.in_use = true;
strlcpy(e.name, name, sizeof e.name);
e.inode_sector = inode_sector;
success = inode_write_at(dir->inode, &e, sizeof e, ofs) == sizeof e;
done:
return success;
}
dir에다가 dir_entry를 추가하는 함수이다. 여기서 다시 둘의 차이를 정의하고 가자.
dir은 inode를 가지고 있다. 이 inode는 다시 어느 sector를 가리키고 있을 것이다.
dir_entry는 작은 구조체이다. dir_entry는 파일 하나를 가리키고 있으며 sector에는 이 파일의 inode가 있는 sector, name에는 이 file의 name, in_use는 dir_entry가 현재 사용되고 있는지 아닌지를 검사하는 bool이다.
그럼 시작해보자.
우선 이름의 유효성 검사를 하고, 이 이름을 가지고 있는 dir_entry가 dir안에 있는지 본다.
없을 때, 다음으로 진행할 것이다.
for문으로 dir에서 비어있는 dir_entry를 하나 가져온다.
우선 in_use를 true로 하고, name을 새겨놓는다.
마지막으로, 작성한 entry를 원래 자리(disk 상의)에 복사한다.
/* Removes any entry for NAME in DIR.
* Returns true if successful, false on failure,
* which occurs only if there is no file with the given NAME. */
bool dir_remove(struct dir *dir, const char *name)
{
struct dir_entry e;
struct inode *inode = NULL;
bool success = false;
off_t ofs;
ASSERT(dir != NULL);
ASSERT(name != NULL);
/* Find directory entry. */
if (!lookup(dir, name, &e, &ofs))
goto done;
/* Open inode. */
inode = inode_open(e.inode_sector);
if (inode == NULL)
goto done;
/* Erase directory entry. */
e.in_use = false;
if (inode_write_at(dir->inode, &e, sizeof e, ofs) != sizeof e)
goto done;
/* Remove inode. */
inode_remove(inode);
success = true;
done:
inode_close(inode);
return success;
}
dir에서 name을 가진 file을 지운다.
우선 dir에 name을 가진 entry가 있는지를 봐야될 것이다.
만약 있다면 inode를 열고, entry를 지운다.
지우는 동작은 in_use를 false로 바꾸고, 원래대로 돌려놓는다.
그리고 inode를 삭제한다.
/* Reads the next directory entry in DIR and stores the name in
* NAME. Returns true if successful, false if the directory
* contains no more entries. */
bool dir_readdir(struct dir *dir, char name[NAME_MAX + 1])
{
struct dir_entry e;
while (inode_read_at(dir->inode, &e, sizeof e, dir->pos) == sizeof e)
{
dir->pos += sizeof e;
if (e.in_use)
{
strlcpy(name, e.name, NAME_MAX + 1);
return true;
}
}
return false;
}
몰라 안해
+++++++++++ 3/5 ++++++++++++
다시 한번 dir와 dir_entry에 대해 정리하고 가자.
어제 자기전에 생각하다가 헷갈리는 부분이 있었다.
/* Opens and returns the directory for the given INODE, of which
* it takes ownership. Returns a null pointer on failure. */
struct dir *
dir_open(struct inode *inode)
{
struct dir *dir = calloc(1, sizeof *dir);
if (inode != NULL && dir != NULL)
{
dir->inode = inode;
dir->pos = 0;
return dir;
}
else
{
inode_close(inode);
free(dir);
return NULL;
}
}
우선 dir_open() 을 보면, dir은 calloc으로 선언하고, inode를 그 안에 집어넣는다. 즉, inode는 어딘가에서 가져오다는 뜻이다.
즉, file이나 directory나 데이터의 집합이고, 이 데이터의 집합은 inode가 관리한다는 것은 같다.
dir은 inode를 가리키고, 이 inode는 dir_entry가 쌓여있는 실제 데이터를 가리키는 것이다. dir_entry는 file (의 inode)을 가리키고 있다. dir_entry들을 구분하기 위해서 name을 사용하고, 우리가 file에 이름을 짓는 것은 dir_entry에 있는 name을 말하는 것이다. dir_entry는 file을 대표하고 있다고 해도 되는 것이다.
아직은 sub_directory가 구현되어있지 않으니, 현재 우리가 다루는 file은 모두 root_dir에 dir_entry의 형태로 들어가있을 것이다.
그렇다면, 여기서 드는 의문은 root_dir은 1로 지정되어있다. 이 때, root_dir inode여야하고, 실제 dir_entry가 들어있는 곳은 sector no.1 이 아닐 것인데, 어디에 들어있는 것인가?
이걸 수정하거나 추가해야할 것 같다.
생각을 해보자.
일단 root_dir 자체는 확보되어있다 (1). 그렇다면 dir_entry를 넣을 공간을 마련해줘야한다.
이걸 어느단계에서 해야될까.
/* Formats the file system. */
static void
do_format (void) {
printf ("Formatting file system...");
#ifdef EFILESYS
/* Create FAT and save it to the disk. */
fat_create ();
fat_close ();
#else
free_map_create ();
if (!dir_create (ROOT_DIR_SECTOR, 16))
PANIC ("root directory creation failed");
free_map_close ();
#endif
printf ("done.\n");
}
찾아보니 free-map의 경우(기존 시스템의 경우), filesys.c에서 root_dir_sector를 만들어줬었다.
이거를 똑같이 넣어주자.
/* Formats the file system. */
static void
do_format (void) {
printf ("Formatting file system...");
#ifdef EFILESYS
/* Create FAT and save it to the disk. */
fat_create ();
/* ---------------------------- >> Project.4 FAT >> ---------------------------- */
if (!dir_create (ROOT_DIR_SECTOR, 16))
PANIC ("---ERROR // do_format // ROOT_DIR CREATION FAILED\n");
/* ---------------------------- << Project.4 FAT << ---------------------------- */
fat_close ();
#else
free_map_create ();
if (!dir_create (ROOT_DIR_SECTOR, 16))
PANIC ("root directory creation failed");
free_map_close ();
#endif
printf ("done.\n");
}
이렇게하고 돌린 결과, project 1, 2, 3은 전부 통과하는 것 같다. (3의 fork와 merge는 간간히 터지고 있는 상황)
이제 file growth를 해보자
'Pintos Project > Project 4' 카테고리의 다른 글
[PintOS, Project 4] Buffer Cache (0) | 2021.03.06 |
---|---|
[PintOS, Project 4] File Growth 구현 (1) | 2021.03.05 |
[PintOS, Project 4] Filesys.c 구현 (0) | 2021.03.04 |
[PintOS, Project 4] inode.c 구현 (0) | 2021.03.04 |
[PintOS, Project 4] fat.c 구현 (0) | 2021.03.04 |
댓글