* ARM processor

- word : CPU가 한번에 처리할 수 있는 크기

- Thumb mode : 32 bit ARM에서 돌아가는 16bit 기계어, ARM 명령어들을 16bit로 압축한 명령어 set

- ARM Mode

Mode 약자 설명
Normal mode User USR Normal Program execution mode

Privileged mode

System SYS Run privileged operating system tasks
Fast Interrupt Request FIQ When a high priority fast interuppt is raised
Interrupt Request IRQ When a low priority normal interrupt is raised
Supervisor SVC A protected mode for the operaing system, entered when a SWI(소프트웨어인터럽트) instruction is executed
Abort ABT Used to handle memory access violations
Undefined Instruction UND Used to handle undefined instructions

- Privileged Mode는 IRQ나 FIQ 등의 Interrupt의 사용 가능 유무를 직접 설정할 수 있다.

- Privileged Mode는 자기들끼리, 자기네들 스스로 서로 Mode 변경이 가능하다. Normal Mode는 자기 스스로 Privileged Mode로 Mode 변경이 불가능하다. 

- ARM의 default mode는 SCV mode이다. 여기서 출발해야 boot up시에 ARM에 대한 모든 권한을 행사할 수 있으니!

 

* Compile

*.c

arm-elf-gcc

C compiler

*.o

linker.ld

arm-elf-gcc

or

arm-elf-ld

Linker

*.elf

arm-elf-objcopy

Object copy

*.bin

*.s

arm-elf-as

Assembly compiler

- elf : 헤더, 바이너리, 심볼 3개의 파트로 나뉘어짐
  . 헤더 : 파일의 구성을 나타내는 로더맵 역할
  . 바이너리 : 실제 타켓 플래시 메모리에 올라가는 실행할 수 있는 코드로 구성
  . 심볼 : 디버깅을 위한 정보로 개발자가 정의한 함수나 변수들이 실제 메모리 주소와 일치가 되도록 매핑

 

* Startup.S

- 부팅 과정 중 가장 첫번째 단계를 맏고 있는 파일로 *.s 어셈블리언어로 만든 소스
  . 왜 어셈블리 언어로?
   1. 인터럽트 처리는 개발자 몫인데, 인터럽트는 자주 발생되니까 최대한 빨리 적게 개발하는 방법으로 실행 코드 수를 줄이는 방법으로 선택
   2. 메모리 컨트롤러 레지스터 설정과 스택 주소 할당을 위해서. main 함수도 C언어로 만들었기에 스택 영역이 필요하고, 스택 할당 전 SDRAM이 읽고 쓰기가 가능해야하기 때문에 스택 영역 할당 전 메모리 컨트롤러 레지스터에 데이터 값을 넣어 초기화.

- 익셉션 벡터, 인터럽트 disable, PPL(Phase Looked Loop), SDRAM 초기화, 스택 영역 할당, 변수 초기화, C언어의 main 함수 진입 등을 어셈블리 언어로 만든다.

- 익셉션 벡터 : 임베디드 시스템이 리셋되거나 인터럽트 발생시 ARM core는 고정된 주소로 점프한 후 개발자가 지정한 주소로 다시 점프해서 프로그램이 흘러가도록 함

- 인터럽트 disable : 임베디드 시스템 부팅 초기가 매우 중요하기 때문에 그 순간 만큼은 인터럽트를 받지 않기 위함

- PLL 설정 : CPU와 각종 디바이스에 클럽 설정하기 위함

- 메모리 클러스터 설정 : CPU가 SDRAM 메모를 읽기, 쓰기할 수 있도록

- main 함수 진입 : CPU가 SDRAM에 읽기 쓰기가 가능해지면 C 프로그램이 동작하기 위한 스택 영역 지정 후 C언어의 main으로 점프한다.

- startup.s와 main.c 파일을 컴파일하면 누가 먼저 실행되어야할지를 linker.ld라는 링크 스크립트에서 결정할 수 있다. : ENTRY(_start) -> startup.s에 있는 레이블

 

* Makefile

- 빌드 과정을 한번 만에 할 수있도록 제공

