1090 lines
No EOL
88 KiB
HTML
1090 lines
No EOL
88 KiB
HTML
|
||
<!DOCTYPE html>
|
||
|
||
|
||
|
||
|
||
<html lang="en">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||
|
||
<title>2.6. The UNIX File Abstraction — Computer Systems Fundamentals</title>
|
||
|
||
<link rel="stylesheet" href="_static/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />
|
||
<link rel="stylesheet" href="_static/css/pygments.css" type="text/css" />
|
||
<link rel="stylesheet" href="_static/css/normalize.css" type="text/css" />
|
||
<link rel="stylesheet" href="../../../JSAV/css/JSAV.css" type="text/css" />
|
||
<link rel="stylesheet" href="../../../lib/odsaMOD-min.css" type="text/css" />
|
||
<link rel="stylesheet" href="_static/css/jquery-1.11.4-smoothness-ui.css" type="text/css" />
|
||
<link rel="stylesheet" href="../../../lib/odsaStyle-min.css" type="text/css" />
|
||
<link rel="stylesheet" href="_static/css/csf.css" type="text/css" />
|
||
|
||
<style>
|
||
.underline { text-decoration: underline; }
|
||
</style>
|
||
|
||
<script type="text/javascript">
|
||
var DOCUMENTATION_OPTIONS = {
|
||
URL_ROOT: './',
|
||
VERSION: '0.4.1',
|
||
COLLAPSE_INDEX: false,
|
||
FILE_SUFFIX: '.html',
|
||
HAS_SOURCE: true
|
||
};
|
||
</script>
|
||
|
||
<script type="text/x-mathjax-config">
|
||
MathJax.Hub.Config({
|
||
tex2jax: {
|
||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||
displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
|
||
processEscapes: true
|
||
},
|
||
"HTML-CSS": {
|
||
scale: "80"
|
||
}
|
||
});
|
||
</script>
|
||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||
<link rel="index" title="Index" href="genindex.html" />
|
||
<link rel="search" title="Search" href="search.html" />
|
||
<link rel="index" title="Computer Systems Fundamentals" href="index.html" />
|
||
<link rel="next" title="7. Events and Signals" href="EventsSignals.html" />
|
||
<link rel="prev" title="5. Process Life Cycle" href="ProcessCycle.html" />
|
||
|
||
</head><body>
|
||
|
||
<nav class="navbar navbar-expand-md navbar-dark navbar-custom fixed-top">
|
||
|
||
<a class="navbar-brand py-0" href="index.html"><img src="_static/CSF-Logo-Square-Text.png" alt="OpenCSF Logo" height="40em" class="py-1 px-2 mb-0 align-center rounded-lg bg-white" /></a>
|
||
<!-- Show a navbar toggler on mobile -->
|
||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#defaultNavbars" aria-controls="defaultNavbars" aria-expanded="false" aria-label="Toggle navigation">
|
||
<span class="navbar-toggler-icon"></span>
|
||
</button>
|
||
<div class="collapse navbar-collapse" id="defaultNavbars">
|
||
<ul class="navbar-nav mr-auto">
|
||
<li class="nav-item dropdown">
|
||
<a class="nav-link dropdown-toggle jmu-gold rounded" href="UnixFile.html#" id="navbarDropdownChapters" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Contents</a>
|
||
<div class="dropdown-menu scrollable-menu" role="menu" aria-labelledby="navbarDropdownChapters">
|
||
<a class="dropdown-item" tabindex="-1" href="UnixFile.html#"><b>Chapter 1</b></a>
|
||
<a class="dropdown-item" href="IntroConcSysOverview.html"> 1.1. Introduction to Concurrent Systems</a>
|
||
<a class="dropdown-item" href="SysAndModels.html"> 1.2. Systems and Models</a>
|
||
<a class="dropdown-item" href="Themes.html"> 1.3. Themes and Guiding Principles</a>
|
||
<a class="dropdown-item" href="Architectures.html"> 1.4. System Architectures</a>
|
||
<a class="dropdown-item" href="StateModels.html"> 1.5. State Models in UML</a>
|
||
<a class="dropdown-item" href="SequenceModels.html"> 1.6. Sequence Models in UML</a>
|
||
<a class="dropdown-item" href="StateModelImplementation.html"> 1.7. Extended Example: State Model Implementation</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 2</b></a>
|
||
<a class="dropdown-item" href="ProcessesOverview.html"> 2.1. Processes and OS Basics</a>
|
||
<a class="dropdown-item" href="Multiprogramming.html"> 2.2. Processes and Multiprogramming</a>
|
||
<a class="dropdown-item" href="KernelMechanics.html"> 2.3. Kernel Mechanics</a>
|
||
<a class="dropdown-item" href="Syscall.html"> 2.4. System Call Interface</a>
|
||
<a class="dropdown-item" href="ProcessCycle.html"> 2.5. Process Life Cycle</a>
|
||
<a class="dropdown-item" href="UnixFile.html"> 2.6. The UNIX File Abstraction</a>
|
||
<a class="dropdown-item" href="EventsSignals.html"> 2.7. Events and Signals</a>
|
||
<a class="dropdown-item" href="Extended2Processes.html"> 2.8. Extended Example: Listing Files with Processes</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 3</b></a>
|
||
<a class="dropdown-item" href="IPCOverview.html"> 3.1. Concurrency with IPC</a>
|
||
<a class="dropdown-item" href="IPCModels.html"> 3.2. IPC Models</a>
|
||
<a class="dropdown-item" href="Pipes.html"> 3.3. Pipes and FIFOs</a>
|
||
<a class="dropdown-item" href="MMap.html"> 3.4. Shared Memory With Memory-mapped Files</a>
|
||
<a class="dropdown-item" href="POSIXvSysV.html"> 3.5. POSIX vs. System V IPC</a>
|
||
<a class="dropdown-item" href="MQueues.html"> 3.6. Message Passing With Message Queues</a>
|
||
<a class="dropdown-item" href="ShMem.html"> 3.7. Shared Memory</a>
|
||
<a class="dropdown-item" href="IPCSems.html"> 3.8. Semaphores</a>
|
||
<a class="dropdown-item" href="Extended3Bash.html"> 3.9. Extended Example: Bash-lite: A Simple Command-line Shell</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 4</b></a>
|
||
<a class="dropdown-item" href="SocketsOverview.html"> 4.1. Networked Concurrency</a>
|
||
<a class="dropdown-item" href="FiveLayer.html"> 4.2. The TCP/IP Internet Model</a>
|
||
<a class="dropdown-item" href="NetApps.html"> 4.3. Network Applications and Protocols</a>
|
||
<a class="dropdown-item" href="Sockets.html"> 4.4. The Socket Interface</a>
|
||
<a class="dropdown-item" href="TCPSockets.html"> 4.5. TCP Socket Programming: HTTP</a>
|
||
<a class="dropdown-item" href="UDPSockets.html"> 4.6. UDP Socket Programming: DNS</a>
|
||
<a class="dropdown-item" href="AppBroadcast.html"> 4.7. Application-Layer Broadcasting: DHCP</a>
|
||
<a class="dropdown-item" href="Extended4CGI.html"> 4.8. Extended Example: CGI Web Server</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 5</b></a>
|
||
<a class="dropdown-item" href="InternetOverview.html"> 5.1. The Internet and Connectivity</a>
|
||
<a class="dropdown-item" href="AppLayer.html"> 5.2. Application Layer: Overlay Networks</a>
|
||
<a class="dropdown-item" href="TransLayer.html"> 5.3. Transport Layer</a>
|
||
<a class="dropdown-item" href="NetSec.html"> 5.4. Network Security Fundamentals</a>
|
||
<a class="dropdown-item" href="NetLayer.html"> 5.5. Network Layer: IP</a>
|
||
<a class="dropdown-item" href="LinkLayer.html"> 5.6. Link Layer</a>
|
||
<a class="dropdown-item" href="Wireless.html"> 5.7. Wireless Connectivity: Wi-Fi, Bluetooth, and Zigbee</a>
|
||
<a class="dropdown-item" href="Extended5DNS.html"> 5.8. Extended Example: DNS client</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 6</b></a>
|
||
<a class="dropdown-item" href="ThreadsOverview.html"> 6.1. Concurrency with Multithreading</a>
|
||
<a class="dropdown-item" href="ProcVThreads.html"> 6.2. Processes vs. Threads</a>
|
||
<a class="dropdown-item" href="RaceConditions.html"> 6.3. Race Conditions and Critical Sections</a>
|
||
<a class="dropdown-item" href="POSIXThreads.html"> 6.4. POSIX Thread Library</a>
|
||
<a class="dropdown-item" href="ThreadArgs.html"> 6.5. Thread Arguments and Return Values</a>
|
||
<a class="dropdown-item" href="ImplicitThreads.html"> 6.6. Implicit Threading and Language-based Threads</a>
|
||
<a class="dropdown-item" href="Extended6Input.html"> 6.7. Extended Example: Keyboard Input Listener</a>
|
||
<a class="dropdown-item" href="Extended6Primes.html"> 6.8. Extended Example: Concurrent Prime Number Search</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 7</b></a>
|
||
<a class="dropdown-item" href="SynchOverview.html"> 7.1. Synchronization Primitives</a>
|
||
<a class="dropdown-item" href="CritSect.html"> 7.2. Critical Sections and Peterson's Solution</a>
|
||
<a class="dropdown-item" href="Locks.html"> 7.3. Locks</a>
|
||
<a class="dropdown-item" href="Semaphores.html"> 7.4. Semaphores</a>
|
||
<a class="dropdown-item" href="Barriers.html"> 7.5. Barriers</a>
|
||
<a class="dropdown-item" href="Condvars.html"> 7.6. Condition Variables</a>
|
||
<a class="dropdown-item" href="Deadlock.html"> 7.7. Deadlock</a>
|
||
<a class="dropdown-item" href="Extended7Events.html"> 7.8. Extended Example: Event Log File</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 8</b></a>
|
||
<a class="dropdown-item" href="SynchProblemsOverview.html"> 8.1. Synchronization Patterns and Problems</a>
|
||
<a class="dropdown-item" href="SynchDesign.html"> 8.2. Basic Synchronization Design Patterns</a>
|
||
<a class="dropdown-item" href="ProdCons.html"> 8.3. Producer-Consumer Problem</a>
|
||
<a class="dropdown-item" href="ReadWrite.html"> 8.4. Readers-Writers Problem</a>
|
||
<a class="dropdown-item" href="DiningPhil.html"> 8.5. Dining Philosophers Problem and Deadlock</a>
|
||
<a class="dropdown-item" href="CigSmokers.html"> 8.6. Cigarette Smokers Problem and the Limits of Semaphores and Locks</a>
|
||
<a class="dropdown-item" href="Extended8ModExp.html"> 8.7. Extended Example: Parallel Modular Exponentiation</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 9</b></a>
|
||
<a class="dropdown-item" href="ParallelDistributedOverview.html"> 9.1. Parallel and Distributed Systems</a>
|
||
<a class="dropdown-item" href="ParVConc.html"> 9.2. Parallelism vs. Concurrency</a>
|
||
<a class="dropdown-item" href="ParallelDesign.html"> 9.3. Parallel Design Patterns</a>
|
||
<a class="dropdown-item" href="Scaling.html"> 9.4. Limits of Parallelism and Scaling</a>
|
||
<a class="dropdown-item" href="DistTiming.html"> 9.5. Timing in Distributed Environments</a>
|
||
<a class="dropdown-item" href="DistDataStorage.html"> 9.6. Reliable Data Storage and Location</a>
|
||
<a class="dropdown-item" href="DistConsensus.html"> 9.7. Consensus in Distributed Systems</a>
|
||
<a class="dropdown-item" href="Extended9Blockchain.html"> 9.8. Extended Example: Blockchain Proof-of-Work</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Appendix A</b></a>
|
||
<a class="dropdown-item" href="CLangOverview.html"> A.1. C Language Reintroduction</a>
|
||
<a class="dropdown-item" href="Debugging.html"> A.2. Documentation and Debugging</a>
|
||
<a class="dropdown-item" href="BasicTypes.html"> A.3. Basic Types and Pointers</a>
|
||
<a class="dropdown-item" href="Arrays.html"> A.4. Arrays, Structs, Enums, and Type Definitions</a>
|
||
<a class="dropdown-item" href="Functions.html"> A.5. Functions and Scope</a>
|
||
<a class="dropdown-item" href="Pointers.html"> A.6. Pointers and Dynamic Allocation</a>
|
||
<a class="dropdown-item" href="Strings.html"> A.7. Strings</a>
|
||
<a class="dropdown-item" href="FunctionPointers.html"> A.8. Function Pointers</a>
|
||
<a class="dropdown-item" href="Files.html"> A.9. Files</a>
|
||
</div>
|
||
</li>
|
||
|
||
|
||
|
||
</ul>
|
||
</div>
|
||
|
||
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||
<li class="nav-item"><a class="nav-link jmu-gold" href="https://w3.cs.jmu.edu/kirkpams/OpenCSF/Books/csf/source/UnixFile.rst"
|
||
target="_blank" rel="nofollow">Show Source</a></li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
|
||
<div class="container center">
|
||
«  <a id="prevmod" href="ProcessCycle.html">2.5. Process Life Cycle</a>
|
||
  ::  
