Linux

[Linux] 하드링크, 심볼릭링크

개발로 먹고 살자 2022. 8. 5. 14:56

오늘은 링크에 대해서 작성해보겠다.

리눅스에는 링크라는 것이 존재하는데 쉽게 말하자면 바탕화면의 바로가기를 떠올리면 된다.

 

우리가 다운받은 파일이 예를 들어 C드라이브에 존재하지만 바탕화면에 설치된 링크를 통해

손쉽게 들어갈 수 있다.

 

A의 위치에 저장되어 있는 실행 파일을 B의 위치에서 실행시키는 것

이것이 우리가 알고 있는 링크의 개념이다.

 

링크는 하드링크심볼릭링크로 나뉘어진다. 심볼릭링크는 소프트링크라고 하기도 한다.

 

이 둘의 차이는 무엇일까?

위의 예시처럼 A의 위치에 저장되어 있는 실행 파일을 바로가기처럼 주소만 링크시킨 것이

심볼릭 링크이고, 원본과 직접적으로 연결되어 있는 것이 하드링크이다.

 

어떠한 경우에 이 둘을 사용할까?

 

심볼릭 링크는 기존 파일에 접근할 수 있는 다른 파일을 만든다. 기존 파일과 다른 i-node를 사용하며

기존 파일의 경로를 저장한다. 일반적으로 지정 경로를 단축하기 위해 사용하는 경우가 있다.

 

리눅스에서 만약 log 파일을 이용하고 싶을 때 경로를 /var/log를 통해 들어가야한다.

하지만 내가 원하는 위치에서 log를 링크시켜 놓는다면 원하는 위치에서 log를 실행시킬 수 있다.

 

 

하드 링크의 경우 주소 심볼릭 링크와 같이 주소만 링크시킨 것이 아닌 원본 데이터를

복사와 같은 형태로 링크하기 때문에 원본 파일과 동일한 내용의 다른 파일이라 할 수 있다.

 

파일에 접근할 수 있는 파일명을 새로 생성하는 것으로 기존 파일과 동일한 i-node를 사용한다.

그렇기 때문에 하드링크를 걸어 파일을 생성하게 되면 원본 파일이 삭제되더라도 하드 링크를

해놓은 파일은 그대로 남아있게 되는 것이다.

 

디렉토리 및 파일은 개별적인 i-node 번호를 가지고 있다. 이 번호를 기준으로 관리가 되어지는데

만약 A라는 파일의 i-node 번호가 100이라면 심볼릭 링크로 만든다면 심볼릭 링크 파일은

101이라는 번호를 부여받게 된다. 우리가 아는 바로가기도 100이라는

i-node 번호를 가리키는 101번 파일을 실행시키는 것이다.

 

하지만 i-node 번호가 100이라는 파일을 하드 링크로 만든다면

하드 링크 파일의 i-node 번호는 100이다.

100이라는 i-node 번호를 가지는 파일이 두 개가 되는 것이다.

 

 

파일의 기본적인 형태인데 원본 파일에 있는 i-node가 정보와 데이터의 위치를 가지고 있다.

그렇기 때문에 파일이 i-node만 가지고 있다면 정보와 데이터의 위치를 알 수 있는 것이다.

 

이 파일에 소프트 링크를 건다면 어떻게 될까?

소프트 링크                 원본 파일

 

소프트 링크를 이용하면 원본 파일의 i-node 200을 가리키는, 기존 파일에 접근할 수 있는

다른 파일을 만든다. 이 때 소프트 링크의 i-node는 원본과 다른 i-node를 가지고 있다.

원본 파일이 사라지게 될 경우 가리키는 i-node가 사라지기 때문에 소프트 링크 또한

사용할 수 없게 된다. i-node를 알 수 없기 때문에 데이터의 위치를 알 수 없기 때문이다.

 

 

하드 링크의 경우는 어떨까?

하드링크                      원본 파일

 

하드 링크는 원본과 직접적으로 연결되기 때문에 원본의 i-node와 같은 i-node를 가지고 있다.

같은 i-node를 가지고 있기 때문에 원본 파일을 수정할 경우 하드 링크의 파일 또한 수정이 된다.

반대로 하드 링크 파일을 수정해도 원본 파일이 변경된다.

그렇기 때문에 협업을 할 때 원본 파일을 놔두고 하드 링크 파일을 통해 수정하여 개발하게 된다. 

 

여기서 원본을 삭제하게 되더라도 하드 링크의 i-node가 원본과 같은 i-node를 가지고