- 프리웨어인 ARM-GCC, 상용 컴파일러 ADS

- startup.o와 main.o를 가지고 링크 시켜야함, 이 과정 후 *.elf 파일 생성, 링크시켜주는 파일은 arm-elf-ld인데, 컴파일러 버전에 따라 arm-elf-gcc에서도 링크 역할해줌

-  구성 : source file name / compiler name / assembler compiler option / c compiler option / compile command

## File Definition ##

PRJ = general

INIT1 = Startup

CM1 = main

## Destination path Definition ##

PRE = arm-elf

SOURCE=./sources/

## ARM tool Definition ##

ARMASM = $(PRE)-as

ARMCC = $(PRE)-gcc

...

## Option Definition ##

AFLAGS = -marm9tdmi -EL -M --gdwarf2

CFLAGS = -B$(GCC_EXEC_PREFIX) -g -gdwarf-2 -Oo -c -mcpu=arm9tdmi -mlittle-endian -mapcs-frame -mno-apcs-stack-check

LFLAGS = -Bstatic -nostartfiles -Xlinker --script=linker.ld -lc

OBJS = $(INIT1).o $(CM1).o

$(PRJ).elf: $(OBJS)

$(ARMLINK) $(LFALGS) -o $(PRJ).elf $(OBJS)

$(ARMOBJCOPY) $(PRJ).elf --output-target=binary $(PRJ).bin

..

all: clean $(PRJ).elf

clean:

rm -f *.o ......

 

* 링커 스크립트(Linker Script) 파일

- 컴파일을 하고 나면 오브젝트 파일이 만들어 질 때 4개의 독립된 영역으로 나누어 진다 : 코드 / 데이터 / 힙/ 스택

- 링크 스크립트는 섹션 영역의 start와 end 영역을 지정, 개발자가 링크 스크립트를 만들 때 임베디드 제품의 메모리 맵을 확인한 다음 각 섹션 영역을 어떻게 나눌 것인지 결정한 후 만든다.

- 일반적으로 .text_start와 .data_start 그리고 .bss_start 주소를 지정해주면 된다.

- arm-elf-size general.elf : 해당 섹션 영역의 사이즈를 알 수 있다.

- 어떤 컴파일을 사용하느냐에 따라 스케트(Scatter) 파일 또는 링크 스크립트 파일이라고 부른다.

- 만드는 방법
  1. MCU 데이터 시트를 열어서 메모리 맵 확인 : 플래시 메모리 시작 주소와 사이즈, SDRAM 시작 주소와 사이즈 확인
  2. 메모리 영역을 어떻게 나눌 것인지 결정 : 플래시 메모리에는 코드영역과 데이터영역 지정, SDRAM 영역은 주로 BSS(Block Started Segment)의 시작 주소 지정

- 힙 영역은 링크 스크립트에서 따로 지정하지 않아도 됨. malloc 함수 자체가 자동으로 .bss_end+4 주소 이후로 잡아준다.

-ARM 프로세서에서 스택은 상위주소에서 하위주소로 증가, Heap은 하위 주소에서 상위 주소로 증가.

- 스택 영역 시작 주소 지정은 linker.ld에서 하지 않고 startup.s에서 지정

 

* RTOS, Embedded OS

- Kernel : Context Switing, Scheduling, Memory Management, ISR Management 등을 담당하는 부분을 따로 떼어서 Kernel이라고 부른다. Task, Process 등이 Kernel에게 Service를 받기 위해 Kernel API를 부르던가, Interrupt가 걸려서 Interrupt 처리할 때 Interrupt 처리 routine의 끝에 Kernel API가 불리던가 하는 등으로 Kernel 활성화

 

'개발 > System' 카테고리의 다른 글

특정 파일 UTF8 ↔ ANSI 변환  (0) 2013.08.24
UNIX의 디렉토리  (0) 2012.10.29
파일 정보의 획득  (0) 2012.10.29
다수의 이름을 갖는 파일  (0) 2012.10.29
access, chmod, chown 시스템 호출  (0) 2012.10.29

java 파일 인코딩이 안맞아서 메모장으로 파일 하나씩 다 열어서 UTF-8로 다 바꿔줘야하나 걱정했는데

