[gnome-devel-docs] programming-guidelines: Add a page on accessing the file system
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-devel-docs] programming-guidelines: Add a page on accessing the file system
- Date: Wed, 11 Feb 2015 10:23:42 +0000 (UTC)
commit 1628fb97954d32d17492eb357034013fd6555a5a
Author: Philip Withnall <philip withnall collabora co uk>
Date: Mon Feb 9 16:46:51 2015 +0000
programming-guidelines: Add a page on accessing the file system
https://bugzilla.gnome.org/show_bug.cgi?id=376123
programming-guidelines/C/file-system.page | 180 +++++++++++++++++++++++++++++
programming-guidelines/Makefile.am | 1 +
2 files changed, 181 insertions(+), 0 deletions(-)
---
diff --git a/programming-guidelines/C/file-system.page b/programming-guidelines/C/file-system.page
new file mode 100644
index 0000000..f6b32e3
--- /dev/null
+++ b/programming-guidelines/C/file-system.page
@@ -0,0 +1,180 @@
+<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">
+
+ <info>
+ <link type="guide" xref="index#coding-style"/>
+
+ <credit type="author copyright">
+ <name>Philip Withnall</name>
+ <email its:translate="no">philip withnall collabora co uk</email>
+ <years>2015</years>
+ </credit>
+
+ <include href="cc-by-sa-3-0.xml" xmlns="http://www.w3.org/2001/XInclude"/>
+
+ <desc>Accessing the file system</desc>
+ </info>
+
+ <title>File System Access</title>
+
+ <synopsis>
+ <title>Summary</title>
+
+ <p>
+ There are a few anti-patterns to consider when accessing the file system.
+ This article assumes knowledge of the standard
+ <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>
+ and
+ <link
href="https://developer.gnome.org/gio/stable/GOutputStream.html"><code>GOutputStream</code></link>
+ APIs.
+ </p>
+
+ <list>
+ <item><p>
+ Use asynchronous I/O for file access.
+ (<link xref="#asynchronous-io"/>)
+ </p></item>
+ <item><p>
+ Always use appropriate functions to construct file names and paths.
+ (<link xref="#file-path-construction"/>)
+ </p></item>
+ <item><p>
+ Validate file paths are in the expected directories before using them.
+ (<link xref="#path-validation-and-sandboxing"/>)
+ </p></item>
+ <item><p>
+ Use mandatory access control profiles to enforce constraints on file
+ access.
+ (<link xref="#path-validation-and-sandboxing"/>)
+ </p></item>
+ </list>
+ </synopsis>
+
+ <section id="asynchronous-io">
+ <title>Asynchronous I/O</title>
+
+ <p>
+ Almost all I/O should be performed asynchronously. That is, without
+ blocking the
+ <link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html">GLib
+ main context</link>. This can be achieved by always using the
+ <code>*_async()</code> and <code>*_finish()</code> variants of each I/O
+ function.
+ </p>
+
+ <example>
+ <p>
+ For example,
+ <link
href="https://developer.gnome.org/gio/stable/GInputStream.html#g-input-stream-read-async"><code>g_input_stream_read_async()</code></link>
+ rather than
+ <link
href="https://developer.gnome.org/gio/stable/GInputStream.html#g-input-stream-read"><code>g_input_stream_read()</code></link>.
+ </p>
+ </example>
+
+ <p>
+ Synchronous I/O blocks the main loop, which means that other events, such
+ as user input, incoming networking packets, timeouts and idle callbacks,
+ are not handled until the blocking function returns.
+ </p>
+
+ <p>
+ Synchronous I/O is acceptable in certain circumstances where the overheads
+ of scheduling an asynchronous operation exceed the costs of local
+ synchronous I/O on Linux. For example, making a small read from a local
+ file, or from a virtual file system such as <file>/proc</file>. For such
+ reads, the low level functions <code>g_open()</code>, <code>read()</code>
+ and <code>g_close()</code> should be used rather than GIO.
+ </p>
+
+ <p>
+ Files in the user’s home directory do <em>not</em> count as local, as they
+ could be on a networked file system.
+ </p>
+
+ <p>
+ Note that the alternative – running synchronous I/O in a separate thread –
+ is highly discouraged; see the
+ <link xref="threading#when-to-use-threading">threading guidelines</link>
+ for more information.
+ </p>
+ </section>
+
+ <section id="file-path-construction">
+ <title>File Path Construction</title>
+
+ <p>
+ File names and paths are not normal strings: on some systems, they can use
+ a character encoding other than UTF-8, while normal strings in GLib are
+ guaranteed to always use UTF-8. For this reason, special functions should
+ be used to build and handle file names and paths. (Modern Linux systems
+ almost universally use UTF-8 for filename encoding, so this is not an
+ issue in practice, but the file path functions should still be used for
+ compatibility with systems such as Windows, which use UTF-16 filenames.)
+ </p>
+
+ <example>
+ <p>
+ For example, file paths should be built using
+ <link
href="https://developer.gnome.org/glib/stable/glib-Miscellaneous-Utility-Functions.html#g-build-filename"><code>g_build_filename()</code></link>
+ rather than
+ <link
href="https://developer.gnome.org/glib/stable/glib-String-Utility-Functions.html#g-strconcat"><code>g_strconcat()</code></link>.
+ </p>
+ </example>
+
+ <p>
+ Doing so makes it clearer what the code is meant to do, and also
+ eliminates duplicate directory separators, so the returned path is
+ canonical (though not necessarily absolute).
+ </p>
+
+ <example>
+ <p>
+ As another example, paths should be disassembled using
+ <link
href="https://developer.gnome.org/glib/stable/glib-Miscellaneous-Utility-Functions.html#g-path-get-basename"><code>g_path_get_basename()</code></link>
+ and
+ <link
href="https://developer.gnome.org/glib/stable/glib-Miscellaneous-Utility-Functions.html#g-path-get-dirname"><code>g_path_get_dirname()</code></link>
+ rather than
+ <link
href="https://developer.gnome.org/glib/stable/glib-String-Utility-Functions.html#g-strrstr"><code>g_strrstr()</code></link>
+ and other manual searching functions.
+ </p>
+ </example>
+ </section>
+
+ <section id="path-validation-and-sandboxing">
+ <title>Path Validation and Sandboxing</title>
+
+ <p>
+ If a filename or path comes from external input, such as a web page or
+ user input, it should be validated to ensure that putting it into a file
+ path will not produce an arbitrary path. For example if a filename is
+ constructed from the constant string <file>~/</file> plus some user input,
+ if the user inputs <file>../../etc/passwd</file>, they can (potentially)
+ gain access to sensitive account information, depending on which user the
+ program is running as, and what it does with data loaded from the
+ constructed path.
+ </p>
+
+ <p>
+ This can be avoided by validating constructed paths before using them,
+ using
+ <link
href="https://developer.gnome.org/gio/stable/GFile.html#g-file-resolve-relative-path"><code>g_file_resolve_relative_path()</code></link>
+ to convert any relative paths to absolute ones, and then validating that
+ the path is beneath a given root sandboxing directory appropriate for the
+ operation. For example, if code downloads a file, it could validate that
+ all paths are beneath <file>~/Downloads</file>, using
+ <link
href="https://developer.gnome.org/gio/stable/GFile.html#g-file-has-parent"><code>g_file_has_parent()</code></link>.
+ </p>
+
+ <p>
+ As a second line of defence, all projects which access the file system
+ should consider providing a mandatory access control profile, using a
+ system such as <link href="http://apparmor.net/">AppArmor</link> or
+ <link href="http://selinuxproject.org/">SELinux</link>, which limits the
+ directories and files they can read from and write to.
+ </p>
+ </section>
+</page>
diff --git a/programming-guidelines/Makefile.am b/programming-guidelines/Makefile.am
index 4ce5e5b..910aec9 100644
--- a/programming-guidelines/Makefile.am
+++ b/programming-guidelines/Makefile.am
@@ -12,6 +12,7 @@ HELP_FILES = \
c-coding-style.page \
databases.page \
documentation.page \
+ file-system.page \
index.page \
memory-management.page \
namespacing.page \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]