있기 때문에 데이터의 위치를 알 수 있어 하드 링크로도 데이터에 접근이 가능하게 된다.

 

 

링크를 생성하는 명령어는 ln을 통해 생성할 수 있다.

옵션 없이 ln을 사용하게 될 경우 하드 링크가 생성되고,

-s 옵션을 작성할 경우 심볼릭 링크를 생성한다.

 

ln 사용법

ln [option] 원본 파일 링크 파일

 

예시

ln a.txt b.txt

a.txt라는 파일의 하드 링크 파일을 b.txt 라는 이름으로 생성한다.

 

ln -s a.txt b.txt

a.txt라는 파일의 심볼릭 링크 파일을 b.txt 라는 이름으로 생성한다.

 

현재 link.c와 symlink.c 라는 파일이 존재한다.

 

 

하드 링크

link.c를 link 하드 링크로 생성하면 link 라는 하드 링크 파일이 생기게 된다.

 

여기서 ls -il 명령어로 확인을 해보면 link와 link.c의 i-node가 543926으로

동일한 i-node를 가지고 있는 것을 볼 수 있다. 파일의 크기 또한 399로 똑같은 것을 볼 수 있다.

 

 

심볼릭 링크

symlink.c 파일을 -s 옵션을 주어 symlink 라는 심볼릭 링크를 만들었다.

확인을 해보면 하늘색으로 표시되는 것을 볼 수 있다.

 

심볼릭 링크는 ls -il 명령어로 확인을 해보면 symlink.c와 symlink의 i-node가

다른 것을 볼 수 있다.

 

또한 심볼릭 링크는 symlink -> symlink.c 와 같이 심볼릭 링크의 포인터가

원본 파일을 가리킨다는 사실을 알 수 있다.

 

 

이번엔 직접 파일을 만들어 링크를 생성해보겠다.

 

하드 링크

우선 하드 링크를 만들었다.

원본 파일을 기준으로 하드 링크 파일을 만든 후

만들기 전과 후의 링크 수를 비교하는 것이다.

 

a.txt의 링크 수는 1개 노드는 512207이다. ls -il을 통해 확인을 해보아도 똑같은 것을 알 수 있다.

여기서 a.txt를 이용해 하드 링크를 만들면 어떻게 될까?

 

a.txt 파일을 하드 링크한 b.txt라는 파일을 만들어보니 link의 개수가 2개로 변경된 것을 알 수 있다.

또한 a.txt와 b.txt의 i-node가 같은 것도 확인할 수 있다.

 

전체 소스 코드

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/stat.h>

int main(int argc, char* argv[]) {

	struct stat statbuf;

	stat(argv[1], &statbuf);
	printf("before link count = %d\n", (int)statbuf.st_nlink);

	link(argv[1], argv[2]);

	stat(argv[1], &statbuf);
	printf("after link count = %d\n", (int)statbuf.st_nlink);
	printf("Inode = %d\n", (int)statbuf.st_ino);

	return 0;
}

 

 

심볼릭 링크

심볼릭 링크를 만들었다.

원본 파일을 기준으로 심볼릭 링크 파일을 만든 후

하드 링크와 같이 만들기 전과 후의 링크 수를 비교하는 것이다.\

 

여기서 주의할 점은 심볼릭 링크는 stat가 아닌 lstat를 통해 확인을 해야한다.

심볼릭 링크를 stat로 검색하면 원본 파일에 대한 정보가 검색되기 때문이다.

lstat는 심볼릭 링크 자체의 파일 정보를 검색한다.

 

stat와 lstat의 차이점은

stat는 지정한 파일이 심볼릭 링크인 경우에는 링크를 따라가서

원본 파일의 정보를 전달하지만 lstat는 지정한 파일이 심볼릭 링크인 경우에

링크 파일 자체의 정보를 전달한다.

 

하드 링크와 똑같은 방법으로 심볼릭 링크도 하나 만들었다.

하지만 하드 링크와는 다른 결과가 나온다. link의 개수는 하드 링크처럼 2개가 되는 것이

아니라 1개가 된다. i-node 또한 원본 파일과 다른 i-node를 가지고 있는 것을 볼 수 있다.

 

전체 소스 코드

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/stat.h>

int main(int argc, char* argv[]) {

	struct stat statbuf;

	stat(argv[1], &statbuf);
	printf("before link count = %d\n", (int)statbuf.st_nlink);

	symlink(argv[1], argv[2]);

	lstat(argv[1], &statbuf);
	printf("after link count = %d\n", (int)statbuf.st_nlink);
	printf("Inode = %d\n", (int)statbuf.st_ino);

	return 0;
}