This required moving files around in the repository and shifting from a master.adoc structure to _topic_map.yml, etc. README and Makefile modified slightly to reflect new build process
548 lines
No EOL
26 KiB
HTML
548 lines
No EOL
26 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta content="IE=edge" http-equiv="X-UA-Compatible">
|
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
|
<title>Defensive Coding Guide | Defensive Coding Guide | Specific Programming Tasks | File System Manipulation</title>
|
|
|
|
<!-- Bootstrap -->
|
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
|
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
|
|
|
|
<!-- Overpass Font -->
|
|
<link rel="stylesheet" href="https://overpass-30e2.kxcdn.com/overpass.css">
|
|
|
|
<link href="../../../master/_stylesheets/asciibinder.css" rel="stylesheet" />
|
|
|
|
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
|
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
|
<!--[if lt IE 9]>
|
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
|
<![endif]-->
|
|
|
|
<link href="../../../master/_images/favicon32x32.png" rel="shortcut icon" type="text/css">
|
|
<!--[if IE]><link rel="shortcut icon" href="../../../master/_images/favicon.ico"><![endif]-->
|
|
<meta content="AsciiBinder" name="application-name">
|
|
</head>
|
|
<body>
|
|
<div class="navbar navbar-default" role="navigation">
|
|
<div class="container-fluid">
|
|
<div class="navbar-header">
|
|
<a class="navbar-brand" href="https://docs.fedoraproject.org/"><img alt="Fedora Documentation" src="../../../master/_images/fedora.svg"></a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="container">
|
|
<p class="toggle-nav visible-xs pull-left">
|
|
<button class="btn btn-default btn-sm" type="button" data-toggle="offcanvas">Toggle nav</button>
|
|
</p>
|
|
<ol class="breadcrumb">
|
|
<li class="sitename">
|
|
<a href="../../../index.html">Home</a>
|
|
</li>
|
|
<li class="hidden-xs active">
|
|
<a href="../../en-US/index.html">Defensive Coding Guide </a>
|
|
</li>
|
|
<li class="hidden-xs active">
|
|
<a href="../../en-US/index.html">Defensive Coding Guide</a>
|
|
</li>
|
|
<li class="hidden-xs active"><a href="../../en-US/tasks/Tasks-Library_Design.html">Specific Programming Tasks</a></li>
|
|
<li class="hidden-xs active">
|
|
File System Manipulation
|
|
</li>
|
|
</ol>
|
|
<div class="row row-offcanvas row-offcanvas-left">
|
|
<div class="col-xs-8 col-sm-3 col-md-3 sidebar sidebar-offcanvas">
|
|
<ul class="nav nav-sidebar">
|
|
<li class="nav-header">
|
|
<a class="" href="#" data-toggle="collapse" data-target="#topicGroup0">
|
|
<span id="tgSpan0" class="fa fa-angle-down"></span>Defensive Coding Guide
|
|
</a>
|
|
<ul id="topicGroup0" class="collapse in list-unstyled">
|
|
<li><a class="" href="../../en-US/index.html">Book Information</a></li>
|
|
<li class="nav-header">
|
|
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-1">
|
|
<span id="sgSpan-0-1" class="fa fa-caret-right"></span> Programming Languages
|
|
</a>
|
|
<ul id="topicSubGroup-0-1" class="nav-tertiary list-unstyled collapse">
|
|
<li><a class="" href="../../en-US/programming-languages/C.html">The C Programming Language</a></li>
|
|
<li><a class="" href="../../en-US/programming-languages/CXX.html">The C++ Programming Language</a></li>
|
|
<li><a class="" href="../../en-US/programming-languages/Java.html">The Java Programming Language</a></li>
|
|
<li><a class="" href="../../en-US/programming-languages/Python.html">The Python Programming Language</a></li>
|
|
<li><a class="" href="../../en-US/programming-languages/Shell.html">Shell Programming and bash</a></li>
|
|
<li><a class="" href="../../en-US/programming-languages/Go.html">The Go Programming Language</a></li>
|
|
<li><a class="" href="../../en-US/programming-languages/Vala.html">The Vala Programming Language</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="nav-header">
|
|
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-2">
|
|
<span id="sgSpan-0-2" class="fa fa-caret-down"></span> Specific Programming Tasks
|
|
</a>
|
|
<ul id="topicSubGroup-0-2" class="nav-tertiary list-unstyled collapse in">
|
|
<li><a class="" href="../../en-US/tasks/Tasks-Library_Design.html">Library Design</a></li>
|
|
<li><a class="" href="../../en-US/tasks/Tasks-Descriptors.html">File Descriptor Management</a></li>
|
|
<li><a class=" active" href="../../en-US/tasks/Tasks-File_System.html">File System Manipulation</a></li>
|
|
<li><a class="" href="../../en-US/tasks/Tasks-Temporary_Files.html">Temporary Files</a></li>
|
|
<li><a class="" href="../../en-US/tasks/Tasks-Processes.html">Processes</a></li>
|
|
<li><a class="" href="../../en-US/tasks/Tasks-Serialization.html">Serialization and Deserialization</a></li>
|
|
<li><a class="" href="../../en-US/tasks/Tasks-Cryptography.html">Cryptography</a></li>
|
|
<li><a class="" href="../../en-US/tasks/Tasks-Packaging.html">RPM Packaging</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="nav-header">
|
|
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-3">
|
|
<span id="sgSpan-0-3" class="fa fa-caret-right"></span> Implementing Security Features
|
|
</a>
|
|
<ul id="topicSubGroup-0-3" class="nav-tertiary list-unstyled collapse">
|
|
<li><a class="" href="../../en-US/features/Features-Authentication.html">Authentication and Authorization</a></li>
|
|
<li><a class="" href="../../en-US/features/Features-TLS.html">Transport Layer Security (TLS)</a></li>
|
|
<li><a class="" href="../../en-US/features/Features-HSM.html">Hardware Security Modules and Smart Cards</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="" href="../../en-US/Revision_History.html">Revision History</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="col-xs-12 col-sm-9 col-md-9 main">
|
|
<div class="page-header">
|
|
<h2>File System Manipulation</h2>
|
|
</div>
|
|
<div id="preamble">
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>In this chapter, we discuss general file system manipulation, with
|
|
a focus on access files and directories to which an other,
|
|
potentially untrusted user has write access.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Temporary files are covered in their own chapter, <a href="#chap-Defensive_Coding-Tasks-Temporary_Files">[chap-Defensive_Coding-Tasks-Temporary_Files]</a>.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="sect-Defensive_Coding-Tasks-File_System-Unowned"><a class="anchor" href="#sect-Defensive_Coding-Tasks-File_System-Unowned"></a>Working with Files and Directories Owned by Other Users</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>Sometimes, it is necessary to operate on files and directories
|
|
owned by other (potentially untrusted) users. For example, a
|
|
system administrator could remove the home directory of a user,
|
|
or a package manager could update a file in a directory which is
|
|
owned by an application-specific user. This differs from
|
|
accessing the file system as a specific user; see
|
|
<a href="#sect-Defensive_Coding-Tasks-File_System-Foreign">Accessing the File System as a Different User</a>.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Accessing files across trust boundaries faces several
|
|
challenges, particularly if an entire directory tree is being
|
|
traversed:</p>
|
|
</div>
|
|
<div class="olist arabic">
|
|
<ol class="arabic">
|
|
<li>
|
|
<p>Another user might add file names to a writable directory at
|
|
any time. This can interfere with file creation and the
|
|
order of names returned by <code>readdir</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p>Merely opening and closing a file can have side effects.
|
|
For instance, an automounter can be triggered, or a tape
|
|
device rewound. Opening a file on a local file system can
|
|
block indefinitely, due to mandatory file locking, unless
|
|
the <code>O_NONBLOCK</code> flag is specified.</p>
|
|
</li>
|
|
<li>
|
|
<p>Hard links and symbolic links can redirect the effect of
|
|
file system operations in unexpected ways. The
|
|
<code>O_NOFOLLOW</code> and
|
|
<code>AT_SYMLINK_NOFOLLOW</code> variants of system
|
|
calls only affected final path name component.</p>
|
|
</li>
|
|
<li>
|
|
<p>The structure of a directory tree can change. For example,
|
|
the parent directory of what used to be a subdirectory
|
|
within the directory tree being processed could suddenly
|
|
point outside that directory tree.</p>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Files should always be created with the
|
|
<code>O_CREAT</code> and <code>O_EXCL</code> flags,
|
|
so that creating the file will fail if it already exists. This
|
|
guards against the unexpected appearance of file names, either
|
|
due to creation of a new file, or hard-linking of an existing
|
|
file. In multi-threaded programs, rather than manipulating the
|
|
umask, create the files with mode <code>000</code> if
|
|
possible, and adjust it afterwards with
|
|
<code>fchmod</code>.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>To avoid issues related to symbolic links and directory tree
|
|
restructuring, the “<code>at</code>” variants of system
|
|
calls have to be used (that is, functions like
|
|
<code>openat</code>, <code>fchownat</code>,
|
|
<code>fchmodat</code>, and
|
|
<code>unlinkat</code>, together with
|
|
<code>O_NOFOLLOW</code> or
|
|
<code>AT_SYMLINK_NOFOLLOW</code>). Path names passed to
|
|
these functions must have just a single component (that is,
|
|
without a slash). When descending, the descriptors of parent
|
|
directories must be kept open. The missing
|
|
<code>opendirat</code> function can be emulated with
|
|
<code>openat</code> (with an
|
|
<code>O_DIRECTORY</code> flag, to avoid opening special
|
|
files with side effects), followed by
|
|
<code>fdopendir</code>.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>If the “<code>at</code>” functions are not available, it
|
|
is possible to emulate them by changing the current directory.
|
|
(Obviously, this only works if the process is not multi-threaded.)
|
|
<code>fchdir</code> has to be used to change the current
|
|
directory, and the descriptors of the parent directories have to
|
|
be kept open, just as with the “<code>at</code>”-based
|
|
approach. <code>chdir("…​")</code> is unsafe because it
|
|
might ascend outside the intended directory tree.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>This “<code>at</code>” function emulation is currently
|
|
required when manipulating extended attributes. In this case,
|
|
the <code>lsetxattr</code> function can be used, with a
|
|
relative path name consisting of a single component. This also
|
|
applies to SELinux contexts and the
|
|
<code>lsetfilecon</code> function.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Currently, it is not possible to avoid opening special files
|
|
<strong>and</strong> changes to files with hard links if the
|
|
directory containing them is owned by an untrusted user.
|
|
(Device nodes can be hard-linked, just as regular files.)
|
|
<code>fchmodat</code> and <code>fchownat</code>
|
|
affect files whose link count is greater than one. But opening
|
|
the files, checking that the link count is one with
|
|
<code>fstat</code>, and using
|
|
<code>fchmod</code> and <code>fchown</code> on
|
|
the file descriptor may have unwanted side effects, due to item
|
|
2 above. When creating directories, it is therefore important
|
|
to change the ownership and permissions only after it has been
|
|
fully created. Until that point, file names are stable, and no
|
|
files with unexpected hard links can be introduced.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Similarly, when just reading a directory owned by an untrusted
|
|
user, it is currently impossible to reliably avoid opening
|
|
special files.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>There is no workaround against the instability of the file list
|
|
returned by <code>readdir</code>. Concurrent
|
|
modification of the directory can result in a list of files
|
|
being returned which never actually existed on disk.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Hard links and symbolic links can be safely deleted using
|
|
<code>unlinkat</code> without further checks because
|
|
deletion only affects the name within the directory tree being
|
|
processed.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="sect-Defensive_Coding-Tasks-File_System-Foreign"><a class="anchor" href="#sect-Defensive_Coding-Tasks-File_System-Foreign"></a>Accessing the File System as a Different User</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>This section deals with access to the file system as a specific
|
|
user. This is different from accessing files and directories owned by a
|
|
different, potentially untrusted user; see <a href="#sect-Defensive_Coding-Tasks-File_System-Foreign">Accessing the File System as a Different User</a>.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>One approach is to spawn a child process which runs under the
|
|
target user and group IDs (both effective and real IDs). Note
|
|
that this child process can block indefinitely, even when
|
|
processing regular files only. For example, a special FUSE file
|
|
system could cause the process to hang in uninterruptible sleep
|
|
inside a <code>stat</code> system call.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>An existing process could change its user and group ID using
|
|
<code>setfsuid</code> and <code>setfsgid</code>.
|
|
(These functions are preferred over <code>seteuid</code>
|
|
and <code>setegid</code> because they do not allow the
|
|
impersonated user to send signals to the process.) These
|
|
functions are not thread safe. In multi-threaded processes,
|
|
these operations need to be performed in a single-threaded child
|
|
process. Unexpected blocking may occur as well.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>It is not recommended to try to reimplement the kernel
|
|
permission checks in user space because the required checks are
|
|
complex. It is also very difficult to avoid race conditions
|
|
during path name resolution.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="sect-Defensive_Coding-Tasks-File_System-Limits"><a class="anchor" href="#sect-Defensive_Coding-Tasks-File_System-Limits"></a>File System Limits</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>For historical reasons, there are preprocessor constants such as
|
|
<code>PATH_MAX</code>, <code>NAME_MAX</code>.
|
|
However, on most systems, the length of canonical path names
|
|
(absolute path names with all symbolic links resolved, as
|
|
returned by <code>realpath</code> or
|
|
<code>canonicalize_file_name</code>) can exceed
|
|
<code>PATH_MAX</code> bytes, and individual file name
|
|
components can be longer than <code>NAME_MAX</code>. This
|
|
is also true of the <code>_PC_PATH_MAX</code> and
|
|
<code>_PC_NAME_MAX</code> values returned by
|
|
<code>pathconf</code>, and the
|
|
<code>f_namemax</code> member of <code>struct
|
|
statvfs</code>. Therefore, these constants should not be
|
|
used. This is also reason why the
|
|
<code>readdir_r</code> should never be used (instead,
|
|
use <code>readdir</code>).</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>You should not write code in a way that assumes that there is an
|
|
upper limit on the number of subdirectories of a directory, the
|
|
number of regular files in a directory, or the link count of an
|
|
inode.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="sect-Defensive_Coding-Tasks-File_System-Features"><a class="anchor" href="#sect-Defensive_Coding-Tasks-File_System-Features"></a>File system features</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>Not all file systems support all features. This makes it very
|
|
difficult to write general-purpose tools for copying files. For
|
|
example, a copy operation intending to preserve file permissions
|
|
will generally fail when copying to a FAT file system.</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>Some file systems are case-insensitive. Most should be
|
|
case-preserving, though.</p>
|
|
</li>
|
|
<li>
|
|
<p>Name length limits vary greatly, from eight to thousands of
|
|
bytes. Path length limits differ as well. Most systems
|
|
impose an upper bound on path names passed to the kernel,
|
|
but using relative path names, it is possible to create and
|
|
access files whose absolute path name is essentially of
|
|
unbounded length.</p>
|
|
</li>
|
|
<li>
|
|
<p>Some file systems do not store names as fairly unrestricted
|
|
byte sequences, as it has been traditionally the case on GNU
|
|
systems. This means that some byte sequences (outside the
|
|
POSIX safe character set) are not valid names. Conversely,
|
|
names of existing files may not be representable as byte
|
|
sequences, and the files are thus inaccessible on GNU
|
|
systems. Some file systems perform Unicode canonicalization
|
|
on file names. These file systems preserve case, but
|
|
reading the name of a just-created file using
|
|
<code>readdir</code> might still result in a
|
|
different byte sequence.</p>
|
|
</li>
|
|
<li>
|
|
<p>Permissions and owners are not universally supported (and
|
|
SUID/SGID bits may not be available). For example, FAT file
|
|
systems assign ownership based on a mount option, and
|
|
generally mark all files as executable. Any attempt to
|
|
change permissions would result in an error.</p>
|
|
</li>
|
|
<li>
|
|
<p>Non-regular files (device nodes, FIFOs) are not generally
|
|
available.</p>
|
|
</li>
|
|
<li>
|
|
<p>Only on some file systems, files can have holes, that is,
|
|
not all of their contents is backed by disk storage.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>ioctl</code> support (even fairly generic
|
|
functionality such as <code>FIEMAP</code> for
|
|
discovering physical file layout and holes) is
|
|
file-system-specific.</p>
|
|
</li>
|
|
<li>
|
|
<p>Not all file systems support extended attributes, ACLs and
|
|
SELinux metadata. Size and naming restriction on extended
|
|
attributes vary.</p>
|
|
</li>
|
|
<li>
|
|
<p>Hard links may not be supported at all (FAT) or only within
|
|
the same directory (AFS). Symbolic links may not be
|
|
available, either. Reflinks (hard links with copy-on-write
|
|
semantics) are still very rare. Recent systems restrict
|
|
creation of hard links to users which own the target file or
|
|
have read/write access to it, but older systems do not.</p>
|
|
</li>
|
|
<li>
|
|
<p>Renaming (or moving) files using <code>rename</code>
|
|
can fail (even when <code>stat</code> indicates that
|
|
the source and target directories are located on the same
|
|
file system). This system call should work if the old and
|
|
new paths are located in the same directory, though.</p>
|
|
</li>
|
|
<li>
|
|
<p>Locking semantics vary among file systems. This affects
|
|
advisory and mandatory locks. For example, some network
|
|
file systems do not allow deleting files which are opened by
|
|
any process.</p>
|
|
</li>
|
|
<li>
|
|
<p>Resolution of time stamps varies from two seconds to
|
|
nanoseconds. Not all time stamps are available on all file
|
|
systems. File creation time (<strong>birth
|
|
time</strong>) is not exposed over the
|
|
<code>stat</code>/<code>fstat</code>
|
|
interface, even if stored by the file system.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect1">
|
|
<h2 id="sect-Defensive_Coding-Tasks-File_System-Free_Space"><a class="anchor" href="#sect-Defensive_Coding-Tasks-File_System-Free_Space"></a>Checking Free Space</h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>The <code>statvfs</code> and
|
|
<code>fstatvfs</code> functions allow programs to
|
|
examine the number of available blocks and inodes, through the
|
|
members <code>f_bfree</code>, <code>f_bavail</code>,
|
|
<code>f_ffree</code>, and <code>f_favail</code> of
|
|
<code>struct statvfs</code>. Some file systems return
|
|
fictional values in the <code>f_ffree</code> and
|
|
<code>f_favail</code> fields, so the only reliable way to
|
|
discover if the file system still has space for a file is to try
|
|
to create it. The <code>f_bfree</code> field should be
|
|
reasonably accurate, though.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="bottom" class="text-muted py-3" >
|
|
<div class="foot">
|
|
<div class="container">
|
|
<div class="row footerlinks">
|
|
<div class="col-sm-3 col-xs-6 widget">
|
|
<h3 class="widget-title">About</h3>
|
|
<div class="widget-body">
|
|
<dl>
|
|
<dd><a href="https://fedoraproject.org/wiki/Overview">About Fedora</a></dd>
|
|
<dd><a href="https://getfedora.org/en/sponsors">Sponsors</a></dd>
|
|
<dd><a href="https://fedoramagazine.org">Fedora Magazine</a></dd>
|
|
<dd><a href="https://fedoraproject.org/wiki/Legal:Main#Legal">Legal</a></dd>
|
|
</dl>
|
|
<ul class="list-inline">
|
|
<li>
|
|
<a href="https://www.facebook.com/TheFedoraProject" class="btn-social btn-outline"><i class="fa fa-fw fa-facebook"></i></a>
|
|
</li>
|
|
<li>
|
|
<a href="https://plus.google.com/112917221531140868607" class="btn-social btn-outline"><i class="fa fa-fw fa-google-plus"></i></a>
|
|
</li>
|
|
<li>
|
|
<a href="https://twitter.com/fedora" class="btn-social btn-outline"><i class="fa fa-fw fa-twitter"></i></a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-sm-3 col-xs-6 widget">
|
|
<h3 class="widget-title uppercase">Download</h3>
|
|
<div class="widget-body">
|
|
<dl>
|
|
<dd><a href="https://getfedora.org/en/workstation/download">Get Fedora Workstation</a></dd>
|
|
<dd><a href="https://getfedora.org/en/server/download">Get Fedora Server</a></dd>
|
|
<dd><a href="https://getfedora.org/en/atomic/download">Get Fedora Atomic</a></dd>
|
|
<dd><a href="https://spins.fedoraproject.org">Fedora Spins</a></dd>
|
|
<dd><a href="https://labs.fedoraproject.org">Fedora Labs</a></dd>
|
|
<dd><a href="https://arm.fedoraproject.org">Fedora ARM<span class="sup">®</span></a></dd>
|
|
<dd><a href="https://alt.fedoraproject.org/">Alternative Downloads</a></dd>
|
|
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-sm-3 col-xs-6 widget">
|
|
<h3 class="widget-title">Support</h3>
|
|
<div class="widget-body">
|
|
<dl>
|
|
<dd><a href="https://fedoraproject.org/wiki/Communicating_and_getting_help">Get Help</a></dd>
|
|
<dd><a href="https://ask.fedoraproject.org/">Ask Fedora</a></dd>
|
|
<dd><a href="https://fedoraproject.org/wiki/Common_F27_bugs">Common Bugs</a></dd>
|
|
<dd><a href="https://developer.fedoraproject.org/">Fedora Developer Portal</a></dd>
|
|
<dd><a href="https://docs.fedoraproject.org/f27/install-guide/index.html">Installation Guide</a></dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-sm-3 col-xs-6 widget">
|
|
<h3 class="widget-title">Join</h3>
|
|
<div class="widget-body">
|
|
<dl>
|
|
<dd><a href="https://fedoraproject.org/wiki/Join">Join Fedora</a></dd>
|
|
<dd><a href="http://fedoraplanet.org">Planet Fedora</a></dd>
|
|
<dd><a href="https://fedoraproject.org/wiki/SIGs">Fedora SIGs</a></dd>
|
|
<dd><a href="https://admin.fedoraproject.org/accounts/">Fedora Account System</a></dd>
|
|
<dd><a href="https://fedoracommunity.org/">Fedora Community</a></dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
</div> <!-- /row of widgets -->
|
|
|
|
<div class="row">
|
|
<div class="col-md-2">
|
|
<div class="widget-body">
|
|
<a href="https://www.redhat.com/"><img class="rh-logo" src="../../../master/_images/redhat-logo.png" alt="Red Hat Logo" /></a>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-7">
|
|
<div class="widget-body">
|
|
<p class="sponsor">Fedora is sponsored by Red Hat.</p>
|
|
<p class="sponsor"><a href="https://www.redhat.com/en/technologies/linux-platforms/articles/relationship-between-fedora-and-rhel">Learn more about the relationship between Red Hat and Fedora »</a></p>
|
|
<p class="copy">© 2017 Red Hat, Inc. and others. Please send any comments or corrections to the <a href="https://pagure.io/fedora-docs/docs-fp-o">documentation team</a></p>
|
|
</div>
|
|
</div>
|
|
</div> <!-- /row of widgets -->
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
|
<!-- Latest compiled and minified JavaScript -->
|
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
|
|
<script src="../../../master/_javascripts/bootstrap-offcanvas.js" type="text/javascript"></script>
|
|
<script type="text/javascript">
|
|
/*<![CDATA[*/
|
|
$(document).ready(function() {
|
|
$("[id^='topicGroup']").on('show.bs.collapse', function (event) {
|
|
if (!($(event.target).attr('id').match(/^topicSubGroup/))) {
|
|
$(this).parent().find("[id^='tgSpan']").toggleClass("fa-angle-right fa-angle-down");
|
|
}
|
|
});
|
|
$("[id^='topicGroup']").on('hide.bs.collapse', function (event) {
|
|
if (!($(event.target).attr('id').match(/^topicSubGroup/))) {
|
|
$(this).parent().find("[id^='tgSpan']").toggleClass("fa-angle-right fa-angle-down");
|
|
}
|
|
});
|
|
$("[id^='topicSubGroup']").on('show.bs.collapse', function () {
|
|
$(this).parent().find("[id^='sgSpan']").toggleClass("fa-caret-right fa-caret-down");
|
|
});
|
|
$("[id^='topicSubGroup']").on('hide.bs.collapse', function () {
|
|
$(this).parent().find("[id^='sgSpan']").toggleClass("fa-caret-right fa-caret-down");
|
|
});
|
|
});
|
|
/*]]>*/
|
|
</script>
|
|
</body>
|
|
</html> |