Blob Blame History Raw
<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" xmlns:xi="http://www.w3.org/2003/XInclude" type="topic" id="file-system" xml:lang="ko">

  <info>
    <link type="guide" xref="index#specific-how-tos"/>

    <credit type="author copyright">
      <name>Philip Withnall</name>
      <email its:translate="no">philip.withnall@collabora.co.uk</email>
      <years>2015</years>
    </credit>

    <include xmlns="http://www.w3.org/2001/XInclude" href="cc-by-sa-3-0.xml"/>

    <desc>파일 시스템에 접근하기</desc>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>조성호</mal:name>
      <mal:email>shcho@gnome.org</mal:email>
      <mal:years>2016, 2017.</mal:years>
    </mal:credit>
  </info>

  <title>파일 시스템 접근</title>

  <synopsis>
    <title>요약</title>

    <p>파일 시스템에 접근해야 할 때 피해야 할 몇가지 방식이 있습니다. 이 내용은 <link href="https://developer.gnome.org/gio/stable/GFile.html"><code>GFile</code></link>, <link href="https://developer.gnome.org/gio/stable/GInputStream.html"><code>GInputStream</code></link>, <link href="https://developer.gnome.org/gio/stable/GOutputStream.html"><code>GOutputStream</code></link> 표준 API를 알고 있음을 가졍합니다.</p>

    <list>
      <item><p>파일 접근시 비동기 입출력을 활용하십시오(<link xref="#asynchronous-io"/>).</p></item>
      <item><p>파일 이름 및 경로를 만들 때마다 적당한 함수를 활용하십시오(<link xref="#file-path-construction"/>).</p></item>
      <item><p>파일 경로를 활용하기 전 예상 디렉터리에 있는지 검증하십시오(<link xref="#path-validation-and-sandboxing"/>).</p></item>
      <item><p>파일 접근을 통제하는 필수 접근 통제 프로파일을 사용하십시오(<link xref="#path-validation-and-sandboxing"/>).</p></item>
    </list>
  </synopsis>

  <section id="asynchronous-io">
    <title>비동기 입출력</title>

    <p>대부분의 모든 입출력 과정은 비동기 방식으로 처리해야합니다. 무슨 이야기냐면 <link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html">GLib 메인 컨텍스트</link>의 동작을 방해하면 안된다는 의미입니다. 각 입출력 함수의 <code>*_async()</code> 및 <code>*_finish()</code> 변형 함수를 활용하여 언제든 수행 가능합니다.</p>

    <example>
      <p>예를 들어 <link href="https://developer.gnome.org/gio/stable/GInputStream.html#g-input-stream-read"><code>g_input_stream_read()</code></link> 함수 대신 <link href="https://developer.gnome.org/gio/stable/GInputStream.html#g-input-stream-read-async"><code>g_input_stream_read_async()</code></link> 함수를 사용하십시오.</p>
    </example>

    <p>동기 입출력은 메인 루프의 실행을 가로 막는데, 사용자 입력, 네트워크 패킷 수신, 콜백 시간 초과 및 대기 같은 상황의 경우 프로그램의 동작 흐름을 가로막은 함수에서 반환 값이 나오기 전에는 처리할 수 없다는 의미입니다.</p>

    <p>동기 입출력은 리눅스에서 로컬 동기 입출력 보다 비동기 처리 스케줄의 처리 시간/용량이 비교적 좋지 않은 일부 상황에서 용납 가능합니다. 예를 들어 로컬 파일 또는 <file>/proc</file> 같은 가상 파일 시스템에서 작은 데이터를 읽어들이는 경우가 있습니다. 이 때, GIO 대신 <code>g_open()</code>, <code>read()</code>, <code>g_close()</code> 저수준 함수를 사용해야합니다.</p>

    <p>로컬에 <em>없다</em>고 간주하는 사용자 개인 디렉터리에 있는 파일은, 네트워크 파일 시스템에 있을 수 있습니다.</p>

    <p>개별 스레드의 동기 입출력 처리 같은 대안책은 가급적 피하시는게 좋습니다. 자세한 내용은 <link xref="threading#when-to-use-threading">스레드 처리 지침서</link>를 참고하십시오.</p>
  </section>

  <section id="file-path-construction">
    <title>파일 경로 만들기</title>

    <p>파일 이름 및 경로는 일반 문자열이 아닙니다. GLib에서는 일반 문자열에 항상 UTF-8을 사용한다고 간주하지만, 일부 시스템에서는 UTF-8이 아닌 다른 문자 인코딩을 사용할 수 있습니다. 이 이유로, 파일 이름 및 경로를 만들고 처리할 때 특별한 함수를 사용해야합니다(최신 리눅스 시스템에서는 대부분 보편적으로 파일 이름 인코딩에 UTF-8을 사용하여 실제로는 문제되지 않지만, UTF-16 파일 이름을 사용하는 윈도우 같은 시스템의 호환성을 확보하려면 파일 경로 함수를 활용해야합니다).</p>

    <example>
      <p>예를 들어 파일 경로는 <link href="https://developer.gnome.org/glib/stable/glib-String-Utility-Functions.html#g-strconcat"><code>g_strconcat()</code></link> 함수보다 <link href="https://developer.gnome.org/glib/stable/glib-Miscellaneous-Utility-Functions.html#g-build-filename"><code>g_build_filename()</code></link> 함수를 사용하여 만들어야합니다.</p>
    </example>

    <p>이렇게 하면 코드가 무슨 일을 하는지 의미를 좀 더 분명하게 하며, (필연적으로 절대적이진 않지만)디렉터리 구분 문자 중복을 방지하여 올바른 경로를 반환합니다.</p>

    <example>
      <p>다른 예를 들어보자면, <link href="https://developer.gnome.org/glib/stable/glib-String-Utility-Functions.html#g-strrstr"><code>g_strrstr()</code></link> 함수 및 다른 직접적인 검색 함수를 활용하기보다는, <link href="https://developer.gnome.org/glib/stable/glib-Miscellaneous-Utility-Functions.html#g-path-get-basename"><code>g_path_get_basename()</code></link> 함수와 <link href="https://developer.gnome.org/glib/stable/glib-Miscellaneous-Utility-Functions.html#g-path-get-dirname"><code>g_path_get_dirname()</code></link> 함수를 활용하여 경로를 분해해야합니다.</p>
    </example>
  </section>

  <section id="path-validation-and-sandboxing">
    <title>경로 검증 및 샌드박싱</title>

    <p>웹 페이지 또는 사용자 입력 등의 외부 입력으로 파일 이름 또는 경로를 받는다면, 파일 경로로 둔 경로의 임의 경로 여부를 확인하여 검증해야합니다.예를 들어 <file>~/</file> 상수 문자열에 일부 사용자 입력을 받아 파일 이름을 만들고, 여기서 사용자 입력이 <file>../../etc/passwd</file>라면, 사용자가 프로그램을 어떻게 실행하며, 만든 경로에서 어떤 데이터를 불러오냐에 따라 민감한 계정 정보로 접근하는데 접근할 수 있는 권한을(잠재적으로) 얻을 수 있습니다.</p>

    <p>이 기능을 사용하기 전, <link href="https://developer.gnome.org/gio/stable/GFile.html#g-file-resolve-relative-path"><code>g_file_resolve_relative_path()</code></link> 함수로 상대 경로를 절대 경로로 변환하고 처리에 적당한 루트 샌드박싱 디렉터리에 있는 경로인지 검증하는 방식으로 작성한 경로를 검증하여 (악의적 접근을) 막을 수 있습니다. 이를테면, 코드로 파일을 다운로드할 때, <link href="https://developer.gnome.org/gio/stable/GFile.html#g-file-has-parent"><code>g_file_has_parent()</code></link> 함수를 사용하면 모든 경로가 <file>~/Downloads</file> 디렉터리에 있는지 검증할 수 있습니다.</p>

    <p>방어 차선책으로, 파일 시스템에 접근하는 모든 프로젝트는 디렉터리 및 파일의 읽기/쓰기 동작을 제한하는 <link href="http://apparmor.net/">AppArmor</link> 또는 <link href="http://selinuxproject.org/">SELinux</link> 같은 시스템을 활용하는 필수 접근 제어 프로파일 제공을 고려해야합니다.</p>
  </section>
</page>