# Files and directories

---

# Files and directories

_Peios / Using Peios / Peiosutils / Files and directories_

> The commands that create, copy, move, remove, and resize files and directories — and how each one handles a file's security descriptor.

This topic covers the commands that *change* the file system: creating files and directories, copying and moving them, removing them, and adjusting their size. If a command brings a file into existence, takes one out of it, or duplicates one, it is here.

This page names every command, and then explains the one theme that runs through the whole topic on Peios: what happens to a file's **security descriptor** when the file is created or copied.

## The commands

| Command | Purpose |
|---|---|
| [`cp`](/peios/using-peios/peiosutils/files-and-directories/cp.md) | Copy files and directories. |
| [`mv`](/peios/using-peios/peiosutils/files-and-directories/mv.md) | Move or rename files and directories. |
| [`rm`](/peios/using-peios/peiosutils/files-and-directories/rm.md) | Remove files, and with `-r`, directories. |
| [`rmdir`](/peios/using-peios/peiosutils/files-and-directories/rmdir.md) | Remove directories, but only empty ones. |
| [`mkdir`](/peios/using-peios/peiosutils/files-and-directories/mkdir.md) | Create directories. |
| [`mkfifo`](/peios/using-peios/peiosutils/files-and-directories/mkfifo.md) | Create named pipes (FIFOs). |
| [`mknod`](/peios/using-peios/peiosutils/files-and-directories/mknod.md) | Create special files — device nodes and FIFOs. |
| [`touch`](/peios/using-peios/peiosutils/files-and-directories/touch.md) | Create empty files, or update a file's timestamps. |
| [`ln`](/peios/using-peios/peiosutils/files-and-directories/ln.md) | Create hard links and symbolic links. |
| [`link` and `unlink`](/peios/using-peios/peiosutils/files-and-directories/link-and-unlink.md) | The single-purpose, low-level versions of "make a hard link" and "remove a file". |
| [`shred`](/peios/using-peios/peiosutils/files-and-directories/shred.md) | Destroy a file's contents by overwriting them, so they cannot be recovered. |
| [`dd`](/peios/using-peios/peiosutils/files-and-directories/dd.md) | Copy data block by block, converting it on the way. |
| [`df`](/peios/using-peios/peiosutils/files-and-directories/df.md) | Report how much space each file system has, and how much is free. |
| [`du`](/peios/using-peios/peiosutils/files-and-directories/du.md) | Report how much space files and directories use. |
| [`truncate`](/peios/using-peios/peiosutils/files-and-directories/truncate.md) | Shrink or extend a file to an exact size. |
| [`mktemp`](/peios/using-peios/peiosutils/files-and-directories/mktemp.md) | Create a temporary file or directory with a safely unique name. |

## Every file has a security descriptor

On Peios, every file and directory carries a **security descriptor** — the record of who owns it and who may do what to it. Access to a file is decided from its descriptor; see [Security descriptors](/peios/security-fundamentals/security-descriptors/overview.md) for the full picture.

That fact shapes two groups of commands in this topic.

### Creating a file gives it a descriptor

When `mkdir`, `mkfifo`, `mknod`, or `touch` creates a new object, that object needs a security descriptor. By default it gets one **inherited from the directory it is created in** — the new object picks up the access rules its parent directory hands down.

All four of these commands share one set of options — the **creation flags** — that let you set the new object's descriptor explicitly instead of taking the inherited default: name an owner, set a different group, lock the object so it does *not* inherit, give it an integrity label, or supply a complete descriptor. The flags are documented in full on the [`mkdir`](/peios/using-peios/peiosutils/files-and-directories/mkdir.md) page; `mkfifo`, `mknod`, and `touch` each link back to it.

### Copying a file makes a fresh descriptor — unless you preserve

`cp` creates new files, and a cross-file-system `mv` does too. A brand-new copy gets a brand-new descriptor inherited from its destination directory — it does **not** carry the source file's security across by default.

When you *do* want the copy to keep the source's owner, access rules, timestamps, or other attributes, that is the job of the `--preserve` family of options. `cp` and `mv` share an identical `--preserve` surface; it is documented on the [`cp`](/peios/using-peios/peiosutils/files-and-directories/cp.md) page.

### Removing a file checks whether you may write it

`rm` and `shred` both make a decision based on whether you can write a file. `rm` prompts before removing a file you cannot write to; `shred`'s `--force` overrides a file's protection so it can be destroyed. Both judge "can you write this?" by a live access check against the file's security descriptor — not by any decorative metadata on the inode. Each command's page explains exactly where that check is made.

## Where to start

For copying — and for the whole `--preserve` model — read [`cp`](/peios/using-peios/peiosutils/files-and-directories/cp.md).

For creating files and directories, and the shared creation flags, read [`mkdir`](/peios/using-peios/peiosutils/files-and-directories/mkdir.md).

For removing things safely, read [`rm`](/peios/using-peios/peiosutils/files-and-directories/rm.md).

---

# cp

_Peios / Using Peios / Peiosutils / Files and directories_

> Copy files and directories — including how a copy gets its security descriptor and the --preserve family that carries attributes from the source.

`cp` copies files and directories.

```
cp [options] source dest
cp [options] source... directory
cp [options] -t directory source...
```

In the first form, `cp` copies one `source` to one `dest`. In the other two, it copies any number of sources *into* a directory, keeping their names.

```
$ cp report.txt report-backup.txt
$ cp report.txt notes.txt /home/jack/archive/
```

## Copying directories

`cp` refuses to copy a directory unless you ask it to descend into one:

| Option | Effect |
|---|---|
| `-r`, `-R`, `--recursive` | Copy directories, and everything inside them, recursively. |
| `-a`, `--archive` | A faithful recursive copy: copy the whole tree, follow no symbolic links, and preserve every attribute. Equivalent to `-d -R --preserve-all`. |

`-a` is the option to use when you want the copy to be as close to the original as possible — same structure, same security, same timestamps. A plain `-r` copies the *contents* but, as the next section explains, gives the copies fresh security of their own.

## What a copy's security descriptor is

This is the part of `cp` that is specific to Peios, so it is worth being precise.

Every file carries a [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md) — the record of who owns it and who may do what to it. When `cp` copies a file, it creates a *new* file, and that new file needs a descriptor.

**By default, a copy gets a fresh descriptor — it does not inherit the source's.** Specifically, a plain `cp`:

- gives the copy a descriptor **inherited from the destination directory**, exactly as if you had created a new file there;
- makes **you** the owner of the copy;
- gives the copy **fresh timestamps** — the copy's modification time is "now".

This is usually what you want. A file copied into your home directory should be governed by your home directory's rules and owned by you, regardless of where it came from. But when you need the copy to keep something from the source, you ask for it explicitly — with the `--preserve` family.

### The `--preserve` family

`--preserve` carries chosen attributes from the source onto the copy. The attributes you can preserve:

| Attribute | What it carries from the source |
|---|---|
| `owner` | The owner SID. |
| `dacl` | The whole DACL — every access rule on the file, inherited rules included. |
| `sacl` | The whole SACL — the audit rules and the integrity label. |
| `daclni` | The DACL with **inherited** rules stripped out — only the rules set explicitly on the source. |
| `saclni` | The SACL with inherited rules stripped out. |
| `timestamps` | The access and modification times. |
| `links` | The hard-link structure — files hard-linked together in the source stay hard-linked in the copy. |
| `security` | The `security.peios.*` extended attributes (other than the descriptor itself). |
| `xattrs` | All other extended attributes. |

You rarely name those individually. These options select sensible sets:

| Option | Preserves |
|---|---|
| `-p` | Timestamps only. |
| `--preserve` | Timestamps only — the same as `-p`. |
| `--preserve=LIST` | Exactly the comma-separated attributes you name. |
| `--preserve-all` | Every attribute in the table above. |
| `--sd` | `owner`, `dacl`, `sacl` — the **full security descriptor**, copied verbatim. |
| `--sd-explicit` | `owner`, `daclni`, `saclni` — the source's **explicitly set** rules only. |
| `--no-preserve=LIST` | Turns the named attributes back *off* — useful to subtract from a broader option. |

### `--sd` versus `--sd-explicit`

Both carry the source's security across; they differ in how they treat *inherited* rules.

- **`--sd`** copies the descriptor exactly — inherited rules and all. The copy ends up with precisely the access rules the source had, even if it lands in a directory that would have handed down something different. Use it when the copy must be a security-exact duplicate.
- **`--sd-explicit`** copies only the rules that were set *explicitly* on the source, and lets the destination directory supply inheritance for the rest. Use it when copying a file into a *different* directory and you want the file's own tailored rules to come along while still picking up the new location's inherited rules.

For what "inherited" versus "explicit" means, see [Inheritance](/peios/security-fundamentals/security-descriptors/inheritance.md).

### When a preserve cannot be honoured

A requested preserve is a firm instruction. If `cp` cannot carry an attribute across — for example, writing the copy's SACL requires the `SeSecurityPrivilege` privilege, and the caller does not have it — `cp` treats that as a hard error and the copy fails. It does not quietly produce a copy that is missing what you asked to preserve.

There is one exception, and it is a matter of definition rather than a softening of the rule. `security` and `xattrs` name extended attributes, and some filesystems have no extended attributes **at all** — FAT, 9p, and a squashfs image built without an attribute table are the ones you will meet. Copying *from* such a filesystem carries nothing, because there was nothing there: the preserve is satisfied vacuously, and the copy succeeds.

That is narrow on purpose. It applies only to reading the source. If the source does have extended attributes and the *destination* filesystem cannot hold them, the preserve genuinely failed and `cp` still stops:

```
# cp -a /home/jack/notes /mnt/usb-fat/
cp: failed to set extended attributes on '/mnt/usb-fat/notes': Operation not supported
```

The distinction matters most for `-a`, which requests both attribute classes on every file it touches. Without it, one xattr-less filesystem anywhere in a tree would abort the whole copy partway through.

## Overwriting an existing destination

By default, if the destination already exists, `cp` overwrites it. These options change that.

| Option | Effect |
|---|---|
| `-i`, `--interactive` | Ask before overwriting an existing file. |
| `-n`, `--no-clobber` | Never overwrite an existing file; skip it silently. |
| `-u`, `--update[=WHICH]` | Overwrite only when the source is newer than the destination. `WHICH` can be `all`, `none`, or `older`. |
| `-f`, `--force` | If an existing destination cannot be opened for writing, remove it and try the copy again. |
| `--remove-destination` | Remove the destination *before* opening it, always — contrast `--force`, which only removes on failure. |
| `-b`, `--backup[=CONTROL]` | Before overwriting, make a backup of the destination. |

## Symbolic links in the source

When a source is a symbolic link, `cp` can copy the link itself or the file it points to.

| Option | Effect |
|---|---|
| `-L`, `--dereference` | Always follow symbolic links — copy the file they point to. |
| `-P`, `--no-dereference` | Never follow symbolic links — copy the link itself. |
| `-H` | Follow only the symbolic links named directly on the command line, not links found while recursing. |
| `-d` | Copy links as links, and preserve hard-link structure. Short for `--no-dereference --preserve=links`. |

## Other ways to copy

`cp` can also produce something other than a plain duplicate.

| Option | Effect |
|---|---|
| `-l`, `--link` | Create a hard link to the source instead of copying its data. |
| `-s`, `--symbolic-link` | Create a symbolic link to the source instead of copying. |
| `--reflink[=WHEN]` | Make a lightweight copy-on-write clone where the file system supports it. `WHEN` is `always`, `auto`, or `never`. |
| `--sparse[=WHEN]` | Control whether runs of zero bytes are stored as holes rather than written out. `WHEN` is `always`, `auto`, or `never`. |
| `--attributes-only` | Create the destination and copy its attributes, but not its data. |

## Other options

| Option | Effect |
|---|---|
| `-t`, `--target-directory=DIR` | Copy every source into `DIR`. Useful when the directory is not the last argument. |
| `-T`, `--no-target-directory` | Treat `dest` as a plain file even if it is a directory. |
| `--parents` | Recreate the source's leading directories under the destination. |
| `-x`, `--one-file-system` | Do not cross into a different file system while recursing. |
| `--strip-trailing-slashes` | Strip any trailing slashes from each source argument before using it. |
| `-v`, `--verbose` | Print each file as it is copied. |
| `--debug` | Explain in detail how each file was copied. Implies `-v`. |
| `--progress` | Show a progress bar. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every file was copied successfully. |
| `1` | A file could not be copied — including a requested `--preserve` that could not be honoured. |

---

# mv

_Peios / Using Peios / Peiosutils / Files and directories_

> Move or rename files and directories — including how a move handles a file's security descriptor depending on whether it crosses a file system.

`mv` moves files and directories from one place to another. Moving a file within the same directory, under a new name, is how you *rename* it.

```
mv [options] source dest
mv [options] source... directory
mv [options] -t directory source...
```

```
$ mv draft.txt report.txt                 # rename
$ mv report.txt notes.txt /home/jack/done/ # move into a directory
```

## A move is either a rename or a copy-and-delete

`mv` does its job in one of two ways, and which one decides what happens to the file's security.

**Within one file system, a move is a rename.** Nothing is copied: the file stays exactly where it physically is, and only its name and directory entry change. The file keeps its inode, and so it keeps its **security descriptor unchanged** — every owner, access rule, audit rule, and timestamp is exactly as before. A rename does not re-evaluate inheritance; a file does not pick up new rules just because it landed in a new directory.

**Across file systems, a move is a copy followed by a delete.** When the destination is on a different file system, `mv` cannot just rename — it copies the data to a new file on the destination, then removes the original. That new file is a genuinely new object, so, exactly as with [`cp`](/peios/using-peios/peiosutils/files-and-directories/cp.md), it gets a **fresh security descriptor inherited from the destination directory** unless you ask otherwise.

So: rename a file and its security is untouched; move it to another file system and the copy starts fresh.

## Preserving security on a cross-file-system move

For the copy-and-delete case, `mv` carries the same `--preserve` family that `cp` does — an identical set of options, behaving the same way. They let a cross-file-system move carry the source's owner, access rules, timestamps, and other attributes onto the new file instead of taking the destination directory's inherited default.

The full `--preserve` reference — the attribute list, `--sd`, `--sd-explicit`, `--preserve-all`, `--no-preserve`, and what happens when a preserve cannot be honoured — is on the [`cp`](/peios/using-peios/peiosutils/files-and-directories/cp.md) page. Everything there applies to `mv` unchanged.

On a same-file-system move the `--preserve` options have nothing to do: a rename already keeps every attribute, because it is the same file.

## Overwriting an existing destination

By default `mv` overwrites an existing destination. These options change that. When more than one of `-i`, `-f`, `-n` is given, the last one wins.

| Option | Effect |
|---|---|
| `-i`, `--interactive` | Ask before overwriting an existing file. |
| `-f`, `--force` | Do not prompt before overwriting. |
| `-n`, `--no-clobber` | Never overwrite an existing file. |
| `-u`, `--update[=WHICH]` | Overwrite only when the source is newer. `WHICH` can be `all`, `none`, or `older`. |
| `-b`, `--backup[=CONTROL]` | Make a backup of the destination before overwriting it. |