폴더만 지정하면 한 번에 바꿔주는 프로그램을 찾았다!!!! 꺅

변환할 확장자도 콤마로 분리해서 여러 개 입력 가능하고 ^^

완전 짱 ^0^



RedUTF8.exe


출처는 http://suime.rgro.net/ 여기인듯하나 현재는 안들어가진당...ㅠㅠ

'개발 > System' 카테고리의 다른 글

임베디드 스케치 공부  (0) 2019.11.19
UNIX의 디렉토리  (0) 2012.10.29
파일 정보의 획득  (0) 2012.10.29
다수의 이름을 갖는 파일  (0) 2012.10.29
access, chmod, chown 시스템 호출  (0) 2012.10.29

디렉토리


  • ● 디렉토리란? 파일 이름들의 집합으로, 파일들을 논리적으로 관련 그룹별로 나누어주는 수단을 제공한다. 디렉토리는 파일뿐 아니라 다른 디렉토리를 토함할 수 있으며, 계층적인 트리 구조를 거꾸로 놓은 것과 같이 묘사될 수 있다.

어떤 디렉토리이든 맨 위에는 루트 디렉토리라 불리는 하나의 디렉토리가 있다. 

이것은 '/' 라는 기호를 사용하여 표현하며, 트리의 단말 노드들은 보통 파일, 특수 파일, 빈 디렉토리이다.

  • ● 현재 작업 디렉토리란? 로그인한 사용자는 현재 작업 디렉토리라고 불리는 파일 구조의 특정한 장소에서 작업을 하게 되는데, 초기 설정 값은 그 사용자의 홈 디렉토리이다.

디렉토리 구조

구조적으로 디렉토리는 일련의 디렉토리 항으로 구성된다.

각 디렉토리항은 최소한 다음과 같이 구성된다.



 i-node 번호


파일 이름을장하는 문자 필드 


i-node 번호는 한 파일을 유일하게 식별한다. 

i-node 번호는 i-node 구조라 불리는 파일에 대한 모든 정보를 저장하고 있는 자료구조를 찾기 위해 운영체제에 의해 사용된다.


점(.)과 이중점(..)


모든 디렉토리 안에는 점(.)과 이중점(..)이라는 이상한 파일이름이 들어가있다.


사실 점(.)현재 디렉토리를 의미하고, 이중점(..)은 현재 디렉토리의 부모 디렉토리를 가리키는 표준 표기법이다.

즉, 현재 디렉토리와 부모 디렉토리에 대한 링크인 것이다!


디렉토리 허가


보통 파일과 같이 디렉토리도 소유자, 소유자와 같은 그룹의 사용자들, 그 외 사용자들에 대한 접근 허가를 가진다.

표기법도 보통 파일과 같이 표현하지만, 조금은 다르게 해석된다.

  • ● 디렉토리에 대한 읽기 허가 : 디렉토리 내에 있는 파일이나 부디렉토리의 이름을 리스트할 수 있음을 뜻한다. 그러나 각 파일 자체에 저장된 정보를 읽을 수 있다는 것은 아니다. 즉, 디렉토리내 각 파일은 각 파일의 독립된 접근 허가에 의해 제어된다!
  • ● 디렉토리에 대한 쓰기 허가 : 디렉토리 내 기존의 파일을 제거하고 같은 이름의 새로운 파일을 만들 수 있음을 뜻한다. 그러나 파일의 내용을 변경시킬 수 있다는 것을 뜻하지는 않는다.
  • ● 디렉토리에 대한 실행 허가 : 탐색 허가로도 불리며, chdir 시스템 호출을 사용하여 사용자가 디렉토리 내부로 들어가는 것을 허용한다. 파일을 열거나 프로그램을 실행시키기 위해서는 각 파일의 독립된 접근 허가에 따른다.

디렉토리와 시스템 호출

디렉토리를 조작하기 위해서서는 앞서 배운 보통 파일과는 다른 시스템 호출을 이용해야 한다.
즉, creat나 open 시스템 호출의 사용이 불가능하다.
이러한 제약 조건은 write를 사용해서 디렉토리를 변경하는 것을 막기 위해서이다.

  • ● 디렉토리의 생성
