메타 정보 획득하기


  • 파일 시스템에는 데이터 외에도 다음과 같은 정보가 추가적으로 저장되어 있다.

    • 파일의 종류
    • 크기
    • 권한
    • 소유자
    • 그룹
    • 작성시간
    • 변경 시간
    • 액세스 시간

stat(2)

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

int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
  • stat()path로 지정한 엔트리 정보를 취득해서 buf에 써넣는다. 성공하면 0을 반환하고, 실패하면 -1을 반환하면서 errno를 설정한다.

  • lstat()stat()와 거의 같지만, path가 심볼릭 링크인 경우 해당 링크를 따라가지 않고 심볼릭 링크 자신의 정보를 반환한다는 점이 다르다.

  • 또한, 파일 디스크립터에서 동일한 정보를 얻을 수 있는 fstat()도 있다.

  • fstat()에 관해서는 man 페이지를 참고하면 자세히 나와 있다.

  • 리눅스 struct stat 구조체와 의미는 아래와 같다.

stat 명령어 만들기

  • 시스템 콜 stat()을 사용하여 stat 명령어를 만들어 볼 것이다.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>

static char *filetype(mode_t mode);

int main(int argc, char *argv[]) {
  struct stat st;

  if (argc != 2) {
    fprintf(stderr, "wrong argument\n");
    exit(1);
  }

  if (lstat(argv[1], &st) < 0) {
    perror(argv[1]);
    exit(1);
  }

  printf("type\t%o (%s)\n", (st.st_mode & S_IFMT), filetype(st.st_mode));
  printf("mode\t%o\n", st.st_mode & ~S_IFMT);
  printf("dev\t%llu\n", (unsigned long long)st.st_dev);
  printf("ino\t%lu\n", (unsigned long)st.st_ino);
  printf("rdev\t%lu\n", (unsigned long)st.st_rdev);
  printf("nlink\t%lu\n", (unsigned long)st.st_nlink);
  printf("uid\t%d\n", st.st_uid);
  printf("gid\t%d\n", st.st_gid);
  printf("size\t%ld\n", st.st_size);
  printf("blksize\t%ld\n", (unsigned long)st.st_blksize);
  printf("blocks\t%lu\n", (unsigned long)st.st_blocks);
  printf("atime\t%s", ctime(&st.st_atime));
  printf("mtime\t%s", ctime(&st.st_mtime));
  printf("ctime\t%s", ctime(&st.st_ctime));

  exit(0);
}

static char *filetype(mode_t mode) {
  if (S_ISREG(mode)) return "file";
  if (S_ISDIR(mode)) return "directory";
  if (S_ISCHR(mode)) return "chardev";
  if (S_ISBLK(mode)) return "blockdev";
  if (S_ISFIFO(mode)) return "fifo";
  if (S_ISLNK(mode)) return "symlink";
  if (S_ISSOCK(mode)) return "socket";
  return "unknown";
}

  • 실행 결과는 위와 같다.

메타 정보 변경하기

  • 메타 정보를 획득하는 시스템 콜은 stat(2) 한 개지만, 변경하는 시스템 콜은 여러개가 있다.
변경 대상 사용하는 시스템 콜
권한 chmod(2)
오너와 그룹 chown (2)
최종 액세스 시간과 최종 갱신 시각 utime(2)

chmod(2)

#include <sys/stat.h>

int chmod(const char *path, mode_t mode);
  • chmod는 경로로 지정한 파일의 모드를 변경한다. 성공하면 0을 반환하고 실패하면 -1을 반환하면서 errno에 에러 번호를 설정한다.

  • mode는 표에 있는 상수를 OR로 묶어서 지정하거나 0775 같은 숫자를 사용한다. C언어에서 숫자에 0을 앞에 두면 8진수가 된다.

  • 예를 들어서, 권한 644의 경우, ‘0644’ 또는 ‘S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH`로 지정한다.

chown(2)

#include <unistd.h>

int chown(const char *path, uid_t owner, gid_t group);
int lchown(const char *path, uid_t owner, gid_t group);
  • chown()은 파일 path의 소유 사용자를 owner로, 소유 그룹을 group로 변경한다. 그중 하나만을 변경하려는 경우에는 변경하지 않는 쪽에 -1을 지정한다.

  • lchown()의 동작은 chown()과 거의 같지만, path가 심볼릭 링크인 경우에는 그 심볼릭 링크 자체의 정보를 변경하는 점이 다르다. 그리고 chown() 은 심볼릭 링크가 가리키는 파일의 정보를 변경한다.

  • 둘 다 성공하면 0을 반환하며, 실패하면 -1을 반환하고 errno를 설정한다.

  • 어느 시스템 콜이든지 소유 사용자를 변경하려면 슈퍼 사용자 권한이 필요하다. 그리고 소유 그룹을 변경하는 경우에는 해당 파일의 소유 사용자여야 하며, 그리고 자신이 포함된 그룹으로만 변경할 수 있다. 물론, 슈퍼 사용자라면 임의의 그룹으로 변경할 수 있다.

  • lchown()이 있다면 lchmod()도 있을 것 같지만, 리눅스에서는 심볼릭 링크 자체에 권한이 없어 lchmod()란 존재하지 않는다. 그러나 BSD 계열의 유닉스에는 존재한다.

utime(2)

#include <sys/types.h>
#include <utime.h>

int utime(const char *path, struct utimbuf *buf);

struct utimbuf {
  time_t actime; /* 최종 액세스 시간 */
  time_t modetime; /* 최종 갱신 시간 */
}
  • utime()은 경로로 지정한 파일의 최종 액세스 시간과 최종 갱신 시간을 변경한다. 만약 buf가 NULL이 아니면 buf의 내용에 따라서 actimemodtime이 설정된다.

  • buf가 NULL 이라면 양쪽 모두 현재 시간으로 변경된다.

chmod 명령어 작성하기

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

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

  if (argc < 2) {
    fprintf(stderr, "no mode given\n");
    exit(1);
  }

  mode = strtol(argv[1], NULL, 0);
  for (i = 2; i < argc; i++) {
    if (chmod(argv[i], mode) < 0) {
      perror(argv[i]);
    }
  }
  exit(0);
}
  • strtol()atoi() 와 같이 정수가 표현된 문자열을 정수 타입의 값으로 변환하는 함수이다. 그러나 atoi()와 다르게 세번째 인자로 진수를 설정할 수 있다.

참고 문헌

>> Home