int open (const char *file);

첫번째 인자의 이름을 가진 파일을 오픈한 후 비음수 정수인 file descriptor (이하 fd)를 반환한다. fd 번호로 0번, 1번은 이미 역할이 정해져있으므로 (0: STDIN, 1: STDOUT) open 시스템콜이 이 두 번호를 리턴하는 일은 없다. 이 두 번호는 시스템콜을 호출할때의 인자로서만 유효하다.

🔎  file descriptor 유의할 점

위의 내용을 고려하여 fd 구조체를 생성한다.

struct fd
{
    int value;
    struct file *file;
    struct list_elem elem;
};

fd 구조체가 가져야 하는 멤버변수는 fd 값을 나타내는 value, 이 fd와 연결된 file을 나타내는 file, 그리고 fd 자체를 list로 관리해야 하기 때문에 필요한 list_elem 인 elem 이다.

이제 스레드 구조체 멤버변수를 수정한다. 프로세스가 오픈한 fd 들을 담는 fd_list를 추가하고, 다음 생성할 fd의 value를 계산하기 위해 현재 fd 값 중 최고 값을 보관하는 fd_count 값을 추가한다.(왜냐면 현재 최고 fd값이 n이라면 그 다음 fd값은 n+1이 될 것이기 때문)

/* thread.h 의 thread 구조체 */
...
struct list fd_list;
int fd_count;
...

이제 스레드 구조체를 수정했으니, 스레드를 시작할 때 fd_list를 init 하고, fd_count를 초기화 하는 코드를 추가한다.

t->fd_count = 1;
list_init(&t->fd_list);

fd 값은 2부터 시작해야 하기 때문에 (0,1 은 이미 사용처가 정해졌으니까) fd_count는 1로 초기화 하고, list_init을 통해 fd_list 리스트를 init 한다.

시스템콜 open이 호출되면 시스템콜 핸들러에 의해 실행되는 syscall_open 를 다룰 준비가 끝났다! file_open() 함수는 아래와 같이 정의된다.

int syscall_open (struct intr_frame *f){

	check_addr(f->R.rdi);

	struct list * fd_list;
	struct file *open_file;
	struct ELF64_hdr ehdr;

	fd_list = &thread_current()->fd_list;
	
	open_file = filesys_open(f->R.rdi);
	if(open_file == NULL){
		f->R.rax = -1;
		return -1;
	}
	
	struct fd *fd = (struct fd*)malloc(sizeof(struct fd));

	fd->value = thread_current()->fd_count + 1;
	fd->file = open_file;
	list_push_back(fd_list,&fd->elem);
	thread_current()->fd_count +=1;

	// open 시 해더파일을 읽어서 excutable 한 파일인지 확인
	if(!(file_read (fd->file, &ehdr, sizeof ehdr) != sizeof ehdr
		|| memcmp (ehdr.e_ident, "\\177ELF\\2\\1\\1", 7)
		|| ehdr.e_type != 2
		|| ehdr.e_machine != 0x3E // amd64
		|| ehdr.e_version != 1
		|| ehdr.e_phentsize != sizeof (struct ELF64_PHDR)
		|| ehdr.e_phnum > 1024)){
			file_deny_write(fd->file);
		}
	open_file->pos=0;
	f->R.rax = fd->value;
	return fd->value;
}