#include <sys/types.h>
#include <sys/stat.h>

int mkdir(const char *pathname, mode_t mode);


첫 번째 인수는 생성될 디렉토리의 경로이름이고, 두 번째 인수는 접근 허가 집합이다.


int retval;

retval = mkdir("/tmp/dir", 0777);


디렉토리의 생성에 성공하면 0을 반환하고, 실패시 -1을 반환한다.


mkdir은 새로 생성된 디렉토리에 두 개의 링크 '.'(점)과 '..'(이중점)을 넣는다.

만약 이 두 개의 링크가 존재하지 않으면 그 항은 디렉토리로 사용할 수 없을 것이다!


  • ● 디렉토리 제거
#include <unistd.h>

int rmdir(const char *pathname);


디렉토리를 제거하고 싶을 경우 rmdir 시스템 호출에 파라미터로 제거할 디렉토리 경로를 입력하여 주면 된다.

이 호출은 디렉토리가 비어있을 경우(단지 .과 ..만을 포함할 경우를 말한다!!)에만 성공적이다!


● 디렉토리 열기

#include <sys/types.h>

#include <dirent.h>


DIR *opendir(const char *dirname);


opendir의 인수는 개방할 디렉토리의 경로이름이다.

만약 성공적으로 개방한다면, 이 호출은 DIR 유형에 대한 포인터를 반환한다.

헤더파일 <dirent.h>에 하나의 디렉토리 스트림을 나타내는 DIR 유형에 대해 정의되어있다.


열려고 하는 것이 디렉토리이기 때문에 처음 open하면(성공시) 디렉토리 스트림에 대한 포인터가 디렉토리의 첫 항에 위치한다.

만약 호출에 실패하면 시스템은 널(null) 포인터를 반환한다!

그러므로 오류 검사코드는 널 포인터인지 아닌지를 검사해야할 것이다!


● 디렉토리 닫기

#include <dirent.h>


int closedir(DIR *dirptr);


closedir 시스템 호출은 인수가 가리키는 디렉토리 스트림을 닫는다.


● 디렉토리 읽기

#include <sys/types.h>

#include <dirent.h>


struct dirent *readdir(DIR *dirptr);


readdir 시스템 호출은 opendir을 통해 얻은 디렉토리 스트림 포인터를 파라미터로 받는다.

이렇게 개방된 디렉토리를 readdir을 통해 읽으면 첫 호출에 의해 디렉토리의 첫 항이 struct dirent로 읽혀 들여진다.

호출이 끝나면, 디렉토리 포인터는 다음 항으로 이동해 있을 것이다.

그렇게 읽고 난 후 디렉토리의 끝 항에 도달하면 널 포인터를 반환하게 된다.


여기서, 디렉토리를 처음부터 다시 읽고 싶다면 다음과 같은 시스템 호출을 사용하면 된다.


#include <sys/types.h>

#include <dirent.h>


void reinddir(DIR *dirptr);


rewinddir 호출은 첫 항으로 돌아가길 원하는 디렉토리 스트림 포인터를 파라미터로 받는다!


다음 예는 개방한 디렉토리 내의 모든 디렉토리항 이름을 출력한다. (i-node 번호가 유효한지 검사하면 된다.)


..

...

while( d = readdir(dp) ) { // opendir로 dp를 얻었다고 가정

if( d->d_no != 0 )

printf("%s \n", d->d_name);

}

...

..






'개발 > System' 카테고리의 다른 글

임베디드 스케치 공부  (0) 2019.11.19
특정 파일 UTF8 ↔ ANSI 변환  (0) 2013.08.24
파일 정보의 획득  (0) 2012.10.29
다수의 이름을 갖는 파일  (0) 2012.10.29
access, chmod, chown 시스템 호출  (0) 2012.10.29

stat와 fstat 시스템 호출


파일에 대한 정보를 알고 싶을 떄에는 stat와 fstat를 이용한다.


#include <sys/types.h>

#include <sys/stat.h>


int stat(const char *pathname, struct stat *buf);

int fstat(int filedes, struct stat *buf);