|
||
<a class="uplink" href="index.html">Contents</a>
|
||
  ::  
|
||
<a id="nextmod" href="EventsSignals.html">2.7. Events and Signals</a>  »
|
||
|
||
</div>
|
||
<br />
|
||
|
||
|
||
|
||
<script type="text/javascript" src="_static/js/jquery-2.1.4.min.js"></script>
|
||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||
<script type="text/javascript" src="_static/js/jquery-1.11.4-ui.min.js"></script>
|
||
<script type="text/javascript" src="_static/js/forge-0.7.0.min.js"></script>
|
||
<script type="text/javascript" src="../../../JSAV/lib/jquery.transit.js"></script>
|
||
<script type="text/javascript" src="../../../JSAV/lib/raphael.js"></script>
|
||
<script type="text/javascript" src="../../../JSAV/build/JSAV-min.js"></script>
|
||
<script type="text/javascript" src="_static/js/config.js"></script>
|
||
<script type="text/javascript" src="../../../lib/odsaUtils-min.js"></script>
|
||
<script type="text/javascript" src="../../../lib/odsaMOD-min.js"></script>
|
||
<script type="text/javascript" src="_static/js/d3-4.13.0.min.js"></script>
|
||
<script type="text/javascript" src="_static/js/d3-selection-multi.v1.min.js"></script>
|
||
<script type="text/javascript" src="../../../lib/dataStructures.js"></script>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<div class="container">
|
||
|
||
<script>ODSA.SETTINGS.DISP_MOD_COMP = true;ODSA.SETTINGS.MODULE_NAME = "UnixFile";ODSA.SETTINGS.MODULE_LONG_NAME = "The UNIX File Abstraction";ODSA.SETTINGS.MODULE_CHAPTER = "Processes and OS Basics"; ODSA.SETTINGS.BUILD_DATE = "2021-06-14 17:15:25"; ODSA.SETTINGS.BUILD_CMAP = false;JSAV_OPTIONS['lang']='en';JSAV_EXERCISE_OPTIONS['code']='java';</script><div class="section" id="the-unix-file-abstraction">
|
||
<h1>2.6. The UNIX File Abstraction<a class="headerlink" href="UnixFile.html#the-unix-file-abstraction" title="Permalink to this headline">¶</a></h1>
|
||
<p>When multiple processes exist on a single machine, they rely on virtual memory to create the
|
||
illusion that they have sole access to the CPU; the context switch mechanism prevents one process
|
||
from accessing another process’s register values, stack, heap, etc. However, processes ultimately do
|
||
not have sole access to the entire machine. There are many resources, such as a network interface,
|
||
storage devices, user input devices, and so on, that must be shared with other processes on the same
|
||
machine. As such, processes act as a unit of ownership for instances of access to these resources.</p>
|
||
<p>The <a class="reference internal" href="Glossary.html#term-unix-file-abstraction"><span class="xref std std-term">UNIX file abstraction</span></a>, which is widely used in modern OS design, provides a uniform
|
||
interface to these various shared resources. This abstraction relies on two features: <strong>a file is a
|
||
sequence of bytes</strong> and <strong>everything is a file</strong>. It is important to emphasize that this definition
|
||
is different from the common usage of the term “file,” which is typically associated with persistent
|
||
data storage. The key differences between this common usage and the UNIX file abstraction are as follows:</p>
|
||
<blockquote>
|
||
<div><ul class="simple">
|
||
<li>Arbitrary or bidirectional access to a file is not necessarily possible. In some cases, once a
|
||
byte has been read from the file, that byte no longer exists in the file; there is no way to seek
|
||
to a previous position in such files. Similarly, sequential access of the bytes in order may be
|
||
required, with no way to skip ahead.</li>
|
||
<li>Files may not have names or persistent storage. Some files (such as those described in Chapter 3
|
||
for <a class="reference internal" href="Glossary.html#term-interprocess-communication"><span class="xref std std-term">interprocess communication</span></a>, commonly referred to as IPC) exist solely as in-memory
|
||
constructs at run-time, identified only by an integer <a class="reference internal" href="Glossary.html#term-file-descriptor"><span class="xref std std-term">file descriptor</span></a>. Other files (such as
|
||
<code class="docutils literal notranslate"><span class="pre">/dev/random</span></code> on UNIX and Linux systems) exist solely as an abstract interface to a hardware
|
||
component or generate data at run-time on demand.</li>
|
||
<li>Files do not necessarily have structure or typing. Readers are likely family with persistent files
|
||
that can be distinguished by a file extension. For instance, a file with the <code class="docutils literal notranslate"><span class="pre">.pdf</span></code> extension has
|
||
a different internal structure than one with a <code class="docutils literal notranslate"><span class="pre">.png</span></code> extension; programs that read or write
|
||
these files must make sure that the bytes adhere to a pre-defined semantic structure. However, in
|
||
the UNIX file abstraction, this pre-defined structure does not exist; a file is <cite>just</cite> a sequence of bytes.</li>
|
||
</ul>
|
||
</div></blockquote>
|
||
<p>By removing so much contextual information about files, this abstraction might seem to lose much of
|
||
its meaning or utility. On the contrary, this abstraction greatly simplifies the work of dealing
|
||
with a variety of resources; there are certain operations (creating, deleting, opening, closing,
|
||
reading, writing) that are common to the lifecycle of all files. The UNIX file abstraction provides
|
||
a single, consistent interface for these operations, thus eliminating much of the complexity of
|
||
supporting many such resources.</p>
|
||
<div class="section" id="basic-file-access">
|
||
<h2>2.6.1. Basic File Access<a class="headerlink" href="UnixFile.html#basic-file-access" title="Permalink to this headline">¶</a></h2>
|
||
<p>The most basic operations for working with files are creating and opening them. For files that can
|
||
be identified with named locations in the file system directory structure (such as <code class="docutils literal notranslate"><span class="pre">/dev/random</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">/usr/bin/cksum</span></code>, or <code class="docutils literal notranslate"><span class="pre">/home/csf/movies.csv</span></code>), we can use the <code class="docutils literal notranslate"><span class="pre">open()</span></code> function. The first
|
||
parameter is the path to the file; this path can be an <em>absolute path</em> (such as
|
||
<code class="docutils literal notranslate"><span class="pre">/dev/random</span></code>) or a <em>relative path</em> (such as <code class="docutils literal notranslate"><span class="pre">../src/main.c</span></code>) that describes the location
|
||
relative to the current working directory. If the file is successfully opened, the return value from
|
||
<code class="docutils literal notranslate"><span class="pre">open()</span></code> is the file descriptor, a non-negative integer value that other functions use to identify
|
||
the file. This value should typically be greater than 2, as the default behavior is to open three
|
||
files when a process is created: 0 (<code class="docutils literal notranslate"><span class="pre">STDIN_FILENO</span></code>) for standard input (such as reading from the
|
||
command prompt), 1 (<code class="docutils literal notranslate"><span class="pre">STDOUT_FILENO</span></code>) for standard output (such as writing out to the screen), and
|
||
2 (<code class="docutils literal notranslate"><span class="pre">STDERR_FILENO</span></code>) for standard error (also writing out to the screen).</p>
|
||
<div class="topic border border-dark rounded-lg bg-light px-2 mb-3">
|
||
<div class="figure align-left">
|
||
<a class="reference internal image-reference" href="_images/CSF-Images-Library.png"><img alt="Decorative C library image" src="_images/CSF-Images-Library.png" style="width: 100%;" /></a>
|
||
</div>
|
||
<p class="topic-title first pt-2 mb-1">C library functions – <fcntl.h></p><hr class="mt-1" />
|
||
<dl class="docutils">
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">open(const</span> <span class="pre">char</span> <span class="pre">*path,</span> <span class="pre">int</span> <span class="pre">oflag,</span> <span class="pre">...);</span></code></dt>
|
||
<dd>Open or create a file for reading or writing.</dd>
|
||
</dl>
|
||
</div>
|
||
<p>The second parameter (<code class="docutils literal notranslate"><span class="pre">oflag</span></code>) specifies how the file will be accessed by the current process.
|
||
<a class="reference external" href="UnixFile.html#tbl2-2">Table 2.2</a> shows the flags that may be passed as a bit-mask to <code class="docutils literal notranslate"><span class="pre">open()</span></code>. Note that these flags do
|
||
not necessarily align with the common notion of file permissions; a file that is accessible for both
|
||
reading and writing may be opened in read-only mode (<code class="docutils literal notranslate"><span class="pre">O_RDONLY</span></code>). However, if the file permissions
|
||
do not allow the requested access, <code class="docutils literal notranslate"><span class="pre">open()</span></code> will return -1.</p>
|
||
<center>
|
||
<div class="row-10">
|
||
<table class="table table-bordered">
|
||
<thead class="jmu-dark-purple-bg text-light">
|
||
<tr>
|
||
<th class="py-0 center">Permission</th>
|
||
<th class="py-0 center">Purpose</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td class="py-0"><code>O_RDONLY</code></td>
|
||
<td class="py-0">Open for reading only</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>O_WRONLY</code></td>
|
||
<td class="py-0">Open for writing only</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>O_RDWR</code></td>
|
||
<td class="py-0">Open for reading and writing</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>O_NONBLOCK</code></td>
|
||
<td class="py-0">Do not block on opening while waiting for data</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>O_CREAT</code></td>
|
||
<td class="py-0">Create the file if it does not exist; requires passing <code>mode_t</code> argument</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>O_TRUNC</code></td>
|
||
<td class="py-0">Truncate to size 0</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>O_EXCL</code></td>
|
||
<td class="py-0">Error if <code>O_CREAT</code> and the file exists</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Table 2.2: Flags for opening files</p>
|
||
</div>
|
||
</center><p>For the common usage of the term “file,” the <code class="docutils literal notranslate"><span class="pre">O_NONBLOCK</span></code> flag is the least intuitive in <a class="reference external" href="UnixFile.html#tbl2-2">Table
|
||
2.2</a>, as this flag is normally used for other purposes. Specifically, this flag plays an important
|
||
role in IPC and network programming. When using a file to communicate with other processes (either
|
||
on the same machine or across the network), the default behavior for reading is for processes to
|
||
<a class="reference internal" href="Glossary.html#term-blocking-i-o"><span class="xref std std-term">block</span></a> (pause) until the data has been received from the sender. The <code class="docutils literal notranslate"><span class="pre">O_NONBLOCK</span></code> flag
|
||
changes this behavior so that reading will immediately fail and the process can move on to other
|
||
work instead of waiting.</p>
|
||
<p><a class="reference external" href="UnixFile.html#cl2-12">Code Listing 2.12</a> illustrates how the flags can be combined as a bitmask using the bitwise-or
|
||
(<code class="docutils literal notranslate"><span class="pre">|</span></code>). In this case, the file is also being created (<code class="docutils literal notranslate"><span class="pre">O_CREAT</span></code>) with a size of 0 bytes initially
|
||
(<code class="docutils literal notranslate"><span class="pre">O_TRUNC</span></code>) and the current process will have write-only access (<code class="docutils literal notranslate"><span class="pre">O_WRONLY</span></code>). This file will be
|
||
persistent and stored in the file system with 644 permissions (6 = read and write for the owner of
|
||
the file, 4 = read-only for the associated group and others); as such, the file could later be
|
||
opened in read-write mode. Note that this third parameter (<code class="docutils literal notranslate"><span class="pre">mode</span></code>) is required when creating a new
|
||
file, but is ignored at other times.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl2-12"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0">1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 2.12:</span>
|
||
<span class="cm"> Creating a new (empty) file that is ready for writing</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="cm">/* This will create an empty file */</span>
|
||
<span class="kt">char</span> <span class="o">*</span><span class="n">path</span> <span class="o">=</span> <span class="s">"data.log"</span><span class="p">;</span>
|
||
<span class="kt">mode_t</span> <span class="n">mode</span> <span class="o">=</span> <span class="mo">0644</span><span class="p">;</span>
|
||
<span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">open</span> <span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">O_CREAT</span> <span class="o">|</span> <span class="n">O_TRUNC</span> <span class="o">|</span> <span class="n">O_WRONLY</span><span class="p">,</span> <span class="n">mode</span><span class="p">);</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>Once the file has been opened, it can be read from. The <code class="docutils literal notranslate"><span class="pre">read()</span></code> function takes three parameters:
|
||
the file descriptor, the address of a buffer in memory to read the bytes into, and the maximum
|
||
number of bytes to read. <a class="footnote-reference" href="UnixFile.html#f15" id="id2">[1]</a> The value returned from <code class="docutils literal notranslate"><span class="pre">read()</span></code> indicates the actual number of
|
||
bytes successfully read, which may be fewer than the <code class="docutils literal notranslate"><span class="pre">nbyte</span></code> parameter. (Calling <code class="docutils literal notranslate"><span class="pre">read()</span></code> with
|
||
<code class="docutils literal notranslate"><span class="pre">nbyte</span></code> set to 100 on a file that only contains 10 bytes of data will return 10, not 100.)
|
||
Finally, when the process is finished working with a file, the <code class="docutils literal notranslate"><span class="pre">close()</span></code> function will release any
|
||
associated resources in the kernel or the C library data that have been allocated for this process.</p>
|
||
<div class="topic border border-dark rounded-lg bg-light px-2 mb-3">
|
||
<div class="figure align-left">
|
||
<a class="reference internal image-reference" href="_images/CSF-Images-Library.png"><img alt="Decorative C library image" src="_images/CSF-Images-Library.png" style="width: 100%;" /></a>
|
||
</div>
|
||
<p class="topic-title first pt-2 mb-1">C library functions – <unistd.h></p><hr class="mt-1" />
|
||
<dl class="docutils">
|
||
<dt><code class="docutils literal notranslate"><span class="pre">ssize_t</span> <span class="pre">read(int</span> <span class="pre">fildes,</span> <span class="pre">void</span> <span class="pre">*buf,</span> <span class="pre">size_t</span> <span class="pre">nbyte);</span></code></dt>
|
||
<dd>Read up to nbyte bytes from a file into the buffer identified by buf.</dd>
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">close(int</span> <span class="pre">fildes);</span></code></dt>
|
||
<dd>Deletes a file descriptor.</dd>
|
||
</dl>
|
||
</div>
|
||
<div class="topic border border-dark rounded-lg alert-danger px-2 mb-3">
|
||
<div class="figure align-left">
|
||
<a class="reference internal image-reference" href="_images/CSF-Images-BugWarning.png"><img alt="Decorative bug warning" src="_images/CSF-Images-BugWarning.png" style="width: 90%;" /></a>
|
||
</div>
|
||
<p class="topic-title first pt-2 mb-1">Bug Warning</p><hr class="mt-1" />
|
||
<p>There are several key aspects of working with files that are easy to underestimate. First and
|
||
foremost is the importance of using a correct value for the <code class="docutils literal notranslate"><span class="pre">nbyte</span></code> parameter of <code class="docutils literal notranslate"><span class="pre">read()</span></code>. This
|
||
parameter always indicates the maximum number of bytes to read and it should never indicate more
|
||
than the size of the allocated buffer pointer. <a class="reference internal" href="Glossary.html#term-buffer-overflow"><span class="xref std std-term">Buffer overflows</span></a> are some
|
||
of the most dangerous and persistent sources of software vulnerabilities, and passing an incorrect
|
||
parameter to <code class="docutils literal notranslate"><span class="pre">read()</span></code> is a common culprit. Consider the following example:</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0">1
|
||
2
|
||
3
|
||
4</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Allocate a buffer of 2 bytes */</span>
|
||
<span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span> <span class="o">=</span> <span class="n">calloc</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="kt">char</span><span class="p">));</span>
|
||
<span class="cm">/* WRONG: This reads MORE THAN 2 bytes into the buffer */</span>
|
||
<span class="n">read</span> <span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">buffer</span><span class="p">));</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>The problem here is a misunderstanding of the <code class="docutils literal notranslate"><span class="pre">sizeof()</span></code> keyword, which returns the size of the
|
||
specified parameter. The misunderstanding is that <code class="docutils literal notranslate"><span class="pre">sizeof(buffer)</span></code> returns the size of a pointer
|
||
variable (8 bytes on a 64-bit system), not the size of the dynamically allocated buffer on the
|
||
heap. (Contrast this with lines 5 and 6 in <a class="reference external" href="UnixFile.html#cl2-13">Code Listing 2.13</a> below.) As such, this code is trying
|
||
to read up to 8 bytes of data into a buffer than can only hold 2 bytes. The result is that
|
||
<code class="docutils literal notranslate"><span class="pre">read()</span></code> will simply copy the additional 6 bytes into the memory <cite>after</cite> the end of the buffer,
|
||
potentially corrupting other data.</p>
|
||
<p>There are other frequent, though less serious, problems with using files. One (which is also in the
|
||
example above) is to call <code class="docutils literal notranslate"><span class="pre">read()</span></code> without checking its return value; programmers often assume
|
||
that the number of bytes read is the same as the number of bytes requested, which is not
|
||
necessarily true. To illustrate this, consider the possibility of calling <code class="docutils literal notranslate"><span class="pre">read()</span></code> on a file that
|
||
has been opened in <code class="docutils literal notranslate"><span class="pre">O_WRONLY</span></code> mode; <code class="docutils literal notranslate"><span class="pre">read()</span></code> would return -1 to indicate the operation failed.
|
||
Another problem is failing to call <code class="docutils literal notranslate"><span class="pre">close()</span></code>; this causes memory leaks, as allocated data is not
|
||
freed up appropriately. On the other hand, another problem can arise when a file descriptor is used
|
||
after the file has been closed; this can cause future reads to fail or (potentially even worse) to
|
||
read from the wrong file.</p>
|
||
</div>
|
||
<p><a class="reference external" href="UnixFile.html#cl2-13">Code Listing 2.13</a> illustrates how to open, read from, and close a file. In this example, we are
|
||
reading from a special file known as <code class="docutils literal notranslate"><span class="pre">/dev/random</span></code>. This file can be used to generate a sequence
|
||
of random numbers one byte at a time; every time this code runs, the result should be different.
|
||
Note that the file is closed on line 13, but the data is not used by the program until line 17. This
|
||
is not a problem, as the data was read into the process’s memory; that is, the <code class="docutils literal notranslate"><span class="pre">read()</span></code> operation
|
||
has made a copy of the data on the stack, so access to the file is no longer necessary.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl2-13"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
16
|
||
17
|
||
18</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 2.13:</span>
|
||
<span class="cm"> Reading 10 random numbers using the /dev/random file</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="kt">uint8_t</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">10</span><span class="p">];</span> <span class="c1">// space allocated automatically on the stack</span>
|
||
<span class="n">memset</span> <span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">buffer</span><span class="p">));</span>
|
||
|
||
<span class="cm">/* /dev/random is a special device file that produces an</span>
|
||
<span class="cm"> unending stream of random numbers */</span>
|
||
<span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">open</span> <span class="p">(</span><span class="s">"/dev/random"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="p">);</span>
|
||
<span class="n">assert</span> <span class="p">(</span><span class="n">fd</span> <span class="o">></span> <span class="mi">0</span><span class="p">);</span>
|
||
<span class="kt">ssize_t</span> <span class="n">bytes</span> <span class="o">=</span> <span class="n">read</span> <span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">buffer</span><span class="p">));</span>
|
||
<span class="n">close</span> <span class="p">(</span><span class="n">fd</span><span class="p">);</span>
|
||
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"Read %zd bytes of random data:</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">bytes</span><span class="p">);</span>
|
||
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">bytes</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">" %02"</span> <span class="n">PRIx8</span><span class="p">,</span> <span class="n">buffer</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>Some files, particularly IPC and device interface files, require special handling when reading.
|
||
Recall that the default behavior for open files is to block until data is ready; this behavior is
|
||
undesirable when other productive work could be done. For instance, a web server that is blocking
|
||
while trying to read data from one client could be missing out on connection requests from other
|
||
clients. The <code class="docutils literal notranslate"><span class="pre">poll()</span></code> function provides a useful interface for avoiding this situation.</p>
|
||
<div class="topic border border-dark rounded-lg bg-light px-2 mb-3">
|
||
<div class="figure align-left">
|
||
<a class="reference internal image-reference" href="_images/CSF-Images-Library.png"><img alt="Decorative C library image" src="_images/CSF-Images-Library.png" style="width: 100%;" /></a>
|
||
</div>
|
||
<p class="topic-title first pt-2 mb-1">C library functions – <poll.h></p><hr class="mt-1" />
|
||
<dl class="docutils">
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">poll(struct</span> <span class="pre">pollfd</span> <span class="pre">fds[],</span> <span class="pre">nfds_t</span> <span class="pre">nfds,</span> <span class="pre">int</span> <span class="pre">timeout);</span></code></dt>
|
||
<dd>Examine an array of file descriptors to determine if some are ready for I/O.</dd>
|
||
</dl>
|
||
</div>
|
||
<p>The first argument to <code class="docutils literal notranslate"><span class="pre">poll()</span></code> consists of an array of <code class="docutils literal notranslate"><span class="pre">struct</span> <span class="pre">pollfd</span></code> instances, the second
|
||
parameter is the length of the array, and the <code class="docutils literal notranslate"><span class="pre">timeout</span></code> designates a maximum amount of time
|
||
(measured in milliseconds) to wait for input to be ready. The fields of the <code class="docutils literal notranslate"><span class="pre">struct</span> <span class="pre">pollfd</span></code> are
|
||
shown below. For each <code class="docutils literal notranslate"><span class="pre">struct</span></code> in the array, the <code class="docutils literal notranslate"><span class="pre">fd</span></code> field designates a file descriptor to
|
||
monitor for input or output events, and the <code class="docutils literal notranslate"><span class="pre">events</span></code> field designates the events to wait for.
|
||
Typically, <code class="docutils literal notranslate"><span class="pre">events</span></code> is set to the constant <code class="docutils literal notranslate"><span class="pre">POLLIN</span></code> to indicate a check for the presence of
|
||
normal data that can be read without blocking. The <code class="docutils literal notranslate"><span class="pre">revents</span></code> field is set by the call to
|
||
<code class="docutils literal notranslate"><span class="pre">poll()</span></code>.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0">1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* defined in poll.h */</span>
|
||
<span class="k">struct</span> <span class="n">pollfd</span> <span class="p">{</span>
|
||
<span class="kt">int</span> <span class="n">fd</span><span class="p">;</span> <span class="cm">/* file descriptor */</span>
|
||
<span class="kt">short</span> <span class="n">events</span><span class="p">;</span> <span class="cm">/* events to look for */</span>
|
||
<span class="kt">short</span> <span class="n">revents</span><span class="p">;</span> <span class="cm">/* events returned */</span>
|
||
<span class="p">};</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p><a class="reference external" href="UnixFile.html#cl2-14">Code Listing 2.14</a> shows how to use <code class="docutils literal notranslate"><span class="pre">poll()</span></code> to check for available data. If <code class="docutils literal notranslate"><span class="pre">poll()</span></code> returns 0,
|
||
then the requested event (available input data) has not occurred before the timeout expired. The
|
||
<code class="docutils literal notranslate"><span class="pre">revents</span></code> field would be set to a value to indicate why the <code class="docutils literal notranslate"><span class="pre">poll()</span></code> failed. For instance,
|
||
<code class="docutils literal notranslate"><span class="pre">POLLHUP</span></code> indicates the device has been disconnected, <code class="docutils literal notranslate"><span class="pre">POLLNVAL</span></code> indicates the file descriptor
|
||
is not open, and <code class="docutils literal notranslate"><span class="pre">POLLERR</span></code> indicates an error has occurred with the device.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl2-14"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
16
|
||
17
|
||
18</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 2.14:</span>
|
||
<span class="cm"> Checking a file descriptor for available input data</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="cm">/* Set up a single pollfd for the file descriptor fd */</span>
|
||
<span class="k">struct</span> <span class="n">pollfd</span> <span class="n">fds</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
|
||
<span class="n">fds</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">fd</span> <span class="o">=</span> <span class="n">fd</span><span class="p">;</span>
|
||
<span class="n">fds</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">events</span> <span class="o">=</span> <span class="n">POLLIN</span><span class="p">;</span> <span class="c1">// Looking for input data</span>
|
||
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">poll</span> <span class="p">(</span><span class="n">fds</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="c1">// wait for 100 ms</span>
|
||
<span class="p">{</span>
|
||
<span class="cm">/* No data is available to be read */</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"Poll failed: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">fds</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">revents</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Close and exit if appropriate */</span>
|
||
<span class="n">close</span> <span class="p">(</span><span class="n">fd</span><span class="p">);</span>
|
||
<span class="n">exit</span> <span class="p">(</span><span class="mi">1</span><span class="p">);</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
</div>
|
||
<div class="section" id="working-with-files">
|
||
<h2>2.6.2. Working with Files<a class="headerlink" href="UnixFile.html#working-with-files" title="Permalink to this headline">¶</a></h2>
|
||
<p>In addition to reading, programs typically need to write to a file. The arguments to <code class="docutils literal notranslate"><span class="pre">write()</span></code> are
|
||
identical to those for <code class="docutils literal notranslate"><span class="pre">read()</span></code>. Unlike <code class="docutils literal notranslate"><span class="pre">read()</span></code>, there is not really a concern with buffer
|
||
overflow with <code class="docutils literal notranslate"><span class="pre">write()</span></code>, as data is being sent away from the current process; the kernel buffers
|
||
on the other end will prevent such errors. However, checking the return value from <code class="docutils literal notranslate"><span class="pre">write()</span></code> is as
|
||
important as it is with <code class="docutils literal notranslate"><span class="pre">read()</span></code> to make sure that all of the intended data was written
|
||
successfully; this is especially true when writing large pieces of data. <a class="reference external" href="UnixFile.html#cl2-15">Code Listing 2.15</a>
|
||
illustrates how to write to a file. Note that writing to the end of a persistent file will cause it
|
||
to grow. In this example, the file is created to be empty (<code class="docutils literal notranslate"><span class="pre">O_TRUNC</span></code>), but writing six bytes
|
||
creates a file of size six (the last byte is the null terminator <code class="docutils literal notranslate"><span class="pre">'\0'</span></code>).</p>
|
||
<div class="topic border border-dark rounded-lg bg-light px-2 mb-3">
|
||
<div class="figure align-left">
|
||
<a class="reference internal image-reference" href="_images/CSF-Images-Library.png"><img alt="Decorative C library image" src="_images/CSF-Images-Library.png" style="width: 100%;" /></a>
|
||
</div>
|
||
<p class="topic-title first pt-2 mb-1">C library functions – <unistd.h></p><hr class="mt-1" />
|
||
<dl class="docutils">
|
||
<dt><code class="docutils literal notranslate"><span class="pre">ssize_t</span> <span class="pre">write(int</span> <span class="pre">fildes,</span> <span class="pre">const</span> <span class="pre">void</span> <span class="pre">*buf,</span> <span class="pre">size_t</span> <span class="pre">nbyte);</span></code></dt>
|
||
<dd>Write up to nbyte bytes from a buffer into the specified file.</dd>
|
||
</dl>
|
||
</div>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl2-15"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
16
|
||
17
|
||
18
|
||
19
|
||
20
|
||
21</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 2.15:</span>
|
||
<span class="cm"> Creating an empty file and writing to it</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="cm">/* Create an empty file with read and write permissions */</span>
|
||
<span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">open</span> <span class="p">(</span><span class="s">"blank"</span><span class="p">,</span> <span class="n">O_CREAT</span> <span class="o">|</span> <span class="n">O_TRUNC</span><span class="p">,</span> <span class="n">S_IRUSR</span> <span class="o">|</span> <span class="n">S_IWUSR</span><span class="p">);</span>
|
||
<span class="n">close</span> <span class="p">(</span><span class="n">fd</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Open the file for writing (write will append) */</span>
|
||
<span class="n">fd</span> <span class="o">=</span> <span class="n">open</span> <span class="p">(</span><span class="s">"blank"</span><span class="p">,</span> <span class="n">O_WRONLY</span><span class="p">);</span>
|
||
<span class="n">assert</span> <span class="p">(</span><span class="n">fd</span> <span class="o">></span> <span class="mi">0</span><span class="p">);</span>
|
||
<span class="n">assert</span> <span class="p">(</span><span class="n">write</span> <span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="s">"hello"</span><span class="p">,</span> <span class="mi">6</span><span class="p">)</span> <span class="o">==</span> <span class="mi">6</span><span class="p">);</span>
|
||
<span class="n">close</span> <span class="p">(</span><span class="n">fd</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Read in what we just wrote */</span>
|
||
<span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">6</span><span class="p">];</span>
|
||
<span class="n">memset</span> <span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">buffer</span><span class="p">));</span>
|
||
<span class="n">fd</span> <span class="o">=</span> <span class="n">open</span> <span class="p">(</span><span class="s">"blank"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="p">);</span>
|
||
<span class="n">assert</span> <span class="p">(</span><span class="n">read</span> <span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="mi">6</span><span class="p">)</span> <span class="o">==</span> <span class="mi">6</span><span class="p">);</span>
|
||
<span class="n">close</span> <span class="p">(</span><span class="n">fd</span><span class="p">);</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"Contents: [%s]</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">buffer</span><span class="p">);</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>If the file supports arbitrary accesses, the <code class="docutils literal notranslate"><span class="pre">lseek()</span></code> function will change the file’s internal
|
||
location information to a specified target. The <code class="docutils literal notranslate"><span class="pre">offset</span></code> can be specified as either a positive or
|
||
negative value. The <code class="docutils literal notranslate"><span class="pre">whence</span></code> parameter, which takes a limited number of possible values, plays an
|
||
important role in determining this location. If <code class="docutils literal notranslate"><span class="pre">whence</span></code> if set to <code class="docutils literal notranslate"><span class="pre">SEEK_SET</span></code>, then the
|
||
<code class="docutils literal notranslate"><span class="pre">offset</span></code> argument is the exact number of bytes into the file to use as the location. Setting
|
||
<code class="docutils literal notranslate"><span class="pre">whence</span></code> to <code class="docutils literal notranslate"><span class="pre">SEEK_CUR</span></code> will add the <code class="docutils literal notranslate"><span class="pre">offset</span></code> to the current location number; a negative
|
||
<code class="docutils literal notranslate"><span class="pre">offset</span></code> will seek backwards, while a positive value seeks forward. Lastly, setting <code class="docutils literal notranslate"><span class="pre">whence</span></code> to
|
||
<code class="docutils literal notranslate"><span class="pre">SEEK_END</span></code> will add the <code class="docutils literal notranslate"><span class="pre">offset</span></code> to the size of the file; using a negative offset moves the
|
||
location to the number of bytes before the end of the file. Whichever value is passed, the final
|
||
location must be positive. If the location is larger than the file size, performing a write at that
|
||
point will increase the file size accordingly. Any gap between the existing end of the file and the
|
||
new data will be filled with null bytes.</p>
|
||
<div class="topic border border-dark rounded-lg bg-light px-2 mb-3">
|
||
<div class="figure align-left">
|
||
<a class="reference internal image-reference" href="_images/CSF-Images-Library.png"><img alt="Decorative C library image" src="_images/CSF-Images-Library.png" style="width: 100%;" /></a>
|
||
</div>
|
||
<p class="topic-title first pt-2 mb-1">C library functions – <unistd.h></p><hr class="mt-1" />
|
||
<dl class="docutils">
|
||
<dt><code class="docutils literal notranslate"><span class="pre">off_t</span> <span class="pre">lseek(int</span> <span class="pre">fildes,</span> <span class="pre">off_t</span> <span class="pre">offset,</span> <span class="pre">int</span> <span class="pre">whence);</span></code></dt>
|
||
<dd>Reposition the offset of a file descriptor to a specified location.</dd>
|
||
</dl>
|
||
</div>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl2-16"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
16
|
||
17
|
||
18
|
||
19
|
||
20
|
||
21
|
||
22
|
||
23
|
||
24
|
||
25</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 2.16:</span>
|
||
<span class="cm"> Growing a file with lseek() and write()</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="cm">/* Open and jump to offset 10 (4 bytes after the end) */</span>
|
||
<span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">open</span> <span class="p">(</span><span class="s">"blank"</span><span class="p">,</span> <span class="n">O_RDWR</span><span class="p">);</span>
|
||
<span class="kt">off_t</span> <span class="n">offset</span> <span class="o">=</span> <span class="n">lseek</span> <span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="n">SEEK_END</span><span class="p">);</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"Offset is now %lld</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">offset</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Write additional bytes, appending to the file */</span>
|
||
<span class="kt">size_t</span> <span class="n">bytes</span> <span class="o">=</span> <span class="n">write</span> <span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="s">"goodbye"</span><span class="p">,</span> <span class="mi">8</span><span class="p">);</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"Wrote %zd additional bytes</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">bytes</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Now read all of the file into a buffer and print it.</span>
|
||
<span class="cm"> Note that the file only contains 18 bytes */</span>
|
||
<span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">20</span><span class="p">];</span>
|
||
<span class="n">memset</span> <span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">buffer</span><span class="p">));</span>
|
||
<span class="n">offset</span> <span class="o">=</span> <span class="n">lseek</span> <span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">SEEK_SET</span><span class="p">);</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"Offset is now %lld</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">offset</span><span class="p">);</span>
|
||
<span class="n">assert</span> <span class="p">(</span><span class="n">read</span> <span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span> <span class="o">==</span> <span class="mi">18</span><span class="p">);</span>
|
||
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"Contents:</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
|
||
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">buffer</span><span class="p">);</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"%02x '%c'</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">buffer</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">buffer</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
|
||
<span class="n">close</span> <span class="p">(</span><span class="n">fd</span><span class="p">);</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p><a class="reference external" href="UnixFile.html#cl2-16">Code Listing 2.16</a> shows the effect of using <code class="docutils literal notranslate"><span class="pre">lseek()</span></code> and <code class="docutils literal notranslate"><span class="pre">write()</span></code> on the file created by Code
|
||
Listing 2.15. The file initially contained six bytes (<code class="docutils literal notranslate"><span class="pre">'h'</span></code>, <code class="docutils literal notranslate"><span class="pre">'e'</span></code>, <code class="docutils literal notranslate"><span class="pre">'l'</span></code>, <code class="docutils literal notranslate"><span class="pre">'l'</span></code>, <code class="docutils literal notranslate"><span class="pre">'o'</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">'\0'</span></code>). The seek on line 7 places the internal location to offset 10. The <code class="docutils literal notranslate"><span class="pre">write()</span></code> on line 11,
|
||
then, extends the file size to include the new data, as well as the padding of null bytes; the new
|
||
file size would then be 18 bytes. As such, the <code class="docutils literal notranslate"><span class="pre">read()</span></code> on line 20 requests 20 bytes but only gets
|
||
18. Printing the final file with <code class="docutils literal notranslate"><span class="pre">hexdump</span></code> shows the results:</p>
|
||
<div class="highlight-none border border-dark rounded-lg bg-light px-2 mb-3 notranslate"><div class="highlight bg-light"><pre class="mb-0"><span></span>00000000 68 65 6c 6c 6f 00 00 00 00 00 67 6f 6f 64 62 79 |hello.....goodby|
|
||
00000010 65 00 |e.|
|
||
00000012
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="accessing-file-metadata">
|
||
<h2>2.6.3. Accessing File Metadata<a class="headerlink" href="UnixFile.html#accessing-file-metadata" title="Permalink to this headline">¶</a></h2>
|
||
<p>When working with files, it is often important to access <a class="reference internal" href="Glossary.html#term-metadata"><span class="xref std std-term">metadata</span></a> – information about the
|
||
file – rather than the contents about the file itself. For instance, when reading a persistent file
|
||
into memory from storage, knowing the file’s size is necessary for allocating memory for the buffer.
|
||
As another example, consider an <em>intrusion detection</em> program that is responsible for
|
||
monitoring a file system for security threats or attacks; this program might check for changes to
|
||
the associated permissions or the user ID that is considered the owner of the file.</p>
|
||
<div class="topic border border-dark rounded-lg bg-light px-2 mb-3">
|
||
<div class="figure align-left">
|
||
<a class="reference internal image-reference" href="_images/CSF-Images-Library.png"><img alt="Decorative C library image" src="_images/CSF-Images-Library.png" style="width: 100%;" /></a>
|
||
</div>
|
||
<p class="topic-title first pt-2 mb-1">C library functions – <sys/stat.h></p><hr class="mt-1" />
|
||
<dl class="docutils">
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">fstat(int</span> <span class="pre">fildes,</span> <span class="pre">struct</span> <span class="pre">stat</span> <span class="pre">*buf);</span></code></dt>
|
||
<dd>Get status information about a file given an open file descriptor.</dd>
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">stat(const</span> <span class="pre">char</span> <span class="pre">*path,</span> <span class="pre">struct</span> <span class="pre">stat</span> <span class="pre">*buf);</span></code></dt>
|
||
<dd>Get status information about a file.</dd>
|
||
</dl>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">fstat()</span></code> and <code class="docutils literal notranslate"><span class="pre">stat()</span></code> functions provide an interface for accessing file metadata. Note that
|
||
<code class="docutils literal notranslate"><span class="pre">stat()</span></code> uses the path name of the file within the directory structure, which is appropriate for
|
||
the common notion of a file as persistent storage; however, <code class="docutils literal notranslate"><span class="pre">fstat()</span></code> works on any file
|
||
descriptor, which allows you to examine the metadata of any file, including unnamed IPC or device
|
||
files. Both functions take a pointer to a <code class="docutils literal notranslate"><span class="pre">struct</span> <span class="pre">stat</span></code>, writing the file metadata into this buffer.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* defined in sys/stat.h */</span>
|
||
<span class="k">struct</span> <span class="n">stat</span> <span class="p">{</span>
|
||
<span class="kt">dev_t</span> <span class="n">st_dev</span><span class="p">;</span> <span class="cm">/* device inode resides on */</span>
|
||
<span class="kt">ino_t</span> <span class="n">st_ino</span><span class="p">;</span> <span class="cm">/* inode's number */</span>
|
||
<span class="kt">mode_t</span> <span class="n">st_mode</span><span class="p">;</span> <span class="cm">/* inode protection mode */</span>
|
||
<span class="n">nlink_t</span> <span class="n">st_nlink</span><span class="p">;</span> <span class="cm">/* number of hard links to the file */</span>
|
||
<span class="kt">uid_t</span> <span class="n">st_uid</span><span class="p">;</span> <span class="cm">/* user-id of owner */</span>
|
||
<span class="kt">gid_t</span> <span class="n">st_gid</span><span class="p">;</span> <span class="cm">/* group-id of owner */</span>
|
||
<span class="kt">dev_t</span> <span class="n">st_rdev</span><span class="p">;</span> <span class="cm">/* device type, for special file inode */</span>
|
||
<span class="kt">off_t</span> <span class="n">st_size</span><span class="p">;</span> <span class="cm">/* file size, in bytes */</span>
|
||
<span class="cm">/* ... other fields depending on OS ... */</span>
|
||
<span class="p">};</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>This <code class="docutils literal notranslate"><span class="pre">struct</span></code> definition contains additional fields based on the particular operating system, but
|
||
the ones shown here are consistent across multiple platforms. A full discussion of all of these
|
||
fields is beyond the scope of this book, but a few of them are particularly important. To start,
|
||
consider the <code class="docutils literal notranslate"><span class="pre">st_ino</span></code> and <code class="docutils literal notranslate"><span class="pre">st_nlink</span></code> fields. Each file stored on typical storage device (USB
|
||
drive, hard drive, etc.) is uniquely identified by an <a class="reference internal" href="Glossary.html#term-inode"><span class="xref std std-term">inode</span></a>, an on-disk data structure that
|
||
contains the metadata; each inode is uniquely identified by an inode number (<code class="docutils literal notranslate"><span class="pre">st_ino</span></code>). However,
|
||
the file might have multiple human-readable names in the directory structure. These names –
|
||
<em>links</em> (also called <em>hard links</em>) – all point to the same file
|
||
contents; the <code class="docutils literal notranslate"><span class="pre">st_nlink</span></code> field indicates the number of links that exist to a single file. With
|
||
hard links, there is only one file; there are just multiple references to the same location. In
|
||
contrast a <em>symbolic link</em> is a distinct file that is not represented in the inode. See
|
||
Appendix A for a longer discussion of inodes and links.</p>
|
||
<p>Another key field of the <code class="docutils literal notranslate"><span class="pre">struct</span> <span class="pre">stat</span></code> is the <code class="docutils literal notranslate"><span class="pre">st_mode</span></code> field. The most common use of this field
|
||
is to set permissions for accessing the file. These permissions include combinations of read, write,
|
||
and execute for the owner of the file (the user), the associated group, or everyone else. The
|
||
<code class="docutils literal notranslate"><span class="pre">st_mode</span></code> field also stores additional permissions and information about the file; for instance,
|
||
this field can be used to distinguish symbolic links, regular files, or directories. <a class="reference external" href="UnixFile.html#tbl2-3">Table 2.3</a> shows
|
||
the standard list of bitmask values that can be combined in the <code class="docutils literal notranslate"><span class="pre">st_mode</span></code> field.</p>
|
||
<center>
|
||
<div class="row">
|
||
<div class="col-6 align-top">
|
||
<table class="table table-bordered">
|
||
<thead class="jmu-dark-purple-bg text-light">
|
||
<tr>
|
||
<th class="py-0 center">Name</th>
|
||
<th class="py-0 center">Bitmask</th>
|
||
<th class="py-0 center">Description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td class="py-0"><code>S_IRUSR</code></td>
|
||
<td class="py-0"><code>000400</code></td>
|
||
<td class="py-0">Read (user)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IWUSR</code></td>
|
||
<td class="py-0"><code>000200</code></td>
|
||
<td class="py-0">Write (user)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IXUSR</code></td>
|
||
<td class="py-0"><code>000100</code></td>
|
||
<td class="py-0">Execute (user)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IRGRP</code></td>
|
||
<td class="py-0"><code>000040</code></td>
|
||
<td class="py-0">Read (group)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IWGRP</code></td>
|
||
<td class="py-0"><code>000020</code></td>
|
||
<td class="py-0">Write (group)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IXGRP</code></td>
|
||
<td class="py-0"><code>000010</code></td>
|
||
<td class="py-0">Execute (group)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IROTH</code></td>
|
||
<td class="py-0"><code>000004</code></td>
|
||
<td class="py-0">Read (other)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IWOTH</code></td>
|
||
<td class="py-0"><code>000002</code></td>
|
||
<td class="py-0">Write (other)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IXOTH</code></td>
|
||
<td class="py-0"><code>000001</code></td>
|
||
<td class="py-0">Execute (other)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="col-6 align-top">
|
||
<table class="table table-bordered">
|
||
<thead class="jmu-dark-purple-bg text-light">
|
||
<tr>
|
||
<th class="py-0 center">Name</th>
|
||
<th class="py-0 center">Bitmask</th>
|
||
<th class="py-0 center">Description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td class="py-0"><code>S_IFIFO</code></td>
|
||
<td class="py-0"><code>010000</code></td>
|
||
<td class="py-0">Named pipe (IPC)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IFCHR</code></td>
|
||
<td class="py-0"><code>020000</code></td>
|
||
<td class="py-0">Character device (terminal)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IFDIR</code></td>
|
||
<td class="py-0"><code>040000</code></td>
|
||
<td class="py-0">Directory file type</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IFBLK</code></td>
|
||
<td class="py-0"><code>006000</code></td>
|
||
<td class="py-0">Block device (disk drive)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IFREG</code></td>
|
||
<td class="py-0"><code>100000</code></td>
|
||
<td class="py-0">Regular file type</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IFLNK</code></td>
|
||
<td class="py-0"><code>120000</code></td>
|
||
<td class="py-0">Symbolic link</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_IFSOCK</code></td>
|
||
<td class="py-0"><code>140000</code></td>
|
||
<td class="py-0">Socket (IPC, networks)</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_ISUID</code></td>
|
||
<td class="py-0"><code>004000</code></td>
|
||
<td class="py-0">Setuid (<code>SUID</code>) bit</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_ISGID</code></td>
|
||
<td class="py-0"><code>002000</code></td>
|
||
<td class="py-0">Setgid (<code>SGID</code>) bit</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="py-0"><code>S_ISVTX</code></td>
|
||
<td class="py-0"><code>001000</code></td>
|
||
<td class="py-0">Sticky bit</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<p>Table 2.3: Bitmasks used in the st_mode field</p>
|
||
</center><p>For example, the hello.c file above would have the bitmask <code class="docutils literal notranslate"><span class="pre">100644</span></code> (displayed as <code class="docutils literal notranslate"><span class="pre">-rw-r--r--</span></code>
|
||
by the <code class="docutils literal notranslate"><span class="pre">ls</span> <span class="pre">-l</span></code> command), as it is a regular file (<code class="docutils literal notranslate"><span class="pre">100000</span></code>) with read/write permissions for the
|
||
user and read for group and others. The symlink.c would have <code class="docutils literal notranslate"><span class="pre">st_mode</span></code> <code class="docutils literal notranslate"><span class="pre">120755</span></code> (displayed as
|
||
<code class="docutils literal notranslate"><span class="pre">lrwxr-xr-x</span></code>). Note that the first character in the displayed version indicates the type of file
|
||
(<code class="docutils literal notranslate"><span class="pre">-</span></code> for <code class="docutils literal notranslate"><span class="pre">S_IFREG</span></code>, <code class="docutils literal notranslate"><span class="pre">l</span></code> for <code class="docutils literal notranslate"><span class="pre">S_IFLNK</span></code>, <code class="docutils literal notranslate"><span class="pre">d</span></code> for <code class="docutils literal notranslate"><span class="pre">S_IFDIR</span></code>, and so on).</p>
|
||
<div class="topic border border-dark rounded-lg bg-light px-2 mb-3">
|
||
<div class="figure align-left">
|
||
<a class="reference internal image-reference" href="_images/CSF-Images-Note.png"><img alt="Decorative note icon" src="_images/CSF-Images-Note.png" style="width: 100%;" /></a>
|
||
</div>
|
||
<p class="topic-title first pt-2 mb-1">Note</p><hr class="mt-1" />
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">SUID</span></code>, <code class="docutils literal notranslate"><span class="pre">SGID</span></code>, and sticky bits have complex meanings and interpretations. One source of
|
||
their complexity is that <code class="docutils literal notranslate"><span class="pre">SUID</span></code> only affects executable regular files, the sticky bit (which is
|
||
mostly obsolete and has changed over time) only affects, and <code class="docutils literal notranslate"><span class="pre">SGID</span></code> affects both executables and
|
||
directories! These meanings can be summarized as follows:</p>
|
||
<blockquote>
|
||
<div><ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">SUID</span></code>: Processes created with this executable will inherit the user ID of the file’s owner,
|
||
rather than the user ID of the user executing the program.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">SGID</span></code> (regular file): Processes created with this executable will inherit the group ID of the
|
||
file’s group, rather than the group ID of the user executing the program.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">SGID</span></code> (directory): Files and subdirectories created in this directory will inherit the group ID
|
||
of this directory.</li>
|
||
<li>Sticky bit (modern usage): Files in this directory can only be deleted by the user who is considered the owner of the file.</li>
|
||
</ul>
|
||
</div></blockquote>
|
||
<p>When these bits are set on a file, <code class="docutils literal notranslate"><span class="pre">ls</span> <span class="pre">-l</span></code> displays them by overlaying them on top of the execute
|
||
bits in the permission field, using an <code class="docutils literal notranslate"><span class="pre">'s'</span></code> in the user field for <code class="docutils literal notranslate"><span class="pre">SUID</span></code>, <code class="docutils literal notranslate"><span class="pre">'s'</span></code> in the group
|
||
field for <code class="docutils literal notranslate"><span class="pre">SGID</span></code>, and <code class="docutils literal notranslate"><span class="pre">'t'</span></code> in the other field for the sticky bit; if the corresponding <code class="docutils literal notranslate"><span class="pre">'x'</span></code>
|
||
bit is present, a lower-case letter is used, while an upper-case letter indicates the <code class="docutils literal notranslate"><span class="pre">'x'</span></code> bit
|
||
is absent. For instance, <code class="docutils literal notranslate"><span class="pre">rwsr-x---</span></code> would indicate both <code class="docutils literal notranslate"><span class="pre">S_IXUSR</span></code> and <code class="docutils literal notranslate"><span class="pre">S_ISUID</span></code> are set;
|
||
<code class="docutils literal notranslate"><span class="pre">rw-r-Sr--</span></code> would mean that <code class="docutils literal notranslate"><span class="pre">S_IGUID</span></code> is set but <code class="docutils literal notranslate"><span class="pre">S_IXGRP</span></code> is not.</p>
|
||
</div>
|
||
<p><a class="reference external" href="UnixFile.html#cl2-17">Code Listing 2.17</a> illustrates how to use <code class="docutils literal notranslate"><span class="pre">fstat()</span></code> to investigate a file’s metadata. The address
|
||
of the local variable <code class="docutils literal notranslate"><span class="pre">info</span></code> is passed to <code class="docutils literal notranslate"><span class="pre">fstat()</span></code> to collect the metadata on line 9. Lines 13 –
|
||
15 are using the bitwise-and operator (<code class="docutils literal notranslate"><span class="pre">&</span></code>) to determine if certain permission bits are set; the
|
||
result would be non-zero (true) if the bit is set but would be zero (false) if not. Lines 18 and 19
|
||
demonstrate a very common technique when reading in files. Line 19 uses the <code class="docutils literal notranslate"><span class="pre">st_size</span></code> field to
|
||
allocate the exact amount of space needed to read in the full file contents, then line 20 reads in
|
||
exactly that number of bytes. Once the file is read into memory, it can be accessed in a variety of
|
||
ways. Since this file is an ASCII-formatted CSV file, it can be manipulated just like a normal
|
||
string. Line 24 uses <code class="docutils literal notranslate"><span class="pre">strtok()</span></code> to split this string at the first instance of the newline
|
||
character (<code class="docutils literal notranslate"><span class="pre">'\n'</span></code>); line 25 can then print just that line as a string. This change only affects
|
||
the in-memory buffer, and it does not change the contents of the original file stored on disk.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl2-17"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
16
|
||
17
|
||
18
|
||
19
|
||
20
|
||
21
|
||
22
|
||
23
|
||
24
|
||
25</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 2.17:</span>
|
||
<span class="cm"> Using fstat() to determine the file size and read in the exact amount of data</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="cm">/* Open a CSV file and read its status information */</span>
|
||
<span class="k">struct</span> <span class="n">stat</span> <span class="n">info</span><span class="p">;</span>
|
||
<span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">open</span> <span class="p">(</span><span class="s">"movies.csv"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="p">);</span>
|
||
<span class="n">assert</span> <span class="p">(</span><span class="n">fd</span> <span class="o">></span> <span class="mi">0</span><span class="p">);</span>
|
||
<span class="n">assert</span> <span class="p">(</span><span class="n">fstat</span> <span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="o">&</span><span class="n">info</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Check the file size and permissions */</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"File is %lld bytes in size</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">st_size</span><span class="p">);</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"Is file readable by user? %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="n">info</span><span class="p">.</span><span class="n">st_mode</span> <span class="o">&</span> <span class="n">S_IRUSR</span> <span class="o">?</span> <span class="s">"yes"</span> <span class="o">:</span> <span class="s">"no"</span><span class="p">));</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"Is file executable by user? %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="n">info</span><span class="p">.</span><span class="n">st_mode</span> <span class="o">&</span> <span class="n">S_IXUSR</span> <span class="o">?</span> <span class="s">"yes"</span> <span class="o">:</span> <span class="s">"no"</span><span class="p">));</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"Is this a directory? %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="n">info</span><span class="p">.</span><span class="n">st_mode</span> <span class="o">&</span> <span class="n">S_IFDIR</span> <span class="o">?</span> <span class="s">"yes"</span> <span class="o">:</span> <span class="s">"no"</span><span class="p">));</span>
|
||
|
||
<span class="cm">/* Create a buffer that is the exact size of the file and</span>
|
||
<span class="cm"> read in the contents */</span>
|
||
<span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span> <span class="o">=</span> <span class="n">calloc</span> <span class="p">(</span><span class="n">info</span><span class="p">.</span><span class="n">st_size</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="kt">char</span><span class="p">));</span>
|
||
<span class="kt">ssize_t</span> <span class="n">bytes</span> <span class="o">=</span> <span class="n">read</span> <span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="n">info</span><span class="p">.</span><span class="n">st_size</span><span class="p">);</span>
|
||
<span class="n">assert</span> <span class="p">(</span><span class="n">bytes</span> <span class="o">==</span> <span class="n">info</span><span class="p">.</span><span class="n">st_size</span><span class="p">);</span>
|
||
<span class="n">close</span> <span class="p">(</span><span class="n">fd</span><span class="p">);</span>
|
||
|
||
<span class="kt">char</span> <span class="o">*</span><span class="n">line</span> <span class="o">=</span> <span class="n">strtok</span> <span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"Here is the first line:</span><span class="se">\n</span><span class="s">%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">line</span><span class="p">);</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<div class="topic border border-dark rounded-lg bg-light px-2 mb-3">
|
||
<div class="figure align-left">
|
||
<a class="reference internal image-reference" href="_images/CSF-Images-Note.png"><img alt="Decorative note icon" src="_images/CSF-Images-Note.png" style="width: 100%;" /></a>
|
||
</div>
|
||
<p class="topic-title first pt-2 mb-1">Note</p><hr class="mt-1" />
|
||
<p>The traditional UNIX permission structure—assigning permissions based only on the user, group, or
|
||
other—is inflexible and not well suited for many applications. For example, consider two user that
|
||
are collaborating on a project. These two users both need full permissions to read and write to a
|
||
file, but they do not want to make the file publicly accessible otherwise. Under the traditional
|
||
approach, a system administrator could create a group containing these two users; the users could
|
||
then set permissions based on the group ID. The problem is that each user can only be assigned to a
|
||
single group. If these users also have similar collaborations with different users on the same
|
||
system, they cannot use the same approach.</p>
|
||
<p>To fix this problem, many modern systems support <em>access control lists</em>
|
||
(ACLs). Using ACLs, users can grant or revoke permissions to other users on an individual basis. In
|
||
addition, ACLs allow the same user to be a member of multiple groups. Rather than using the
|
||
traditional ls and chmod commands to view and change permissions, ACLs use the <code class="docutils literal notranslate"><span class="pre">getfacl</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">setfacl</span></code> commands. Consider the following example of these two commands.</p>
|
||
<div class="highlight-none border border-dark rounded-lg bg-light px-2 mb-3 notranslate"><div class="highlight bg-light"><pre class="mb-0"><span></span>$ getfacl team
|
||
# file: team
|
||
# owner: csf
|
||
# group: staff
|
||
user::rwx
|
||
user:alissa:rwx
|
||
user:marcos:rwx
|
||
group::r-x
|
||
group:csfadmin:r-x
|
||
mask::rwx
|
||
other::---
|
||
default:user::rwx
|
||
default:user:alissa:rwx
|
||
default:user:marcos:rwx
|
||
default:group::r-x
|
||
default:csfadmin:r-x
|
||
default:other::---
|
||
$ setfacl -m u:sergei:rwx
|
||
$ setfacl -m d:u:sergei:rwx
|
||
</pre></div>
|
||
</div>
|
||
<p>For each file and directory, there is an assigned owner and group, just like the traditional UNIX
|
||
permissions, as indicated by the lines beginning with <code class="docutils literal notranslate"><span class="pre">#</span></code>. The other lines are individual
|
||
permissions that have been set for the particular file. The user and group permissions contain
|
||
three fields separated by a colon (<code class="docutils literal notranslate"><span class="pre">:</span></code>). The middle field indicates which user or group and the
|
||
third field indicates the permissions (read, write, execute); if the user or group field is empty,
|
||
the permission applies to the owner or group of the file. Directories can also have <code class="docutils literal notranslate"><span class="pre">default</span></code>
|
||
permission lines; any time a file is created in this directory, the specified default permissions
|
||
are automatically assigned to it. When using <code class="docutils literal notranslate"><span class="pre">setfacl</span></code> to add, change, or remove a permission
|
||
entry, the terms <code class="docutils literal notranslate"><span class="pre">user</span></code>, <code class="docutils literal notranslate"><span class="pre">group</span></code>, and <code class="docutils literal notranslate"><span class="pre">default</span></code> can be abbreviated as simply <code class="docutils literal notranslate"><span class="pre">u</span></code>, <code class="docutils literal notranslate"><span class="pre">g</span></code>, or
|
||
<code class="docutils literal notranslate"><span class="pre">d</span></code>.</p>
|
||
</div>
|
||
<table class="docutils footnote" frame="void" id="f15" rules="none">
|
||
<colgroup><col class="label" /><col /></colgroup>
|
||
<tbody valign="top">
|
||
<tr><td class="label"><a class="fn-backref" href="UnixFile.html#id2">[1]</a></td><td>To reiterate the notion of files as just a sequence of bytes, note that the file
|
||
descriptor here was not necessarily the value returned from <code class="docutils literal notranslate"><span class="pre">open()</span></code> as described above. For
|
||
files that do not correspond to named locations in the directory tree structure, the file
|
||
descriptor may be created by a different function (such as <code class="docutils literal notranslate"><span class="pre">pipe()</span></code> or <code class="docutils literal notranslate"><span class="pre">socket()</span></code> as described
|
||
in Chapters 3 and 4).</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<div
|
||
id="ProcFileSumm"
|
||
class="embedContainer"
|
||
data-exer-name="ProcFileSumm"
|
||
data-long-name="UNIX file questions"
|
||
data-short-name="ProcFileSumm"
|
||
data-frame-src="../../../Exercises/Processes/ProcFileSumm.html?selfLoggingEnabled=false&localMode=true&module=UnixFile&JXOP-debug=true&JOP-lang=en&JXOP-code=java"
|
||
data-frame-width="950"
|
||
data-frame-height="550"
|
||
data-external="false"
|
||
data-points="1.0"
|
||
data-required="True"
|
||
data-showhide="show"
|
||
data-threshold="5"
|
||
data-type="ka"
|
||
data-exer-id="">
|
||
|
||
<div class="center">
|
||
<div id="ProcFileSumm_iframe"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<div class="container">
|
||
|
||
<div class="mt-4 container center">
|
||
«  <a id="prevmod1" href="ProcessCycle.html">2.5. Process Life Cycle</a>
|
||
  ::  
|
||
<a class="uplink" href="index.html">Contents</a>
|
||
  ::  
|
||
<a id="nextmod1" href="EventsSignals.html">2.7. Events and Signals</a>  »
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
<br />
|
||
|
||
<div class="row jmu-dark-purple-bg">
|
||
<div class="col-md-12">
|
||
<center>
|
||
<a id="contact_us" class="btn button-link-no-blue jmu-gold" rel="nofollow" href="mailto:webmaster@opencsf.org" role="button">Contact Us</a>
|
||
<a id="license" class="btn button-link-no-blue jmu-gold" rel="nofollow" href="https://w3.cs.jmu.edu/kirkpams/OpenCSF/lib/license.html" target="_blank">License</a>
|
||
</center>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<script src="_static/js/popper.js-1.14.7-min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||
<script src="_static/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||
</body>
|
||
</html> |