472 lines
22 KiB
HTML
472 lines
22 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 | Temporary Files</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">
|
||
|
Temporary Files
|
||
|
</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="" href="../../en-US/tasks/Tasks-File_System.html">File System Manipulation</a></li>
|
||
|
<li><a class=" active" 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>Temporary Files</h2>
|
||
|
</div>
|
||
|
<div id="preamble">
|
||
|
<div class="sectionbody">
|
||
|
<div class="paragraph">
|
||
|
<p>In this chapter, we describe how to create temporary files and
|
||
|
directories, how to remove them, and how to work with programs
|
||
|
which do not create files in ways that are safe with a shared
|
||
|
directory for temporary files. General file system manipulation
|
||
|
is treated in a separate chapter, <a href="#chap-Defensive_Coding-Tasks-File_System">[chap-Defensive_Coding-Tasks-File_System]</a>.</p>
|
||
|
</div>
|
||
|
<div class="paragraph">
|
||
|
<p>Secure creation of temporary files has four different aspects.</p>
|
||
|
</div>
|
||
|
<div class="ulist">
|
||
|
<ul>
|
||
|
<li>
|
||
|
<p>The location of the directory for temporary files must be
|
||
|
obtained in a secure manner (that is, untrusted environment
|
||
|
variables must be ignored, see <a href="#sect-Defensive_Coding-Tasks-secure_getenv">[sect-Defensive_Coding-Tasks-secure_getenv]</a>).</p>
|
||
|
</li>
|
||
|
<li>
|
||
|
<p>A new file must be created. Reusing an existing file must be
|
||
|
avoided (the <code>/tmp</code> race
|
||
|
condition). This is tricky because traditionally, system-wide
|
||
|
temporary directories shared by all users are used.</p>
|
||
|
</li>
|
||
|
<li>
|
||
|
<p>The file must be created in a way that makes it impossible for
|
||
|
other users to open it.</p>
|
||
|
</li>
|
||
|
<li>
|
||
|
<p>The descriptor for the temporary file should not leak to
|
||
|
subprocesses.</p>
|
||
|
</li>
|
||
|
</ul>
|
||
|
</div>
|
||
|
<div class="paragraph">
|
||
|
<p>All functions mentioned below will take care of these aspects.</p>
|
||
|
</div>
|
||
|
<div class="paragraph">
|
||
|
<p>Traditionally, temporary files are often used to reduce memory
|
||
|
usage of programs. More and more systems use RAM-based file
|
||
|
systems such as <code>tmpfs</code> for storing temporary
|
||
|
files, to increase performance and decrease wear on Flash storage.
|
||
|
As a result, spooling data to temporary files does not result in
|
||
|
any memory savings, and the related complexity can be avoided if
|
||
|
the data is kept in process memory.</p>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="sect1">
|
||
|
<h2 id="chap-Defensive_Coding-Tasks-Temporary_Files-Location"><a class="anchor" href="#chap-Defensive_Coding-Tasks-Temporary_Files-Location"></a>Obtaining the Location of Temporary Directory</h2>
|
||
|
<div class="sectionbody">
|
||
|
<div class="paragraph">
|
||
|
<p>Some functions below need the location of a directory which
|
||
|
stores temporary files. For C/C++ programs, use the following
|
||
|
steps to obtain that directory:</p>
|
||
|
</div>
|
||
|
<div class="ulist">
|
||
|
<ul>
|
||
|
<li>
|
||
|
<p>Use <code>secure_getenv</code> to obtain the value
|
||
|
of the <code>TMPDIR</code> environment variable. If
|
||
|
it is set, convert the path to a fully-resolved absolute
|
||
|
path, using <code>realpath(path, NULL)</code>. Check
|
||
|
if the new path refers to a directory and is writeable. In
|
||
|
this case, use it as the temporary directory.</p>
|
||
|
</li>
|
||
|
<li>
|
||
|
<p>Fall back to <code>/tmp</code>.</p>
|
||
|
</li>
|
||
|
</ul>
|
||
|
</div>
|
||
|
<div class="paragraph">
|
||
|
<p>In Python, you can use the <code>tempfile.tempdir</code>
|
||
|
variable.</p>
|
||
|
</div>
|
||
|
<div class="paragraph">
|
||
|
<p>Java does not support SUID/SGID programs, so you can use the
|
||
|
<code>java.lang.System.getenv(String)</code> method to
|
||
|
obtain the value of the <code>TMPDIR</code> environment
|
||
|
variable, and follow the two steps described above. (Java’s
|
||
|
default directory selection does not honor
|
||
|
<code>TMPDIR</code>.)</p>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="sect1">
|
||
|
<h2 id="named-temporary-files"><a class="anchor" href="#named-temporary-files"></a>Named Temporary Files</h2>
|
||
|
<div class="sectionbody">
|
||
|
<div class="paragraph">
|
||
|
<p>The <code>mkostemp</code> function creates a named
|
||
|
temporary file. You should specify the
|
||
|
<code>O_CLOEXEC</code> flag to avoid file descriptor leaks
|
||
|
to subprocesses. (Applications which do not use multiple threads
|
||
|
can also use <code>mkstemp</code>, but libraries should
|
||
|
use <code>mkostemp</code>.) For determining the
|
||
|
directory part of the file name pattern, see <a href="#chap-Defensive_Coding-Tasks-Temporary_Files-Location">Obtaining the Location of Temporary Directory</a>.</p>
|
||
|
</div>
|
||
|
<div class="paragraph">
|
||
|
<p>The file is not removed automatically. It is not safe to rename
|
||
|
or delete the file before processing, or transform the name in
|
||
|
any way (for example, by adding a file extension). If you need
|
||
|
multiple temporary files, call <code>mkostemp</code>
|
||
|
multiple times. Do not create additional file names derived
|
||
|
from the name provided by a previous
|
||
|
<code>mkostemp</code> call. However, it is safe to close
|
||
|
the descriptor returned by <code>mkostemp</code> and
|
||
|
reopen the file using the generated name.</p>
|
||
|
</div>
|
||
|
<div class="paragraph">
|
||
|
<p>The Python class <code>tempfile.NamedTemporaryFile</code>
|
||
|
provides similar functionality, except that the file is deleted
|
||
|
automatically by default. Note that you may have to use the
|
||
|
<code>file</code> attribute to obtain the actual file
|
||
|
object because some programming interfaces cannot deal with
|
||
|
file-like objects. The C function <code>mkostemp</code>
|
||
|
is also available as <code>tempfile.mkstemp</code>.</p>
|
||
|
</div>
|
||
|
<div class="paragraph">
|
||
|
<p>In Java, you can use the
|
||
|
<code>java.io.File.createTempFile(String, String,
|
||
|
File)</code> function, using the temporary file location
|
||
|
determined according to <a href="#chap-Defensive_Coding-Tasks-Temporary_Files-Location">Obtaining the Location of Temporary Directory</a>.
|
||
|
Do not use <code>java.io.File.deleteOnExit()</code> to
|
||
|
delete temporary files, and do not register a shutdown hook for
|
||
|
each temporary file you create. In both cases, the deletion
|
||
|
hint cannot be removed from the system if you delete the
|
||
|
temporary file prior to termination of the VM, causing a memory
|
||
|
leak.</p>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="sect1">
|
||
|
<h2 id="temporary-files-without-names"><a class="anchor" href="#temporary-files-without-names"></a>Temporary Files without Names</h2>
|
||
|
<div class="sectionbody">
|
||
|
<div class="paragraph">
|
||
|
<p>The <code>tmpfile</code> function creates a temporary
|
||
|
file and immediately deletes it, while keeping the file open.
|
||
|
As a result, the file lacks a name and its space is deallocated
|
||
|
as soon as the file descriptor is closed (including the implicit
|
||
|
close when the process terminates). This avoids cluttering the
|
||
|
temporary directory with orphaned files.</p>
|
||
|
</div>
|
||
|
<div class="paragraph">
|
||
|
<p>Alternatively, if the maximum size of the temporary file is
|
||
|
known beforehand, the <code>fmemopen</code> function can
|
||
|
be used to create a <code>FILE *</code> object which is
|
||
|
backed by memory.</p>
|
||
|
</div>
|
||
|
<div class="paragraph">
|
||
|
<p>In Python, unnamed temporary files are provided by the
|
||
|
<code>tempfile.TemporaryFile</code> class, and the
|
||
|
<code>tempfile.SpooledTemporaryFile</code> class provides
|
||
|
a way to avoid creation of small temporary files.</p>
|
||
|
</div>
|
||
|
<div class="paragraph">
|
||
|
<p>Java does not support unnamed temporary files.</p>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="sect1">
|
||
|
<h2 id="chap-Defensive_Coding-Tasks-Temporary_Directory"><a class="anchor" href="#chap-Defensive_Coding-Tasks-Temporary_Directory"></a>Temporary Directories</h2>
|
||
|
<div class="sectionbody">
|
||
|
<div class="paragraph">
|
||
|
<p>The <code>mkdtemp</code> function can be used to create
|
||
|
a temporary directory. (For determining the directory part of
|
||
|
the file name pattern, see <a href="#chap-Defensive_Coding-Tasks-Temporary_Files-Location">Obtaining the Location of Temporary Directory</a>.)
|
||
|
The directory is not automatically removed. In Python, this
|
||
|
function is available as <code>tempfile.mkdtemp</code>.
|
||
|
In Java 7, temporary directories can be created using the
|
||
|
<code>java.nio.file.Files.createTempDirectory(Path, String,
|
||
|
FileAttribute…​)</code> function.</p>
|
||
|
</div>
|
||
|
<div class="paragraph">
|
||
|
<p>When creating files in the temporary directory, use
|
||
|
automatically generated names, e.g., derived from a sequential
|
||
|
counter. Files with externally provided names could be picked
|
||
|
up in unexpected contexts, and crafted names could actually
|
||
|
point outside of the tempoary directory (due to
|
||
|
<strong>directory traversal</strong>).</p>
|
||
|
</div>
|
||
|
<div class="paragraph">
|
||
|
<p>Removing a directory tree in a completely safe manner is
|
||
|
complicated. Unless there are overriding performance concerns,
|
||
|
the <strong class="application">rm</strong> program should be used, with
|
||
|
the <code class="option">-rf</code> and <code class="option">--</code> options.</p>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="sect1">
|
||
|
<h2 id="compensating-for-unsafe-file-creation"><a class="anchor" href="#compensating-for-unsafe-file-creation"></a>Compensating for Unsafe File Creation</h2>
|
||
|
<div class="sectionbody">
|
||
|
<div class="paragraph">
|
||
|
<p>There are two ways to make a function or program which excepts a
|
||
|
file name safe for use with temporary files. See
|
||
|
<a href="#sect-Defensive_Coding-Tasks-Processes-Creation">[sect-Defensive_Coding-Tasks-Processes-Creation]</a>,
|
||
|
for details on subprocess creation.</p>
|
||
|
</div>
|
||
|
<div class="ulist">
|
||
|
<ul>
|
||
|
<li>
|
||
|
<p>Create a temporary directory and place the file there. If
|
||
|
possible, run the program in a subprocess which uses the
|
||
|
temporary directory as its current directory, with a
|
||
|
restricted environment.
|
||
|
Use generated names for all files in that temporary
|
||
|
directory. (See <a href="#chap-Defensive_Coding-Tasks-Temporary_Directory">Temporary Directories</a>.)</p>
|
||
|
</li>
|
||
|
<li>
|
||
|
<p>Create the temporary file and pass the generated file name
|
||
|
to the function or program. This only works if the function
|
||
|
or program can cope with a zero-length existing file. It is
|
||
|
safe only under additional assumptions:</p>
|
||
|
<div class="ulist">
|
||
|
<ul>
|
||
|
<li>
|
||
|
<p>The function or program must not create additional files
|
||
|
whose name is derived from the specified file name or
|
||
|
are otherwise predictable.</p>
|
||
|
</li>
|
||
|
<li>
|
||
|
<p>The function or program must not delete the file before
|
||
|
processing it.</p>
|
||
|
</li>
|
||
|
<li>
|
||
|
<p>It must not access any existing files in the same
|
||
|
directory.</p>
|
||
|
<div class="paragraph">
|
||
|
<p>It is often difficult to check whether these additional
|
||
|
assumptions are matched, therefore this approach is not
|
||
|
recommended.</p>
|
||
|
</div>
|
||
|
</li>
|
||
|
</ul>
|
||
|
</div>
|
||
|
</li>
|
||
|
</ul>
|
||
|
</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>
|