먼저 stat에 대해서!

첫 번째 인수는 정보를 알고 싶은 파일 경로이름이다.

두 번째 인수는 이 호출이 성공하면 정보들이 저장될 구조체이다.


다음으로 fstat에 대해서!

첫 번째 인수는 정보를 알고 싶은 파일 경로이름이 아니라, 개방되어있는 파일 기술자이다.

두 번째 인수는 stat와 동일하다.


..

...

struct stat s;

int fd;


fd = open("/tmp/myfile", O_RDWR);


stat("/tmp/myfile", &s);


fstat(fd, &s);


stat 구조에 대한 정의는 헤더파일 <sys/stat.h>에서 찾을 수 있으며, 이 구조에서 사용되는 자료형은 헤더파일 <sys/types.h>에 있다.

다음은 stat의 구조에 대한 설명이당.


자료형 

변수명 

의미 

dev_t 

st_dev 

파일이 들어 있는 논리적 장치를 기술함 

ino_t 

st_ino 

inode 번호

mode_t

st_mode 

파일 모드, 요걸 이용하여 허가 계산할 수 있음

nlink_t 

st_nlink

하드링크 계수(비심볼형 링크의 수) 

uid_t 

st_uid 

파일의 사용자 식별번호 

gid_t

st_gid 

파일의 그룹 식별번호 

dev_t 

st_rdev 

파일 엔트리가 장치를 기술하는 데 사용될때 의미를 가짐..(당분간 무시 ㅠㅠ) 

off_t 

st_size 

파일의 현재 논리적 크기를 바이트 수로 표시 

time_t 

st_atime 

마지막으로 읽혔던 시간, open이나 creat할 때 

time_t 

st_mtime 

변경된 시간 기록 

time_t

st_ctime 

stat 구조 자체가 변경될 때의 시간(link, chmod, write 등) 

long 

st_blksize 

파일 시스템 고유의 I/O 블록 크기 기록 

long 

st_blocks 

특정 파일에 할당된 물리적 파일 시스템 블록의 수 기록 




'개발 > System' 카테고리의 다른 글

특정 파일 UTF8 ↔ ANSI 변환  (0) 2013.08.24
UNIX의 디렉토리  (0) 2012.10.29
다수의 이름을 갖는 파일  (0) 2012.10.29
access, chmod, chown 시스템 호출  (0) 2012.10.29
다중 사용자 환경에서의 파일  (0) 2012.10.28

바로가기 아이콘을 만드는 것처럼 UNIX 파일은, 물리적 집합은 중복해서 메모리에 저장되어 있지 않아도 여러 경로이름과 연관될 수 있다.

이러한 것들의 각 이름은 하나의 하드링크라고 하고, 한 파일과 연관된 링크의 수는 그 파일의 링크 계수라고 부른다.

경로이름은 다르게, 아이노드 번호는 같게! (원본 파일의 아이노드 번호를 참조한당 :D)


link 시스템 호출


#include <unistd.h>


int link(const char *orginal_path, const char *new_path);


새 하드링크는 link 시스템 호출로 생성할 수 있다.

첫 번째 인수는 기존 파일 이름의 문자형 포인터이다.

두 번째 인수는 그 파일에 대한 새로운 이름 또는 링크를 가리킨다. new_path는 이미 존재하는 파일이 아니여야한다!


새로운 링크 생성이 성공하면 link 시스템 호출은 0을 반환하고, 오류가 발생하면 -1을 반환한다.


link("/tmp/one/orginal_myfile", "/tmp/two/new_myfile");


link 호출에는 두 가지 중요한 제한이 있는데, 다음과 같다.

  • 디렉토리는 참조할 수 없다.
  • 다른 파일 시스템에 있는 파일을 참조할 수 없다.


앞서 파일을 제거하는 방법 중 하나로 unlink 시스템 호출이 있었다.

unlink 호출은 지명된 링크를 제거하고, 파일의 링크 계수를 하나 줄인다.

만약 링크 계수가 0이되고, 그 파일을 개방한 프로그램이 하나도 없으면, 파일은 시스템으로부터 제거된 것이다!



