하드 링크
-
리눅스에는 하나의 파일에 두 개 이상의 이름을 지정할 수 있다. 이를 위해서 링크라는 개념이 존재하는데 이를 하드 링크라고 부르기도 한다.
-
링크란 파일에 새로운 이름을 붙이는 것이다. 예를 들면 다음과 같이 A 라는 파일을 만들었다고 가정을 하자.
echo 'this is a file.' > a
-
이때 파일의 이름과 실체의 관계는 이름이 실체를 포인터처럼 가리키고 있는 모습이다.
-
여기서 파일 A의 실체에 새로운 이름 B를 붙여보자. 이때 사용하는 명령어가 바로
ln
이다.
ln a b
-
이 작업은 파일 A를 가리키는 하드 링크 B를 만드는 것이다.
-
이후에 A의 내용을 변경하면 B의 내용도 동일하게 변경된다. 왜냐하면 A와 B는 같은 것을 가리키고 있기 때문이다.
-
파일에 부여된 이름의 개수는
ls -l
를 사용하여 확인할 수 있다. 이름이 하나만 있는 파일을ls
명령어로 표시하면 다음과 같이 출력 된다.
rm -f a b
-
왼쪽에서 두 번째 란이 이름의 개수를 의미한다. 이것을 링크 카운터라고 한다. 현재 링크 카운터가 두 개인 것을 확인할 수 있고 양쪽 다 모두 2개인 것을 확인할 수 있는데 링크 카운터는 실체에 기록되기 때문이다.
-
한편, 이름을 삭제하려면
rm
명령어를 사용한다. -
rm
이 파일을 제거하는 명령어라고 인식하기 쉽지만, 사실은rm
이 삭제하는 것은 파일이 아닌 파일의 이름이다. 실체를 가리키는 이름이 모두 없어진 시점에서, 즉 링크 카운트가 0이 되었을 때 비로소 실체가 삭제된다.
rm
에 의해서 링크 카운터가 다시 1로 되돌아 간 것을 확인할 수 있다.
link(2)
- 하드 링크를 작성하는 시스템 콜이
link(2)
이다.
#include <unistd.h>
int link(const char *src, const char *dest);
-
link()
는src
로 지정한 파일에 새로운 이름dest
를 추가한다. 두 번째 인자가 새로 만들 이름이라는 점에 유의하기 바란다. -
성공하면 0을 반환하고 실패하면 -1을 반환하면서
errno
를 설정한다. -
한편,
link()
에는 다음과 같은 중요한 제약이 있다.
src
와dest
에는 동일한 파일 시스템에 있어야 한다. 양쪽 모두가 하나의 파일 시스템에 존재해야 한다.
src
와dest
에 디렉터리는 사용할 수 없다. 즉, 디렉터리에 하드 링크를 붙일 수 없다. 이 제한은 나중에 언급할 심볼릭 링크를 사용하여 해결할 수 있다.
ln 명령어 작성하기
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "%s: wrong arguments\n", argv[0]);
exit(1);
}
if (link(argv[1], argv[2]) < 0) {
perror(argv[1]);
exit(1);
}
exit(0);
}
ls -l
출력하는 항목 중 왼쪽에서 두 번재 열에 주목을 하면ln.c
의 링크 카운터가 2로 증가한 것을 확인할 수 있다.
심볼릭 링크
-
심볼릭 링크는 하드 링크처럼 파일의 실체에 새로운 이름을 붙이는 매커니즘이다.
-
그러나 그 구조는 하드 링크와 상당히 다르다. 하드 링크는 이름과 실체를 연결하는 구조이지만, 심볼링 링크는 이름에 이름을 연결하는 구조이다.
-
그리고 실제로 심볼릭 링크에 엑세스가 있을 때 비로소 이름의 실체를 찾는다.
-
그러나 심볼링 링크에는 다음과 같은 특징이 있다.
- 심볼릭 링크에는 대응하는 실체가 존재하지 않아도 된다. 심볼릭 링크는 실제로 액세스 할 때가 아니면 이름의 실체의 맵핑을 하지 않기 때문에 실체가 없어도 만들 수 있다.
- 파일 시스템의 경계를 뛰어넘어서 별명을 붙일 수 있다. 하드 링크는 하나의 파일 시스템 내에서만 만들 수 있다는 제약이 있었다. 그러나 심볼릭 링크는 파일 시스템의 경계와 관계없이 만들 수 있다.
- 디렉터리에도 별명을 붙일 수 있다. 디렉터리에 대해서는 하드 링크는 만들 수 없지만 심볼릭 링크는 만들 수 있따.
- 현재는 하드 링크를 거의 사용하지 않고 파일에 별명을 붙이고 싶을 때는 심볼릭 링크를 사용하는 것 이 좋다.
symlink(2)
- 심볼릭 링크를 만드는 시스템 콜은
symlink(2)
이다.
#include <unistd.h>
int symlink(const char *src, const char *dest);
symlink()
는 지정한 경로에 대한 새로운 심볼릭 링크를 만든다. 성공하면 0을 반환하고 실패하면 -1을 반환하면서errno
를 설정한다.
readlink(2)
- 심볼릭 링크가 가리키는 이름을 얻기 위해
readlink(2)
를 사용한다.
#include <unistd.h>
int readlink(const char *path, char *buf, size_t bufsize);
-
readlink()
는 심볼릭 링크path
가 가리키는 이름을buf
에 담아준다. 이때 최대bufsize
바이트를 담아주며bufsize
는 보통의 크기로 지정한다. 또한readlink()
는 문자열의 마지막에\0
을 기록하지 않기 때문에 주의해야 한다. -
호출에 성공하면
buf
에 포함된 바이트 수를 반환한다. 실패하면 -1을 반환하면서errno
를 설정한다.
symlink
명령어 만들기
- 보통 리눅스에서 심볼릭 링크를 만들 때
ln -s
를 사용하는데, 여기서는 전용 명령어처럼 만들어 보기로 하겠다. 이름은symlink
이다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "%s: wrong number of arguments\n", argv[0]);
exit(1);
}
if (symlink(argv[1], argv[2]) < 0) {
perror(argv[1]);
exit(1);
}
exit(0);
}
- 심볼링 링크가 제대로 이루어진 것을 확인할 수 있고, 파일 목록을 조회하였을 때 화살표로 어떤 파일을 가리키는지 알려준다.