## Other options

| Option | Effect |
|---|---|
| `-t`, `--target-directory=DIR` | Move every source into `DIR`. |
| `-T`, `--no-target-directory` | Treat `dest` as a plain file even if it is a directory. |
| `--strip-trailing-slashes` | Strip any trailing slashes from each source argument. |
| `-v`, `--verbose` | Print each file as it is moved. |
| `--debug` | Explain in detail how each file was moved. Implies `-v`. |
| `--progress` | Show a progress bar. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every file was moved successfully. |
| `1` | A file could not be moved. |

---

# rm

_Peios / Using Peios / Peiosutils / Files and directories_

> Remove files and directories — including how rm decides a file is write-protected and worth prompting about.

`rm` removes files. With `-r`, it removes directories and everything inside them.

```
rm [options] file...
```

```
$ rm draft.txt old-notes.txt
$ rm -r build/
```

Removal is not reversible — once `rm` removes a file, its directory entry is gone. `rm` has a few safety behaviours, below, but the basic rule stands: think before you confirm.

## Removing directories

`rm` will not remove a directory unless you say so:

| Option | Effect |
|---|---|
| `-r`, `-R`, `--recursive` | Remove directories and all of their contents, recursively. |
| `-d`, `--dir` | Remove a directory, but only if it is already empty. |

## The write-protected prompt

By default — when you have not passed `-f` and `rm` is running interactively — `rm` prompts before removing a file you cannot write to:

```
$ rm policy.db
rm: remove write-protected regular file 'policy.db'?
```

The point of that prompt is to catch mistakes: a file you cannot write is one you most likely did not mean to delete.

**"Write-protected" here means a real access check.** `rm` decides it by asking the kernel whether your token may write the file — a live check against the file's [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md). It is not read off any decorative metadata on the inode; it is the same authority question that any write to the file would face. So the prompt is honest: if `rm` says a file is write-protected, it is a file the access model would genuinely stop you writing.