symlink 시스템 호출


#include <unistd.h>


int symlink(const char *realname, const char *symname);


앞서 link의 두 가지 제한을 보았다. 심볼릭 링크는 특수한 파일의 종류로, 그 내용물인 문자열이 링크가 가리키는 또 다른 파일의 경로이름이다.

link 호출을 이용하면 아이노드 블록을 같이 참조하지만, symlink는 자신만의 아이노드 블록을 가지며, 데이터 블록이 원본 파일 경로를 가리키고 있다.

즉, 심볼릭 링크는 다른 파일에 대한 포인터라고 할 수 있다.



readlink 시스템 호출


#include <unistd.h>


int readlink(const char *sympath, char *buffer, size_t bufsize);


만약 심볼릭 링크 파일이 open으로 개방되면, open 시스템 호출은 심볼릭 링크 파일이 가리키는 파일의 파일 기술자를 반환한다.

readlink는 링크를 따라가지 않고 심볼릭 링크 자체에서 동작하는 시스템 호출이다.

만일 한 프로그래머가 심볼릭 링크 자체에 들어있는 자료를 보고 싶으면 반드시 readlink를 사용해야 한다.


readlink 시스템 호출은 먼저 sympath를 개방하고, 그 파일 내용을 buffer로 읽어 들인다.

반환 값은 버퍼 내의 문자 수를 나타내거나 오류 발생시 -1이다.

심볼릭 링크에 의해 가리켜지고 있는 원래의 파일이 제거되었는데, 그 파일을 이 심볼릭 링크를 통해 접근하려고 하면 오류가 발생한다.



rename 시스템 호출


rename 시스템 호출은 정규 파일, 디렉토리의 이름을 바꾸는 것이다.


#include <stdio.h>


int rename(const char *old_pathname, const char *new_pathname);


첫 번째 인수 old_pathname이 두 번째 인수 new_pathname으로 개명된다.

만약 new_pathname이 이미 존재하면 이를 먼저 제거한 후 old_pathname을 개명한다!


'개발 > System' 카테고리의 다른 글

UNIX의 디렉토리  (0) 2012.10.29
파일 정보의 획득  (0) 2012.10.29
access, chmod, chown 시스템 호출  (0) 2012.10.29
다중 사용자 환경에서의 파일  (0) 2012.10.28
리눅스의 파일 시스템  (0) 2012.10.28

access 시스템 호출


access 시스템 호출은 소유자가 해당 파일의 읽기, 쓰기, 실행 접근 권한을 가졌는지 조사한다.


#include <unistd.h>


int access(const char *pathname, int amode);


첫 번째 인수는 조사하려는 파일명이다.

두 번째 인수는 접근 방법을 나타내는 값으로 다음과 같다.

  • R_OK : 호출 프로세스가 읽기 접근 권한을 가지고 있는가?
  • W_OK : 호출 프로세스가 쓰기 접근 권한을 가지고 있는가?
  • X_OK : 호출 프로세스가 파일을 실행시킬 수 있는가?
  • F_OK : 파일이 존재하는가?
이 시스템 호출의 반환값은 두 번째 인수에 대한 대답에 YES라면 0을 반환하고, 오류 발생시에는 -1을 반환한다.


chmod 시스템 호출


#include <sys/types.h>

#include <sys/stat.h>


int chmod(const char *pathname, mode_t newmode);


chmod 시스템 호출은 기존 파일의 허가를 변경한다.

이 시스템 호출은 허가를 변경할 수 있는 권한을 가진 경우, 즉 파일 소유자나 수퍼 사용자만이 사용할 수 있다.


첫 번째 인수는 변경하려는 파일명이다.

두 번째 인수는 변경할 새로운 파일 모드이다.


if(chmod(pathname, 0644) == -1)

printf("파일 허가 변경에 실패하였습니다.\n");


위와 같이 변경할 새로운 파일 모드를 입력하면 된다.



chown 시스템 호출


#include <sys/types.h>

#include <unistd.h>


int chown(const char *pathname, uid_t owner_id, gid_t group_id);


chown은 파일의 소유자와 그룹을 함께 변경할 수 있다.