(The check is about *write* access to the file's contents. Whether you may actually *remove* the file is a separate question, decided by its own access right — so you can be prompted about a write-protected file and still be allowed to delete it. The prompt is a courtesy check, not the authorisation.)

## Controlling the prompts

| Option | Effect |
|---|---|
| `-f`, `--force` | Never prompt. Also ignore files that do not exist instead of reporting them. |
| `-i` | Prompt before *every* removal. |
| `-I` | Prompt just *once* before removing more than three files or before a recursive removal. Less intrusive than `-i`, but still a check against a slip. |
| `--interactive[=WHEN]` | Set the prompting explicitly: `never`, `once`, or `always`. |

## The root failsafe

`rm` refuses to recursively remove `/` — the root of the file system — because doing so by accident would be catastrophic.

| Option | Effect |
|---|---|
| `--preserve-root` | Refuse to recurse on `/`. This is the default; you do not need to ask for it. |
| `--no-preserve-root` | Disable the failsafe. Required, in full and unabbreviated, if you genuinely intend a recursive operation on `/`. |

## Other options

| Option | Effect |
|---|---|
| `-v`, `--verbose` | Print each file as it is removed. |
| `--progress` | Show a progress bar. |

## `rm` and `shred`

`rm` unlinks a file — it removes the name, and the space becomes free. The file's *data* may still be physically present on the device until something else overwrites it. When you need the contents to be genuinely unrecoverable, use [`shred`](/peios/using-peios/peiosutils/files-and-directories/shred.md), which overwrites the data before removing the file.

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every requested removal succeeded (or, with `-f`, the file did not exist). |
| `1` | A file could not be removed. |

---

# rmdir

_Peios / Using Peios / Peiosutils / Files and directories_

> Remove directories, but only when they are already empty.

`rmdir` removes directories — but only **empty** ones. If a directory still has anything in it, `rmdir` leaves it alone and reports the failure.

```
rmdir [options] directory...
```

```
$ rmdir old-cache/
```

That refusal to touch a non-empty directory is the whole point of `rmdir`: it is the safe way to remove a directory you *believe* is empty. If it is not empty, you find out instead of losing the contents. To remove a directory together with everything inside it, use [`rm -r`](/peios/using-peios/peiosutils/files-and-directories/rm.md).

## Options

| Option | Effect |
|---|---|
| `-p`, `--parents` | Remove the directory and then its ancestors, as long as each becomes empty in turn. `rmdir -p a/b/c` removes `a/b/c`, then `a/b`, then `a`. |
| `--ignore-fail-on-non-empty` | Do not treat "directory not empty" as a failure. Other failures are still reported. Useful when clearing out whatever directories happen to be empty and leaving the rest. |
| `-v`, `--verbose` | Print a line for each directory as it is removed. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every directory was removed. |
| `1` | A directory could not be removed — it was not empty, did not exist, or removal was refused. |

---

# mkdir

_Peios / Using Peios / Peiosutils / Files and directories_

> Create directories — and the shared creation flags that set a new object's security descriptor, used by mkdir, mkfifo, mknod, and touch.

`mkdir` creates directories.

```
mkdir [options] directory...
```

```
$ mkdir reports
$ mkdir -p projects/2026/q2
```

## Creating parent directories

By default `mkdir` creates exactly the directories you name, and fails if a parent is missing. `-p` removes that restriction:

| Option | Effect |
|---|---|
| `-p`, `--parents` | Create any missing parent directories along the way. Also makes `mkdir` succeed quietly if the directory already exists. |
| `-v`, `--verbose` | Print a line for each directory as it is created. |

## The creation flags

A new directory needs a [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md) — the record of who owns it and who may do what to it. By default, **a new directory inherits its descriptor from the directory it is created in**: it picks up the access rules its parent hands down. For most directories that is exactly right, and you pass no extra options at all.

When you need the new directory to have a *different* descriptor, the **creation flags** set it explicitly. These five flags are shared, unchanged, by `mkdir`, [`mkfifo`](/peios/using-peios/peiosutils/files-and-directories/mkfifo.md), [`mknod`](/peios/using-peios/peiosutils/files-and-directories/mknod.md), and [`touch`](/peios/using-peios/peiosutils/files-and-directories/touch.md) — whenever one of those commands creates a new object, it accepts this same set. This page is the full reference for them.

| Flag | Argument | Effect |
|---|---|---|
| `--owner` | SID | Make this principal the owner, instead of you. |
| `--group` | SID | Set the object's group. |
| `--label` | level | Give the object a mandatory integrity label. |
| `--no-inherit` | — | Do **not** inherit rules from the parent directory; lock the object to its owner. |
| `--sddl` | SDDL string | Supply the entire security descriptor directly. |

A SID argument is either a literal `S-1-…` value or a well-known alias — `BA` for the built-in administrators, for example.

`--label` takes one of these levels, lowest to highest: `untrusted`, `low`, `medium`, `medium-plus`, `high`, `system`, `protected`. The label applies the standard rule for files and directories — a principal below the object's level cannot write to it.

### Inherited, or explicit

The default and `--no-inherit` are the two ends of a choice.

- **Inherited (the default)** — the new directory tracks its parent. Rules the parent hands down apply to it, and as the parent's rules change the directory follows along. This keeps a tree of directories consistent without per-directory effort.
- **`--no-inherit`** — the new directory takes nothing from its parent. Its access is locked to its owner, and it does not follow the parent's rules. Use it to carve out a directory whose security stands apart from the tree around it.

See [Inheritance](/peios/security-fundamentals/security-descriptors/inheritance.md) for the full model.

### `--sddl` for a complete descriptor

The four flags above are shortcuts for common adjustments. When you need to specify the *whole* descriptor — a particular set of access rules, audit rules, owner, and group all at once — `--sddl` takes it as a single string in the security-descriptor definition language:

```
$ mkdir --sddl 'O:BAG:BAD:(A;OICI;FA;;;BA)' secure-area
```

`--sddl` is mutually exclusive with `--owner`, `--group`, `--label`, and `--no-inherit` — it already says everything those flags would say, so combining them is rejected.

### How the descriptor is applied

`mkdir` creates the directory first and then applies the descriptor to it. The two steps are not separately visible — `mkdir` either finishes with the directory created and secured as asked, or fails as a whole. If applying the descriptor fails, the half-created directory is not left behind.

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every directory was created. |
| `1` | A directory could not be created, or a creation flag could not be applied. |

---

# mkfifo

_Peios / Using Peios / Peiosutils / Files and directories_

> Create named pipes (FIFOs).

`mkfifo` creates **named pipes**, also called FIFOs.

```
mkfifo [options] name...
```

```
$ mkfifo events
```

A named pipe is a file that two programs use to pass a stream of data: one writes into it, the other reads from it, and the data flows through in order — first in, first out, which is what "FIFO" stands for. Unlike an ordinary pipe between two commands, a named pipe has a name on the file system, so the two programs do not have to be started together or be related to each other.

## Setting the new pipe's security

A FIFO is a file, and a new file needs a [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md). By default a new FIFO inherits its descriptor from the directory it is created in.

`mkfifo` accepts the shared **creation flags** — `--owner`, `--group`, `--label`, `--no-inherit`, and `--sddl` — to set that descriptor explicitly instead. They behave exactly as they do for `mkdir`; the full reference is on the [`mkdir`](/peios/using-peios/peiosutils/files-and-directories/mkdir.md) page.

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every FIFO was created. |
| `1` | A FIFO could not be created — for example, the name already exists. |

---

# mknod

_Peios / Using Peios / Peiosutils / Files and directories_

> Create special files — device nodes and named pipes.

`mknod` creates **special files** — files that are not data but an interface to something else: a device, or a named pipe.

```
mknod [options] name type [major minor]
```

```
$ mknod /dev/mydisk b 8 0
$ mknod backlog p
```

## The type argument

The `type` says what kind of special file to create:

| Type | Creates |
|---|---|
| `b` | A **block device** — a device addressed in fixed-size blocks, such as a disk. |
| `c` or `u` | A **character device** — a device addressed as a stream of bytes, such as a terminal. |
| `p` | A **named pipe** (FIFO). |

For a block or character device (`b`, `c`, `u`) you must also give a **major** and a **minor** number. The major number selects which driver handles the device; the minor number tells that driver which specific device is meant. For a pipe (`p`), the major and minor numbers are omitted — a pipe has no driver behind it.

A major or minor number is read as hexadecimal if it begins with `0x`, as octal if it begins with `0`, and as decimal otherwise.

`mknod NAME p` and [`mkfifo NAME`](/peios/using-peios/peiosutils/files-and-directories/mkfifo.md) do the same thing; `mkfifo` exists as the clearer way to ask for just a pipe.

## Setting the new file's security

A special file needs a [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md) like any other file, and by default a new one inherits its descriptor from the directory it is created in.

`mknod` accepts the shared **creation flags** — `--owner`, `--group`, `--label`, `--no-inherit`, and `--sddl` — to set that descriptor explicitly. They behave exactly as they do for `mkdir`; the full reference is on the [`mkdir`](/peios/using-peios/peiosutils/files-and-directories/mkdir.md) page.

## Exit status

| Code | Meaning |
|---|---|
| `0` | The special file was created. |
| `1` | It could not be created — a missing or invalid type, missing device numbers, or a name that already exists. |

---

# touch

_Peios / Using Peios / Peiosutils / Files and directories_

> Create empty files, or update the timestamps of existing ones.

`touch` does one of two things, depending on whether the file already exists:

- if the file **does not exist**, `touch` creates it, empty;
- if the file **does exist**, `touch` updates its timestamps to the current time.

```
touch [options] [file...]
```

```
$ touch notes.txt        # create notes.txt if absent, else bump its times
```

The "create an empty file" behaviour is the everyday use. The "update timestamps" behaviour matters to tools that decide what work to do by comparing file times — `touch` is how you tell such a tool that a file should be considered freshly changed.

## Which timestamps, and to what

By default `touch` sets both the access time and the modification time to the current moment. These options narrow or redirect that.

| Option | Effect |
|---|---|
| `-a` | Change only the access time. |
| `-m` | Change only the modification time. |
| `--time=WORD` | Choose which time to change by name: `access`, `atime`, or `use` for the access time; `modify` or `mtime` for the modification time. |
| `-d`, `--date=STRING` | Use the time described by `STRING` instead of the current time. |
| `-t STAMP` | Use the time given as `[[CC]YY]MMDDhhmm[.ss]` instead of the current time. |
| `-r`, `--reference=FILE` | Use the timestamps of `FILE` instead of the current time. |
| `-h`, `--no-dereference` | If the named file is a symbolic link, change the link's own timestamps rather than those of the file it points to. |

## Not creating a file

To use `touch` purely to update timestamps, and never to create anything:

| Option | Effect |
|---|---|
| `-c`, `--no-create` | Do not create a file that does not exist. A named file that is absent is silently skipped. |

## Setting a created file's security

When `touch` *creates* a file, that new file needs a [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md), and by default it inherits one from the directory it is created in.

`touch` accepts the shared **creation flags** — `--owner`, `--group`, `--label`, `--no-inherit`, and `--sddl` — to set that descriptor explicitly. They behave exactly as they do for `mkdir`; the full reference is on the [`mkdir`](/peios/using-peios/peiosutils/files-and-directories/mkdir.md) page.

These flags apply **only on the create path**. If `touch` is updating the timestamps of a file that already exists, there is no new descriptor to set, and the creation flags have nothing to do — they do not alter an existing file's security. Pair them with `-c` and they never take effect at all, since `-c` means nothing is ever created.

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every file was created or updated as requested. |
| `1` | A file could not be created or updated. |

---

# ln

_Peios / Using Peios / Peiosutils / Files and directories_

> Create hard links and symbolic links between files.

`ln` creates **links** — extra ways to reach a file.

```
ln [options] target link_name
ln [options] target
ln [options] target... directory
ln [options] -t directory target...
```

```
$ ln -s /opt/app/bin/app /lcl/bin/app   # a symbolic link
$ ln data.csv data-archive.csv                # a hard link
```

## Hard links and symbolic links

There are two kinds of link, and they are genuinely different things.

A **hard link** is another name for the *same file*. The file's data exists once; a hard link is an additional directory entry pointing at it. Every hard link to a file is equal — none is "the original" — and the file's data stays as long as at least one hard link remains. Hard links cannot span file systems, and cannot be made to directories.

A **symbolic link** is a small file that simply *contains a path*. When something opens a symbolic link, it is redirected to whatever that path names. The symbolic link and its target are separate files: if the target is moved or removed, the link still exists but now points at nothing — it "dangles". Symbolic links can point anywhere, across file systems and at directories.

`ln` creates **hard links by default**, and symbolic links with `-s`. When in doubt, `-s` — a symbolic link's behaviour is the easier one to reason about.

The two also differ in how they are secured. A hard link is not a new file, so creating one involves no new [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md) — every name for the file shares the file's existing one. A symbolic link *is* a new file, and like any new file it inherits its own descriptor from the directory it is created in.

## The forms

- `ln target link_name` — create one link named `link_name`.
- `ln target` — create a link to `target` in the current directory, with the same final name.
- `ln target... directory` — create a link to each `target` inside `directory`.
- `ln -t directory target...` — the same, with the directory named first.

## Options

| Option | Effect |
|---|---|
| `-s`, `--symbolic` | Make symbolic links instead of hard links. |
| `-f`, `--force` | Remove an existing destination file so the link can be created. |
| `-i`, `--interactive` | Ask before removing an existing destination. |
| `-r`, `--relative` | For a symbolic link, write the target as a path relative to the link's own location, rather than an absolute path. |
| `-n`, `--no-dereference` | If `link_name` is itself a symbolic link to a directory, treat it as an ordinary file — replace the link rather than create something inside the directory it points to. |
| `-L`, `--logical` | When the target is a symbolic link, link to what it points to. |
| `-P`, `--physical` | Make a hard link to a symbolic link itself, rather than to its target. |
| `-t`, `--target-directory=DIR` | Create all links inside `DIR`. |
| `-T`, `--no-target-directory` | Treat `link_name` as a plain file, never as a directory to create links inside. |
| `-b`, `--backup[=CONTROL]` | Back up an existing destination before replacing it. |
| `-S`, `--suffix=SUFFIX` | Use `SUFFIX` for backup file names. |
| `-v`, `--verbose` | Print the name of each link as it is created. |

## Inspecting links afterwards

[`readlink`](/peios/using-peios/peiosutils/listing-and-paths/readlink.md) prints where a symbolic link points. The low-level [`link`](/peios/using-peios/peiosutils/files-and-directories/link-and-unlink.md) command makes a single hard link with no options, for scripts that want exactly that and nothing else.

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every link was created. |
| `1` | A link could not be created. |

---

# link and unlink

_Peios / Using Peios / Peiosutils / Files and directories_

> The single-purpose, low-level commands for creating one hard link and for removing one file.

`link` and `unlink` are the bare, single-purpose versions of two operations that [`ln`](/peios/using-peios/peiosutils/files-and-directories/ln.md) and [`rm`](/peios/using-peios/peiosutils/files-and-directories/rm.md) also perform. Each does exactly one thing, takes exactly its operands, and has no options. They exist for scripts that want one precise operation with no surrounding behaviour — no prompting, no link kinds to choose, no recursion.

## `link`

```
link file1 file2
```

`link` creates one hard link: a new name, `file2`, for the existing file `file1`. `file1` must exist; `file2` must not.

```
$ link data.csv data-archive.csv
```

That is the whole command. It performs the link operation directly and reports whether it succeeded. For anything more — symbolic links, replacing an existing destination, linking into a directory — use [`ln`](/peios/using-peios/peiosutils/files-and-directories/ln.md).

## `unlink`

```
unlink file
```

`unlink` removes one file: it deletes the directory entry `file`. It takes a single name and removes it directly.

```
$ unlink stale.lock
```

`unlink` does not prompt, does not recurse, and does not remove directories. For removing several files, removing directories, or any of the safety prompts, use [`rm`](/peios/using-peios/peiosutils/files-and-directories/rm.md).

## Why they exist

`ln` and `rm` are the commands to use day to day — they are flexible and have the safety behaviours. `link` and `unlink` are deliberately rigid: a script that calls `unlink` will *only ever* remove a single file, and a reviewer can see that at a glance. The narrowness is the feature.

## Exit status

Both commands:

| Code | Meaning |
|---|---|
| `0` | The operation succeeded. |
| `1` | The operation failed — a missing or already-existing operand, or a refused request. |

---

# shred

_Peios / Using Peios / Peiosutils / Files and directories_

> Destroy a file's contents by overwriting them repeatedly, so they cannot be recovered — including how --force overrides a file's protection.

`shred` destroys a file's contents. It does not just unlink the file — it **overwrites the data**, repeatedly, so that what was there cannot be read back even with effort and specialised equipment.

```
shred [options] file...
```

```
$ shred -u -v secret-keys.txt
```

[`rm`](/peios/using-peios/peiosutils/files-and-directories/rm.md) removes a file's *name*; the data may sit on the device, recoverable, until something else happens to overwrite it. `shred` overwrites the data on purpose. Use it when a file held something that must not be recoverable.

By default `shred` overwrites a file three times and then **leaves the file in place** — empty of its old contents but still present. That default exists because `shred` is often pointed at device files, which usually should not be removed. To remove the file after shredding it, pass `-u`.

## When shredding actually works

`shred` relies on one assumption: that writing to the file overwrites the *same physical storage* the old data occupied. On a traditional file system that holds. Several common file system designs break it — anything that writes new data to a fresh location instead of in place, keeps snapshots, journals file data, caches copies elsewhere, or compresses. On those, `shred` cannot guarantee the old data is gone.

Backups and remote mirrors are a separate matter entirely: `shred` cannot reach a copy of the file that lives somewhere else.

Treat `shred` as effective on a plain local file system and uncertain otherwise.

## Options

| Option | Effect |
|---|---|
| `-n`, `--iterations=N` | Overwrite `N` times instead of the default of 3. |
| `-u`, `--remove[=HOW]` | Remove the file after overwriting it. `HOW` controls how thoroughly the *name* itself is obscured before the file is unlinked. |
| `-z`, `--zero` | Add a final pass that writes zeros, so the file does not visibly look shredded afterwards. |
| `-s`, `--size=N` | Shred `N` bytes, rather than the whole file. Accepts size suffixes such as `K`, `M`, `G`. |
| `-x`, `--exact` | Do not round the shredded size up to the next full block. Without it, `shred` rounds up so the block's slack space is overwritten too. |
| `--random-source=FILE` | Take the random bytes for the overwrite passes from `FILE`. |
| `-v`, `--verbose` | Show progress as each pass runs. |
| `-f`, `--force` | Override a file's protection: when a live access check shows you cannot write the file, rewrite its security descriptor so the overwrite can proceed (see below). |

## `--force` and a file's protection

To overwrite a file, `shred` has to be able to write it. If the file's [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md) does not grant you write access, an ordinary `shred` cannot proceed.

`-f` (`--force`) handles that case. When `--force` is given and a live access check shows you cannot currently write the file, `shred` **rewrites the file's security descriptor** to one that grants full access, and then overwrites the file. The reasoning is deliberate: the file is about to be destroyed anyway, and `--force` is you saying "override this file's protection."

`--force` can do this only when you are allowed to change the file's security in the first place — that is, when you own the file or hold the right to rewrite its access rules. If you cannot change the descriptor, `--force` cannot grant itself write access, and the shred still fails. `--force` overrides a file's *protection*; it does not manufacture authority you do not have.

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every file was shredded successfully. |
| `1` | A file could not be shredded. |

---

# dd

_Peios / Using Peios / Peiosutils / Files and directories_

> Copy data block by block between files, optionally converting and reshaping it on the way.

`dd` copies data from one place to another, a block at a time, and can transform the data as it goes. It is the tool for low-level copying — writing a disk image to a device, extracting an exact byte range out of a file, copying from or to a raw device.

```
dd [operand]...
```

```
$ dd if=disk.img of=/dev/mydisk bs=4M status=progress
```

## How dd is told what to do

`dd` does not take options in the usual `-x` form. It takes **operands**, each written `name=value`, in any order. With no `if=` operand it reads from standard input; with no `of=` operand it writes to standard output.

## The operands

| Operand | Meaning |
|---|---|
| `if=FILE` | Read input from `FILE`. |
| `of=FILE` | Write output to `FILE`. |
| `bs=BYTES` | Read and write `BYTES` at a time. Sets both the input and output block size at once. |
| `ibs=BYTES` | Input block size (default 512). |
| `obs=BYTES` | Output block size (default 512). |
| `cbs=BYTES` | Conversion block size — used by the `block` and `unblock` conversions. |
| `count=N` | Stop after `N` input blocks, rather than reading to the end. |
| `skip=N` | Skip `N` input blocks before copying. Also spelled `iseek=N`. |
| `seek=N` | Skip `N` output blocks before writing. Also spelled `oseek=N`. |
| `conv=LIST` | Apply the comma-separated conversions below. |
| `iflag=LIST` | Comma-separated input flags — how the input is opened and read. |
| `oflag=LIST` | Comma-separated output flags — how the output is opened and written. |
| `status=LEVEL` | How much to report: `progress` (periodic stats while copying), `noxfer` (final counts only), `none` (silent). |

A size value accepts a unit suffix (`K`, `M`, `G`, …). So `bs=4M` is four mebibytes per block.

## Conversions (`conv=`)

| Value | Effect |
|---|---|
| `ucase` / `lcase` | Convert the data to upper-case / lower-case. |
| `swab` | Swap every adjacent pair of bytes. |
| `sync` | Pad each input block out to its full size — with zeros, or with spaces alongside `block`/`unblock`. |
| `block` / `unblock` | Convert between newline-terminated lines and fixed-size `cbs` records. |
| `sparse` | Where an output block is all zeros, seek past it instead of writing it. |
| `excl` | Fail if the output file already exists. |
| `nocreat` | Fail if the output file does *not* already exist. |
| `notrunc` | Do not truncate the output file when opening it. |
| `noerror` | Continue past read errors instead of stopping. |
| `fdatasync` / `fsync` | Flush the data — or the data and metadata — to storage before finishing. |

When `dd` **creates** the output file — an `of=` file that does not already exist — the new file needs a [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md), and it inherits one from the directory it is created in.

## Input and output flags (`iflag=`, `oflag=`)

| Flag | Applies to | Effect |
|---|---|---|
| `count_bytes` | input | Interpret `count=N` as a number of bytes, not blocks. |
| `skip_bytes` | input | Interpret `skip=N` as a number of bytes. |
| `fullblock` | input | Wait for a full `ibs` of data on each read. |
| `seek_bytes` | output | Interpret `seek=N` as a number of bytes. |
| `append` | output | Open the output in append mode. |
| `direct` | both | Use direct I/O, bypassing the cache. |
| `dsync` / `sync` | both | Use synchronised I/O — for data, or for data and metadata. |
| `nonblock` | both | Use non-blocking I/O. |
| `noatime` | both | Do not update the file's access time. |
| `nocache` | both | Ask the system to drop the file's cached pages. |
| `directory` | both | Fail unless the file is a directory. |

## What dd prints

Unless `status=none` is set, `dd` prints a summary when it finishes:

```
16+0 records in
16+0 records out
67108864 bytes (67 MB, 64 MiB) copied, 1.234 s, 54.4 MB/s
```

The `records in` / `records out` counts are written `complete+partial` — full-sized blocks plus any short final block. `status=progress` prints the last line periodically during a long copy.

## Exit status

| Code | Meaning |
|---|---|
| `0` | The copy completed. |
| `1` | The copy failed — a bad operand, an I/O error, or a file that could not be opened. |

---

# df

_Peios / Using Peios / Peiosutils / Files and directories_

> Report how much space each file system has and how much of it is free.

`df` — "disk free" — reports, for each file system, how much space it has and how much is still available.

```
df [options] [file...]
```

With no arguments, `df` reports on every mounted file system. Given a `file`, it reports on the one file system that file lives on.

```
$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda2       456G  198G  235G  46% /
/dev/sda1       511M   12M  499M   3% /boot
```

## The default columns

Each line is one file system:

- **Filesystem** — the device or source backing it.
- **Size** — its total capacity.
- **Used** — space in use.
- **Avail** — space still available.
- **Use%** — used space as a percentage.
- **Mounted on** — where it is attached in the directory tree.

## Choosing the units

By default sizes are shown in blocks. These options change that.

| Option | Effect |
|---|---|
| `-h`, `--human-readable` | Show sizes with unit suffixes — `456G`, `12M` — using powers of 1024. |
| `-H`, `--si` | Likewise, but using powers of 1000. |
| `-B`, `--block-size=SIZE` | Show sizes scaled to `SIZE` — `-BM` reports in megabytes. |
| `-k` | Use 1024-byte blocks. |

## Choosing what to report

| Option | Effect |
|---|---|
| `-a`, `--all` | Include dummy and otherwise-hidden file systems that `df` would normally skip. |
| `-l`, `--local` | Report only local file systems, skipping network-mounted ones. |
| `-t`, `--type=TYPE` | Report only file systems of type `TYPE`. |
| `-x`, `--exclude-type=TYPE` | Report everything *except* file systems of type `TYPE`. |
| `--total` | Add a final line giving the grand total across everything reported. |

## Changing the output

| Option | Effect |
|---|---|
| `-i`, `--inodes` | Report inode counts — total, used, and free — instead of block space. A file system can run out of inodes while it still has space. |
| `-T`, `--print-type` | Add a column showing each file system's type. |
| `--output[=LIST]` | Replace the default columns with exactly the fields named in `LIST`. With no list, print every available field. |
| `-P`, `--portability` | Use a fixed, simple column layout that does not wrap a long device name onto its own line. |

## Sync behaviour

| Option | Effect |
|---|---|
| `--sync` | Flush pending writes before reading the usage figures, for the most up-to-date numbers. |
| `--no-sync` | Do not flush first. This is the default and is faster. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | The report was produced. |
| `1` | A failure — for example, a named file does not exist, or the table of file systems could not be read. |

---

# du

_Peios / Using Peios / Peiosutils / Files and directories_

> Report how much disk space files and directories use.

`du` — "disk usage" — reports how much space files and directories occupy. Where [`df`](/peios/using-peios/peiosutils/files-and-directories/df.md) tells you about a whole file system, `du` tells you where the space has actually gone.

```
du [options] [file...]
```

```
$ du -sh /home/jack/projects
4.2G    /home/jack/projects
```

With no arguments, `du` works on the current directory. By default it walks the directory tree, prints the cumulative size of **each directory** (a directory's size includes everything under it), and ends with the total for the argument itself. Individual files are not listed unless you ask for them.

## What to count and how deep

| Option | Effect |
|---|---|
| `-a`, `--all` | List every file, not only directories. |
| `-s`, `--summarize` | Print only a single total for each argument — no per-subdirectory breakdown. |
| `-d`, `--max-depth=N` | Show totals only down to `N` levels below each argument. `-d 0` is the same as `-s`. |
| `-S`, `--separate-dirs` | Give each directory's *own* size, excluding its subdirectories. |
| `-c`, `--total` | Add a final grand-total line. |
| `--inodes` | Count inodes used rather than space used. |

## What "size" means

| Option | Effect |
|---|---|
| `-h`, `--human-readable` | Sizes with unit suffixes — `4.2G` — using powers of 1024. |
| `--si` | Likewise, using powers of 1000. |
| `-B`, `--block-size=SIZE` | Scale sizes to `SIZE`. |
| `-k` / `-m` | Use 1024-byte / 1024×1024-byte units. |
| `--apparent-size` | Report the apparent size of files — how much data they contain — rather than the disk space they occupy. The two differ for sparse files and because of block rounding. |
| `-b`, `--bytes` | Report plain byte counts. Equivalent to `--apparent-size --block-size=1`. |

## Following symbolic links

By default `du` does not follow symbolic links.

| Option | Effect |
|---|---|
| `-L`, `--dereference` | Follow all symbolic links and count what they point to. |
| `-D`, `-H`, `--dereference-args` | Follow only the symbolic links named directly on the command line. |
| `-P`, `--no-dereference` | Follow no symbolic links. This is the default. |
| `-x`, `--one-file-system` | Do not cross into a different file system while walking. |
| `-l`, `--count-links` | Count a hard-linked file every time it is encountered, instead of once. |

## Limiting the output

| Option | Effect |
|---|---|
| `--exclude=PATTERN` | Skip files and directories whose name matches `PATTERN`. |
| `--exclude-from=FILE` | Skip everything matching any pattern listed in `FILE`. |
| `-t`, `--threshold=SIZE` | Show only entries at least `SIZE` (or, with a negative `SIZE`, at most that big). |
| `--files0-from=F` | Take the list of files to measure from `F`, NUL-separated. `-` means standard input. |
| `--time[=WORD]` | Also show a timestamp — by default the latest modification time anywhere in the directory. |
| `-0`, `--null` | End each output line with a NUL character instead of a newline. |
| `-v`, `--verbose` | Report extra detail about what is being processed. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | The report was produced. |
| `1` | A file or directory could not be accessed. |

---

# truncate

_Peios / Using Peios / Peiosutils / Files and directories_

> Shrink or extend a file to an exact size.

`truncate` sets a file's size to an exact figure — shrinking it, or extending it.

```
truncate [options] file...
```

```
$ truncate -s 0 logfile        # empty the file
$ truncate -s 1G disk.img      # make a 1 GiB file
```

Shrinking a file discards everything past the new size. Extending it adds space that reads back as zero bytes; that added space is a *hole* — it costs no actual storage until something writes real data into it, which is how `truncate -s 1G` can create a "1 GiB file" instantly.

By default, `truncate` creates a file that does not yet exist (as an empty file, then sized as asked). A file created this way needs a [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md), and it inherits one from the directory it is created in.

## Specifying the size

`-s` (`--size`) takes the size. A plain number sets the size outright. A unit suffix scales it: `K`, `M`, `G`, `T`, … where the bare letter is a power of 1024 (`K` = 1024) and the letter with `B` is a power of 1000 (`KB` = 1000).

A size may also begin with a prefix, which makes it *relative to the file's current size*:

| Prefix | Meaning |
|---|---|
| `+` | Extend by this much. |
| `-` | Reduce by this much. |
| `<` | Shrink to this size only if the file is currently larger ("at most"). |
| `>` | Extend to this size only if the file is currently smaller ("at least"). |
| `/` | Round the size *down* to a multiple of this number. |
| `%` | Round the size *up* to a multiple of this number. |

```
$ truncate -s +4K notes.txt    # 4 KiB larger than it is now
$ truncate -s '<1M' notes.txt  # cap it at 1 MiB, leave smaller files alone
```

## Options

| Option | Effect |
|---|---|
| `-s`, `--size=SIZE` | Set or adjust the size to `SIZE`, as described above. |
| `-r`, `--reference=RFILE` | Base the size on the current size of `RFILE` instead of giving a number. Combine with a relative `-s` to mean "the size of `RFILE`, adjusted". |
| `-c`, `--no-create` | Do not create a file that does not exist; skip it instead. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every file was resized. |
| `1` | A file could not be resized — a bad size, or a file that could not be opened. |

---

# mktemp

_Peios / Using Peios / Peiosutils / Files and directories_

> Create a temporary file or directory with a safely unique name.

`mktemp` creates a temporary file — or, with `-d`, a temporary directory — gives it a name that is not already taken, and prints that name.

```
mktemp [options] [template]
```

```
$ mktemp
/tmp/tmp.QV8x3kZ1aR
$ mktemp -d
/tmp/tmp.7bNc0wPe2L
```

The reason to use `mktemp` rather than inventing a name yourself is **safety**. A script that picks a fixed name like `/tmp/work` has two problems: two copies of the script collide, and a name an attacker can predict is a name an attacker can interfere with before the script gets to it. `mktemp` chooses an unpredictable name *and* creates the file in the same step, so nothing can slip in between. It prints the name it used, for the script to capture:

```
work=$(mktemp)
# ...use "$work"...
rm "$work"
```

The temporary file or directory `mktemp` creates is a new object, and a new object needs a [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md); it inherits one from the directory it is created in.

## Templates

The name comes from a **template** — a name with a run of trailing `X` characters, each of which `mktemp` replaces with a random character. More `X`s means a wider range of possible names.

```
$ mktemp report-XXXXXX.txt
report-a8Kp2Q.txt
```

With no template, `mktemp` uses a built-in default that places the file in the temporary directory. A template needs at least three `X`s.

## Options

| Option | Effect |
|---|---|
| `-d`, `--directory` | Create a directory instead of a file. |
| `-p`, `--tmpdir[=DIR]` | Create the temporary object inside `DIR`. With no `DIR`, use the directory named by the `TMPDIR` environment variable, or the system temporary directory. The template is then just the final name component. |
| `--suffix=SUFFIX` | Append `SUFFIX` after the random part of the name — for giving the file an extension. |
| `-u`, `--dry-run` | Do not create anything; just print a name that *would* be free. This reintroduces the race the command exists to avoid — use it only when you genuinely cannot create the object yet. |
| `-q`, `--quiet` | Print no error message if creation fails; rely on the exit status. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | The temporary file or directory was created; its name was printed. |
| `1` | Creation failed — a bad template, or a directory that does not exist. |

---

# sd

_Peios / Using Peios / Peiosutils / Files and directories_

> The sd command reads and changes a file's security descriptor — owner, access rules, audit rules, integrity label, and inheritance.

`sd` is the command-line tool for working with **security descriptors** on files. Everything this topic describes — owners, DACLs, ACEs, the SACL, integrity labels, inheritance — `sd` is how you read it and change it from a shell.

```
sd subcommand path [arguments]
```

```
$ sd show ./report.txt
$ sd allow ./report.txt alice:read
$ sd owner ./report.txt BA
```

Where [`ls -l`](/peios/using-peios/peiosutils/listing-and-paths/ls.md) shows a file's owner and a summary, and [`cp --preserve`](/peios/using-peios/peiosutils/files-and-directories/cp.md) carries a descriptor across, `sd` is the tool that edits the descriptor directly.

## The subcommands

| Group | Subcommand | Does |
|---|---|---|
| Inspect | `show` | Print the descriptor on a path. |
| | `check` | Simulate an access check against the path. |
| DACL | `allow` | Add an allow rule for one or more principals. |
| | `deny` | Add a deny rule for one or more principals. |
| | `remove` | Drop every DACL rule for the named principals. |
| Auditing | `audit` | Add an audit rule to the SACL. |
| | `unaudit` | Drop every SACL rule for the named principals. |
| Ownership | `owner` | Set the descriptor's owner. |
| | `group` | Set the descriptor's group. |
| Integrity | `integrity` | Set the mandatory integrity label. |
| Inheritance | `inherit` | Turn inheritance protection on or off. |
| | `reset` | Drop the file's own rules and re-inherit from the parent. |
| | `propagate` | Push inheritance down to descendants. |
| Wholesale | `set` | Replace the entire descriptor at once. |

## Naming a principal

Wherever a subcommand takes a `PRINCIPAL`, it accepts any of:

| Form | Example | Meaning |
|---|---|---|
| `@self` | `@self` | The user SID of the token running `sd`. |
| `@owner` | `@owner` | A placeholder that the access check substitutes with the file's own owner. |
| A well-known label | `Everyone`, `Administrators`, `LocalSystem` | A named built-in principal. |
| A two-letter alias | `WD`, `BA`, `SY` | The short alias for a well-known principal. |
| A raw SID | `S-1-5-32-544` | Any SID, written out in full. |

See [SIDs](/peios/security-fundamentals/identity/sids.md) for what these are.

## Naming permissions

Wherever a subcommand takes `PERMS`, several notations are accepted, and may be mixed:

| Form | Example | Meaning |
|---|---|---|
| Single letters | `rwx`, `r`, `m` | `r` read, `w` write, `x` execute, `d` delete, `m` modify, `f` full, `c` change-permissions, `o` take-ownership. |
| Words | `read,write`, `modify` | The same set, spelled out. |
| Fine-grained names | `read-data,append,traverse` | Individual low-level rights, for precise rules. |
| Raw hex | `0x1F01FF` | An access mask written directly. |

Run letters together (`rwx`) or separate names with commas (`read,write,execute`).

## Inspecting

### `sd show`

Prints the descriptor on a path — the owner, the group, the DACL, the SACL.

```
$ sd show ./report.txt
```

| Flag | Effect |
|---|---|
| `--sddl` | Render the descriptor as an SDDL string. |
| `--raw` | Render SIDs in raw `S-1-…` form only. |
| `--label` | Render SIDs as their labels where known. |
| `--all` | Verbose — decode every flag and show raw masks alongside. |
| `--json` | Emit JSON. |

### `sd check`

Simulates an [access decision](/peios/security-fundamentals/access-decisions/overview.md): "would this access be allowed?" — without performing it.

```
$ sd check ./report.txt write
$ sd check ./report.txt read --pid 4821 --explain
```

| Argument / flag | Effect |
|---|---|
| `PERMS` | The access to test for. |
| `--pid PID` | Check against process `PID`'s token instead of your own. |
| `--explain` | Show why the decision came out as it did — the rule-by-rule walk. |

`sd check` is the first thing to reach for when an access is denied and you do not know why. `--explain` walks the descriptor the same way the kernel does.

## Changing the DACL

The DACL is the list of allow and deny rules. These three subcommands edit it.

### `sd allow` and `sd deny`

Add an allow (or deny) rule for one or more `PRINCIPAL:PERMS` pairs.

```
$ sd allow ./report.txt alice:read bob:rw
$ sd deny  ./report.txt Everyone:write
```

| Flag | Effect |
|---|---|
| `--flags LIST` | ACE inheritance flags — `CI` container-inherit, `OI` object-inherit, `NP` no-propagate, `IO` inherit-only; `none` clears them. |
| `--if EXPR` | Make it a [conditional rule](/peios/security-fundamentals/security-descriptors/conditional-aces.md), applied only when `EXPR` is true. |
| `--replace` | Drop any existing rules for this principal and kind first, instead of appending. |
| `--recursive`, `-r` | Apply to every descendant of the path. |

Remember that a **deny** rule, when it matches, wins over any allow — see [DACL evaluation](/peios/security-fundamentals/security-descriptors/dacl-evaluation.md).

### `sd remove`

Drops every DACL rule — allow and deny — for the named principals.

```
$ sd remove ./report.txt bob carol
```

| Flag | Effect |
|---|---|
| `--allow-empty` | Permit the result to be a present-but-empty DACL, which denies everyone. Without this, `sd` refuses to produce one. |
| `--recursive`, `-r` | Apply to every descendant. |

## Auditing

### `sd audit` and `sd unaudit`

The SACL holds audit rules — see [The SACL](/peios/security-fundamentals/security-descriptors/the-sacl.md). `sd audit` adds one; `sd unaudit` drops every SACL rule for the named principals.

```
$ sd audit ./secrets.db Everyone:write:failure
```

An audit spec is `PRINCIPAL:PERMS:WHEN`, where `WHEN` is `success`, `failure`, or `both` — which outcomes to log. `sd audit` takes the same `--flags`, `--if`, `--replace`, and `-r` options as `sd allow`.

## Ownership

### `sd owner` and `sd group`

Set the descriptor's owner or group SID.

```
$ sd owner ./report.txt alice
$ sd group ./report.txt Administrators
```

Both take a single `PRINCIPAL` and accept `-r`. Changing an owner is itself an access-controlled act — see [Ownership](/peios/security-fundamentals/security-descriptors/ownership.md).

## Integrity

### `sd integrity`

Sets the file's mandatory integrity label.

```
$ sd integrity ./report.txt high
```

The level is one of `untrusted`, `low`, `medium`, `medium-plus`, `high`, `system`, `protected`. The standard catalog is five levels (`untrusted`, `low`, `medium`, `high`, `system`); `medium-plus` (RID 8448) and `protected` (RID 20480) are non-standard Windows-compatibility levels — the kernel compares any `S-1-16-<rid>` numerically.

| Flag | Effect |
|---|---|
| `--policy BITS` | The label's policy bits, comma-separated: `NW` no write-up, `NR` no read-up, `NX` no execute-up. |
| `--recursive`, `-r` | Apply to every descendant. |

For what the label does, see [Mandatory integrity control](/peios/security-fundamentals/access-decisions/mandatory-integrity-control.md).

## Inheritance

### `sd inherit`

Turns inheritance protection on or off — the `+` mark `ls -l` shows.

```
$ sd inherit off ./report.txt    # lock the file; stop inheriting
$ sd inherit on  ./report.txt    # let it inherit from its parent again
```

`inherit on` lets the file inherit rules from its parent directory. `inherit off` protects the file — it keeps its current rules and stops tracking the parent.

| Flag | Effect |
|---|---|
| `--strip-inherited` | When turning protection off, also drop the inherited rules already on the file. |
| `--recursive`, `-r` | Apply to every descendant. |

### `sd reset`

Drops the file's own explicit rules and rebuilds its DACL purely from what the parent directory hands down — returning the file to "inherits everything".

### `sd propagate`

Pushes this directory's inheritable rules down into its descendants, refreshing what they inherit. Use it after changing a directory's rules so the children pick up the change.

See [Inheritance](/peios/security-fundamentals/security-descriptors/inheritance.md) for the full model.

## Replacing the whole descriptor

### `sd set`

Replaces the entire descriptor in one step.

```
$ sd set ./report.txt 'O:BAG:BAD:P(A;;FA;;;BA)(A;;0x1200a9;;;BU)'
```

| Argument / flag | Effect |
|---|---|
| `SDDL` | The new descriptor as an SDDL string. `-` reads it from standard input. |
| `--binary FILE` | Instead of SDDL, read the raw descriptor bytes from `FILE` (`-` for standard input). |
| `--components LIST` | Override which parts of the descriptor (owner, group, DACL, SACL) the operation writes. |

## Common flags

These apply across the subcommands:

| Flag | Effect |
|---|---|
| `--recursive`, `-r` | Apply the change to every descendant of the path. |
| `--no-follow-symlinks`, `-P` | Operate on a symbolic link itself, not the file it points to. |
| `--json` | Emit JSON instead of human-readable output. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | The operation succeeded — or, for `sd check`, the access would be **allowed**. |
| non-zero | The operation failed, the path was unreachable, or — for `sd check` — the access would be **denied**. |