첫 번째 인수는 변경하려는 파일명이다.

두 번째 인수는 새 소유자를 나타낸다.

세 번째 인수는 새 그룹을 나타낸다.


성공 시 0을 반환하고, 오류 발생 시 -1을 반환한다.


uid_t와 gid_t는 <sys/types.h>에 정의된 유형들이다.


chown은 파일의 소유자나 수퍼 사용자만 사용할 수 있고, 한 번 소유권이 바뀌면 원래 사용자의 사용자 식별 번호와 파일의 사용자 식별 번호가 서로 달라지기 때문에 이를 취소할 수 없다.

'개발 > System' 카테고리의 다른 글

파일 정보의 획득  (0) 2012.10.29
다수의 이름을 갖는 파일  (0) 2012.10.29
다중 사용자 환경에서의 파일  (0) 2012.10.28
리눅스의 파일 시스템  (0) 2012.10.28
UNIX 파일 접근 프리미티브 : 파일 제거  (0) 2012.10.28

사용자와 소유권


모든 파일은 시스템의 사용자 중 하나에 의해 소유되는데, 보통 파일을 생성한 사용자이다.

각 파일 소유자의 실제 신원은 사용자 식별 번호(uid)라 불리는 양의 정수값으로 표시된다.


그룹과도 연관되어 있는데, 그룹이란 여러 사용자를 포함하는 프로젝트를 제어하는, 직접적인 수단을 제공하는 사용자들의 단순한 집단이다.

각 사용자는 적어도 한 그룹에 속하고, 여러 그룹에 속할 수도 있다.

양의 정수값인 그룹 식별번호(gid)로 파일의 소유 그룹 실제 신원을 알 수 있다.


파일의 소유자 또는 수퍼 사용자는 파일의 소유권을 변경할 수 있다.

수퍼 사용자의 사용자 이름은 보통 root이고, uid가 항상 0이다.


한 파일이 생성될 때, 생성하는 프로세스와 연관된 그룹 식별번호가 사용자 식별번호와 함께 저장된다.


허가와 파일 모드


소유자는 파일에 대한 허가를 선택할 수 있다.

허가는 서로 다른 유형의 사용자들이 파일에 접근할 수 있는 권한을 결정한다.

다음은 사용자의 세 가지 유형이다.

  • 파일의 소유자
  • 파일에 연관된 그룹과, 같은 그룹에 속하는 사용자
  • 그 외 사용자

파일 허가는 세 가지 기본적인 유형이 있는데, 다음과 같다.
  • 파일의 읽기 권한
  • 파일의 쓰기 권한
  • 파일의 실행 권한

시스템은 이러한 파일 허가를 파일 모드라고 불리는 비트 패턴으로 파일에 저장한다.

팔진수 값 

상징형 모드 

의 미 

0400 

S_IRUSR

소유자에게 읽기를 허가함. 

0200 

S_IWUSR 

소유자에게 쓰기를 허가함. 

0100 

S_IXUSR 

소유자에게 실행을 허가함.

0040 

S_IRGRP 

그룹에 대해 읽기를 허가함. 

0020 

S_IWGRP 

그룹에 대해 쓰기를 허가함. 

0010 

S_IXGRP 

그룹에 대해 실행을 허가함. 

0004 

S_IROTH 

다른 모든 사용자에 대해 읽기를 허가함. 

0002 

S_IWOTH 

다른 모든 사용자에 대해 쓰기를 허가함. 

0001 

S_IXOTH 

다른 모든 사용자에 대해 실행을 허가함. 


헤더파일 <sys/stat.h>에 허가 비트들의 상징형 이름을 수록하고 있다.

파일 모드는 원하는 권한의 팔진수 값을 더하면 된다.

예를 들면 0700 + 050 + 05 = 0755 은 소유자는 읽고, 쓰고, 실행하는 것이 가능하고, 그룹의 구성원과 그 외 사용자는 읽고, 실행만 가능하도록 허락하는 것이다.

또는 상징형 표현에 대해 비트 단위 OR(|)를 수행함으로써 지정할 수도 있다.

예를 들면 세 가지 사용자 유형 모두 읽기 권한만 지정하려면, S_IRUSR | S_IRGRP | S_IROTH 를 하면 된다.

파일 데이터의 할당


리눅스의 파일 시스템은 크게 4가지로 구분 할 수 있다.



부트 블록(Boot Block) 


슈퍼 블록(Super Block) 

아이노드 블록(inode Blocks) 

데이터 블록(Data Blocks) 


  • 부트 블록 : 운영체제를 부팅시키기 위한 코드가 저장되어 있다.
  • 슈퍼 블록 : 파일 시스템과 관련된 정보를 저장하고 있다.
  • 아이노드 블록 : 파일에 대한 정보를 저장하고 있으며, 모든 파일은 반드시 하나의 아이노드 블록을 가지고 있다.
  • 데이터 블록 : 파일이 보관해야하는 데이터가 저장되어 있으며, 보관하는 데이터의 크기에 따라 여러 개가 있을 수 있다.


파일의 제거


#include <unistd.h>


int unlink(const char *pathname);


#include <stdio.h>


int remove(const char *pathname);


파일을 제거하는 데에는 두 가지 방법이 있다.

두 호출 모두 제거할 파일의 이름(스트링)을 인수로 받는다.


unlink("/tmp/myfile1");


remove("/tmp/myfile2");


위와 같이 사용할 수 있다.


두 호출 모두 파일의 제거에 성공하면 0을 반환하고, 실패시 -1을 반환한다.


빈 디렉토리를 제거히기 위해서는 remove(path)는 rmdir(path)와 동일하다.

디렉토리에 대해서는 unlink 대신 항상 remove 시스템 호출을 사용해야 한다.

추후 자세히 살펴보자.

lseek 시스템 호출


#include <sys/types.h>

#include <unistd.h>


off_t lseek(int filedes, off_t offset, int start_flag);


앞에서 파일 포인터에 대해 배웠다.

lseek 시스템 호출은 이 파일 포인터를 임의의 위치로 변경할 수 있게 해준다.


첫 번째 인수는 파일 기술자이고, 두 번째 인수는 파일 포인터의 새 위치를 결정하는데, 세 번째 인수에서 더해질 바이트 수를 지정한다.

세 번째 인수는 두 번째 인수가 어느 위치를 기준으로 하여 더해질지 위치의 기준으로 다음과 같다.

  • SEEK_SET : offset을 파일의 시작위치부터 계산한다.
  • SEEK_CUR : offset을 파일 포인터의 현재 위치부터 계산한다.
  • SEEK_END : offset을 파일의 끝부터 계산한다.
두 번째 인수는 (off_t)로 캐스팅해주는 것에 유의해야한다.
lseek 시스템 호출의 반환값은 파일 안의 새로운 위치이거나 오류 발생시 -1을 반환한다.
off_t 타입은 <sys/types.h>에 정의되어 있으므로, 이 헤더파일은 include해준다.

다음의 예를 보자.

off_t newpos;
..
...
newpos = lseek(fd, (off_t) -8, SEEK_END);


오류가 발생하지 않는다면 newpos는 새로운 위치 값을 반환받을 것이다.

위에서 말한대로 두 번째 인수는 (off_t)로 캐스팅해주었다.

여기서 두 번째 인수 offset의 값은 음수가 가능하다. 즉, 파일 포인터에서 거꾸로 이동하는 것이 가능하다는 것이다.

만약 파일의 시작점보다 더 앞으로 움직일 때에는 오류가 발생할 것이다!

또한 파일의 끝보다 더 뒤의 위치로 이동을 할 수가 있는데, 이 때에는 읽기를 위한 자료를 존재하지 않지만 파일이 확장하게 된다.

이 경우 실제로 물리적으로 할당은 되지 않지만, ASCII null 문자로 채워진다.


※ 파일 오픈 후 파일 포인터 맨 끝에 위치시키기

fd = open("myfile", O_RDWR);

lseek(fd, (off_t) 0, SEEK_END);


fd = open("myfile", O_RDWR | APPEND);

 

위의 예시 둘 다 파일 포인터를 맨 끝에 위치시킨다!

+ Recent posts