Filesystems
Class: CSCE-313
Notes:
Question 1
Read the section titled Pseudo Filesystems in Learning Modern Linux and answer the following questions.
- What is the PID of the shell in your GCP VM. Use the
pscommand to find the PID of the shell in which you ran the command. - How many FD's are in the shell's file descriptor table? Use the
/procfilesystem.
1) Find the PID of your current shell
Run:
ps
You will see output similar to this:
PID TTY TIME CMD
1234 pts/0 00:00:00 bash
1250 pts/0 00:00:00 ps
- In this example, the shell is bash, and its PID is 1234.
Sometimes your shell might be sh, zsh, or bash, but on many Linux VMs it is usually bash.
How to identify the shell
The shell is the row whose CMD is your shell program, such as:
- bash
- sh
- zsh
Do not choose the row for ps, because that is just the command you ran to inspect the processes.
2) Find how many file descriptors are in the shell’s file descriptor table
Once you know the shell PID, look in /proc/<PID>/fd.
Using the example PID 1234, run:
ls /proc/1234/fd
That lists the file descriptors currently open for that shell.
0 1 2 255
To count them, run:
ls /proc/1234/fd | wc -l
If the output is:
4
then the shell has 4 file descriptors open.
Why use /proc?
The /proc filesystem is a pseudo-filesystem. It does not store normal files on disk. Instead, it shows information about the kernel and running processes.
For a specific process:
/proc/<PID>/contains information about that process/proc/<PID>/fd/shows the file descriptors that process currently has open
Each entry in that directory corresponds to one open file descriptor.
Question 2
Use mount to find the device on which the root ext4 filesystem is laid out, and then use fdisk -l to determine the block size of the file system.
1. Find the device for the root ext4 filesystem
Run:
mount
- The
mountcommand lists all mounted filesystems. Each entry shows:- the device
- the mount point
- the filesystem type
You will see many mounted filesystems. Look for the line where the mount point is / (the root filesystem).
Example output:
/dev/sda1 on / type ext4 (rw,relatime,discard,errors=remount-ro)
From this line we learn:
- Device:
/dev/sda1 - Mount point:
/ - Filesystem type: ext4
So the root filesystem is stored on /dev/sda1.
2. Determine the block size with fdisk
Now inspect that device with:
sudo fdisk -l
fdisk -llists disk and partition information, including:- disk size
- partitions
- sector size (block size)
- The sector size indicates the basic storage unit used by the filesystem on the disk.
Find the section for the same device you identified earlier.
Example snippet:
Disk /dev/sda: 16 GiB, 17179869184 bytes, 33554432 sectors
Disk model: PersistentDisk
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: 6187B054-63B8-49DD-801F-4A35BBCD6B28
The key line is:
Sector size (logical/physical): 512 bytes / 4096 bytes
This means the filesystem block size is 512 bytes (logical) and 4096 bytes (physical).
Question 3
Find how long the Ubuntu OS on your GCP VM has been up since its last reboot by querying the /proc filesystem.
1. Check the uptime using /proc
Run the following command:
cat /proc/uptime
Output:
1589.23 3095.49
The file contains two numbers (in seconds):
- Total time the system has been running since the last boot
- Total time all CPUs have been idle
For the question, you only need the first number.
1589.23 seconds
Question 4
Print "Hello World" on your terminal by writing "Hello World" to the file that the terminal device represents.
Command to run
Run:
echo "Hello World" > /dev/tty
This will print:
Hello World
to your terminal.
Explanation
In Linux, devices are represented as files inside the /dev directory.
/dev/tty is a special device file that represents the current terminal session.
That means any data written to /dev/tty is displayed directly on the terminal.
Question 5
What is the significance of the x bit (execute) on a directory in Linux? Create a directory, say f, and create three files inside f: say these files are a, b, c. Change the permission of f to 400 using chmod 400 f. Can you still do ls f? Can you do ls -l f? Explain what you see.
1. What the execute (x) bit means on a directory
For directories, the execute permission (x) allows users to enter and traverse the directory.
Specifically, the x bit allows you to:
- Access files inside the directory
- Traverse the directory path
- Use commands like
cd,ls, or open files within it (if other permissions allow it)
Without the execute permission, even if you know the file names inside the directory, you cannot access them.
Directory permissions behave differently than file permissions:
| Permission | Meaning for directories |
|---|---|
| r | Allows listing the directory contents |
| w | Allows creating, deleting, or renaming files |
| x | Allows entering/traversing the directory |
2. Create the directory and files
Run the following commands:
mkdir f
touch f/a f/b f/c
This creates:
f/
├── a
├── b
└── c
3. Change permissions
Now remove execute permission:
chmod 400 f
Check permissions:
ls -ld f
Example output:
dr-------- 2 user user 4096 Mar 8 12:00 f
Meaning:
d→ directoryr--------→ owner has read only, no execute permission
4. Try listing the directory
Run:
ls f
Output:
ls: cannot access 'f/a': Permission denied
ls: cannot access 'f/b': Permission denied
ls: cannot access 'f/c': Permission denied
a b c
Why this happens?
- Even though you have read permission, you do not have execute permission, which means the system cannot traverse the directory to access its entries.
- So Linux knows the directory exists, but it cannot access the files inside it.
5. Try long listing
Run:
ls -l f
Output:
ls: cannot access 'f/a': Permission denied
ls: cannot access 'f/b': Permission denied
ls: cannot access 'f/c': Permission denied
total 0
-????????? ? ? ? ? ? a
-????????? ? ? ? ? ? b
-????????? ? ? ? ? ? c
Why?
ls -lrequires accessing file metadata for each file inside the directory.- Without the execute bit, the system cannot traverse the directory, so it cannot retrieve the file information.
6. Takeaway
The execute bit is required to access files inside a directory.
Even if the directory has read permission, you cannot access its contents without the execute permission.
The execute (
x) bit on a directory allows a user to traverse the directory and access files within it. Without the execute permission, the system cannot access the files inside the directory even if read permission is present.
Question 6
Interpret the following mode bits in octal on a filesystem object. What type of object is it?
- 0100664
- 010664
- 0101664
Convert to octal
In Linux, the mode bits of a filesystem object encode two things:
- The file type
- The permission bits
These are typically stored as a 6-digit octal number:
TTPPPP
Where:
- TT = file type bits
- PPPP = permission bits
Common file type values:
| Octal Prefix | File Type |
|---|---|
| 010 | Regular file |
| 004 | Directory |
| 012 | Symbolic link |
| 006 | Block device |
| 002 | Character device |
| 001 | FIFO (named pipe) |
| 014 | Socket |
The last three digits represent permissions:
| Digit | Meaning |
|---|---|
| Owner | permissions for owner |
| Group | permissions for group |
| Others | permissions for others |
Permission values:
| Value | Meaning |
|---|---|
| 4 | read |
| 2 | write |
| 1 | execute |
1. Mode: 0100664
File type
010 → regular file
Permissions
664
Breakdown:
| User | Permission |
|---|---|
| Owner | rw- (6) |
| Group | rw- (6) |
| Others | r– (4) |
Result
- Object type: Regular file
- Permissions:
rw-rw-r--
2. Mode: 010664
This is essentially the same value but written without the extra zero padding.
File type
010 → regular file
Permissions
664
Result
- Object type: Regular file
- Permissions: rw-rw-r--
So 0100664 and 010664 represent the same thing, just formatted differently.
3. Mode: 0101664
File type
010 → regular file
Special bits
- The extra 1 indicates the sticky bit.
Permissions
664
| User | Permission |
|---|---|
| Owner | rw- |
| Group | rw- |
| Others | r– |
| Result |
- Object type: Regular file
- Permissions:
rw-rw-r-- - Special bit: sticky bit set
Summary
| Mode | Object Type | Permissions | Notes |
|---|---|---|---|
| 0100664 | Regular file | rw-rw-r– | Standard format |
| 010664 | Regular file | rw-rw-r– | Same as above |
| 0101664 | Regular file | rw-rw-r– | Sticky bit set |
In Unix-like systems, octal values representing file modes are often interpreted as part of the st_mode field, which combines the file type and the permission bits (read/write/execute). While both 0100664 and 010664 represent a regular file, the difference lies in how they are interpreted by certain tools (like git or ls internals) regarding their 16-bit or 32-bit representation.
Key Differences:
0100664(7-digit octal): This is the typical representation for a regular file (in high bits) withrw-rw-r--permissions (664). It is often used in systems that distinguish between file types, with the100indicating a "regular file" type in 16-bit mode structures.010664(6-digit octal): This is a shorter form, often interpreted as a regular file, where the leading digits are implicitly filled. The10prefix usually designates a regular file in Git's internal object mode (100000 for regular files).- Functional Difference: In most common shell commands (like
chmod), the leading digits0100and010are treated similarly as indicating a "regular file" when viewed from a high-level file system perspective, focusing on the trailing 3 or 4 digits (664).
| Octal Value | Type Bits | Permissions | Description |
|---|---|---|---|
| 0100664 | 100 (Reg) | 664 (rw-rw-r--) | Explicitly sets regular file, read/write to owner/group, read to others |
| 010664 | 10 (Reg) | 664 (rw-rw-r--) | Often interpreted as regular file by specific tools (e.g., git) |
Note: In octal notation, the leading 0 simply indicates that the number is octal, not part of the permission value. |
Question 7
Do problem 1 under Weekly-HW → Filesystems on the class website.W
What are the possible contents of the file foo when the following code is executed? Read the manual page entry for the Unix command od and examine the contents of the file after executing the program using od -c -A d foo. What are the permission bits on foo if the file did not exist when the code is executed. What if the file already existed?
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd;
char *fname = "foo";
fd = open(fname, O_CREAT|O_TRUNC|O_WRONLY, S_IRWXU);
write(fd, "pqrs", 2);
write(fd, "jklmn", 6);
close(fd);
return 0;
}
What the program does
fd = open(fname, O_CREAT|O_TRUNC|O_WRONLY, S_IRWXU);
write(fd, "pqrs", 2);
write(fd, "jklmn", 6);
open(...)- Flags:
O_CREATcreates foo if it does not existO_TRUNCtruncates it to length 0 if it already existsO_WRONLYopens it write-only
- Mode:
S_IRWXUmeans owner getsrwx, which is octal 0700
- Flags:
- First write:
write(fd, "pqrs", 2);- This writes only the first 2 bytes of "pqrs"
- So after this, the file contains:
pq
- Second write
write(fd, "jklmn", 6);- The string literal "jklmn" in memory is actually:
j k l m n \0 - because C strings end with a null byte (
\0). - So writing 6 bytes writes:
jklmn\0 - So the final file contents are:
pqjklmn\0 - That is 8 bytes total.
- The string literal "jklmn" in memory is actually:
What od -c -A d foo would show
Shows the file byte-by-byte as characters, with decimal offsets.
Output:
$ od -c -A d foo
0000000 p q j k l m n \0
0000008
Possible contents of foo
There is really one intended result here, assuming all system calls succeed:
pqjklmn\0
- The null byte at the end is part of the file because the second write asks for 6 bytes.
- So if you inspect it with normal text tools, it may look strange, because the last byte is not a printable character.
Permission bits if foo did not exist
When the file does not already exist, open(..., O_CREAT, S_IRWXU) creates it with mode:
S_IRWXU = 0700
That means:
- owner: read, write, execute
- group: no permissions
- others: no permissions
So the created file would have permissions:
0700
or symbolically:
rwx------
Important detail: umask
In practice, the actual permissions are affected by the process’s umask.
So the real created mode is:
0700 & ~umask
- For example, if the umask were 022, the file would still end up as 0700, since group/other bits are already off.
What if foo already existed?
If foo already exists:
O_CREATdoes nothingO_TRUNCtruncates the file to length 0- the file is then overwritten with the new 8 bytes
So the contents still become:
pqjklmn\0
But the permission bits do not change just because of open with O_CREAT.
- That mode argument is only used when creating a new file.
- So, if foo already existed, its existing permission bits remain unchanged.
The program opens foo for writing, creates it if needed, and truncates it if it already exists. The first call: write(fd, "pqrs", 2); writes only the first two characters, so it writes pq. The second call: write(fd, "jklmn", 6); writes six bytes: j, k, l, m, n, and the terminating null byte \0. Therefore the final contents of foo are: pqjklmn\0
Using od -c -A d foo:
0000000 p q j k l m n \0
0000008
- If foo did not exist before execution, it is created with permission bits
0700 (rwx------), but in practice we still need to consider umask in this calculation. - If foo already existed, its contents are truncated and replaced, but its permission bits remain whatever they were before because of open with
O_CREAT(only used when creating a file).
Question 8
Do Problem 4 under Weekly-HW -> Filesystems on the class website
What permission bits does a file have if it's readable and executable by everyone except for the owner of the file?
Calculating permissions
We need permissions such that:
- Owner → not readable, not executable
- Group → readable and executable
- Others → readable and executable
Recall the permission values:
| Permission | Value |
|---|---|
| read (r) | 4 |
| write (w) | 2 |
| execute (x) | 1 |
Owner permissions
Owner should have no read and no execute, and no write mentioned either. So owner permissions are:
---
Octal value:
0
Group permissions
Group must have:
r-x
That is
4 + 1 = 5
Other permissions
Others must also have:
r-x
Octal value:
4 + 1 = 5
Final octal permission
Octal value:
055
Symbolic form:
---r-xr-x
Question 9
The setuid and setgid bits. The setuid (set user ID) and setgid (set group ID) bits are special permission bits in Linux that affect how processes execute:
- Setuid bit (octal 4000): When set on an executable file, the process runs with the privileges of the file’s owner rather than the user who executed it. For example,
/usr/bin/passwdhas the setuid bit set, allowing regular users to change their passwords (which requires modifying/etc/shadow, normally restricted to root). - Setgid bit (octal 2000): When set on an executable, the process runs with the privileges of the file’s group. When set on a directory, new files created within inherit the directory’s group ownership rather than the creator’s primary group.
These bits appear in the execute position: s for setuid/setgid. The uppercase letter S indicates the corresponding execute bit is not set. In other words, $$s=x+\text { setuid }$$
while $$S=\bar{x}+\text { setuid }$$
What is the octal representation of the file permissions -rwsr-xr-x?
Options:
- 0755
- 4755
- 2755
- 6755
Overall explanation:
1. Identify the file type
The first character:
-
- means it is a regular file (not part of the permission number).
2. Break the permissions into groups
rws r-x r-x
| Section | Meaning |
|---|---|
| rws | owner permissions |
| r-x | group permissions |
| r-x | others permissions |
3. Convert the normal permissions to octal
Using:
| Permission | Value |
|---|---|
| r | 4 |
| w | 2 |
| x | 1 |
Owner: rws
s means:
- execute bit is set
- setuid bit is also set
Note:
s(lowercase): The execute bit () is present ( ) + the setuid bit is present ( ). S(uppercase): The execute bit () is NOT present ( ) + the setuid bit is present ( ).
Normal permissions:
rwx = 4 + 2 + 1 = 7
Group: r-x
4 + 1 = 5
Others: r-x
4 + 1 = 5
So the base permissions are:
755
4. Add the special bit
s in the owner execute position means the setuid bit is set.
Setuid value:
4000
So we add it:
4000 + 0755 = 4755
Answer: 4755
Question 10
Consider the following program.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main(void) {
if(open("/foo/bar", O_RDONLY) < 0) exit(1);
}
The program exits with a value of 1 if it cannot open the file **/foo/bar**. How can we change this program to print a more specific message that indicates the reason for failure to open the file? Hint: use **perror** (man 3 perror).
Consider the following program.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main(void) {
if(open("/foo/bar", O_RDONLY) < 0) exit(1);
}
The program exits with a value of 1 if it cannot open the file /foo/bar. How can we change this program to print a more specific message that indicates the reason for failure to open the file? Hint: use perror (man 3 perror).
Understanding current program
The program currently exits silently if open() fails:
if(open("/foo/bar", O_RDONLY) < 0) exit(1);
However, when a system call like open() fails, it sets a global variable called errno that contains the reason for the failure (for example: file not found, permission denied, etc.).
The function perror() prints a human-readable message describing the error stored in errno.
Modified program using perror
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main(void) {
if (open("/foo/bar", O_RDONLY) < 0) {
perror("open");
exit(1);
}
}
How it works
open("/foo/bar", O_RDONLY)tries to open the file in read-only mode.- If the call fails, it returns -1.
- The kernel sets
errnoto indicate the reason for failure.
perror("open") prints the message:
open: <error description>
Example outputs might be:
open: No such file or directory
or
open: Permission denied
The program can be modified to print a more specific error message by using the
perror()function. When a system call such asopen()fails, it sets the global variableerrnoto indicate the reason for the failure. Theperror()function readserrnoand prints a descriptive error message. By callingperror("open")whenopen()returns a negative value, the program prints the reason why the file/foo/barcould not be opened.
Question 11
Which bit pattern represents a directory with permissions drwxr-xr-x? Note that the leading 0 in the choices indicates that the # is specified in octal. You can use an online octal to binary converter such as the one at www.rapidtables.com to simplify your life.
Options:
- 0040755
- 0100755
- 0040644
- 0120755
Overall explanation:
1. Identify the file type
The first character:
d
- means the object is a directory.
In Linux mode bits, the directory type is represented by:
040000
2. Convert the permission bits
Permissions:
rwx r-x r-x
Convert each group to octal:
| Permission | Calculation | Octal |
|---|---|---|
| rwx | 4+2+1 | 7 |
| r-x | 4+1 | 5 |
| r-x | 4+1 | 5 |
So the permission part is:
0755
3. Combine file type and permissions
Combined mode:
040755
With the leading zero indicating octal formatting:
0040755
Question 12
Consider this code that creates a file:
int fd = open("newfile.txt", O_CREAT | O_WRONLY, 0644);
If the process's umask is set to 0022, what will be the actual permissions of the created file? Explain your reasoning. See APUE Section 4.8 for an explanation of umask. Specifically, for the open system call, the actual permission bits used to create the new file are $$\text { mode } \wedge \overline{u m a s k}$$
Notes:
- mode = permissions requested by the program
- umask = bits that must be turned off
1. Given values
Requested mode in the program:
0644
This corresponds to:
rw-r--r--
| Owner | Group | Others |
|---|---|---|
| rw- | r– | r– |
Process umask:
0022
This means:
----w--w-
- So the umask removes write permission for group and others.
2. Compute the complement of the umask
~0022 = 0755
In permission form:
rwxr-xr-x
3. Apply the formula
Compute in octal:
0644
&0755
-----
0644
4. Final result
The resulting permissions remain:
0644
Symbolically
rw-r--r--
Why the permissions do not change
The umask only removes permissions that were requested. Since the requested mode 0644 already does not include write permission for group and others, the umask 0022 has no additional effect.
The file will be created with permissions 0644 (rw-r--r--). The final mode is computed as:
mode & ~umask
0644 & ~0022
0644 & 0755 = 0644
The bitwise AND operation (&) compares each bit of two numbers and returns a 1 only if both bits are 1. To see why 0644 & 0755=0644, we must convert the octal digits into their 3-bit binary equivalents.
Convert Octal to Binary
In octal, each digit represents 3 bits (4, 2, and 1):
- 0644 in binary:
- 6=110
- 4=100
- 4=100
- Result:
110 100 100
- 0755 in binary:
- 7=111
- 5=101
- 5=101
- Result:
111 101 101
Perform the Bitwise AND
Now, we compare the bits vertically. A
| Position | 0644 (Binary) | 0755 (Binary) | Result (Binary) | ||
|---|---|---|---|---|---|
| Owner | 1 1 0 |
1 1 1 |
1 1 0 |
||
| Group | 1 0 0 |
1 0 1 |
1 0 0 |
||
| Other | 1 0 0 |
1 0 1 |
1 0 0 |
Full Binary Result: 110 100 100
Convert Back to Octal
Finally, convert the binary result groups back into octal digits:
110=100=100=
Final Octal:
Question 13
A file has permissions -rwsr-sr-x with octal 6755. What happens when a regular user executes this file? You can read more about setuid and setguid in APUE Section 4.4.
Options:
- The process runs with the user's normal privileges
- The process runs with the owner's user ID and the file's group ID
- The process runs with root privileges
- The execution is denied due to security restrictions
Overall explanation:
Reasoning
This specific octal mode, 6755, is a combination of standard permissions and two special "set" bits. Here is how it breaks down:
1. The Special Bits (6xxx)
The leading 6 in the octal representation is the sum of two special bits:
- SetUID (4): Represented by the
sin the owner's position (rws). - SetGID (2): Represented by the
sin the group's position (r-s). - Total:
.
2. The Execution Behavior
When a regular user executes this file, the operating system changes the Effective User ID (EUID) and Effective Group ID (EGID) for that specific process:
- SetUID (User ID): The process ignores the identity of the person who clicked "run" and instead inherits the privileges of the file's owner.
- SetGID (Group ID): Similarly, the process inherits the privileges of the file's group, regardless of the user's primary group.
Comparison of Options
| Scenario | Mode Bits | Behavior |
|---|---|---|
| Normal Execution | 0755 |
Runs as the user who executed it. |
| SetUID Only | 4755 |
Runs as the file owner. |
| SetGID Only | 2755 |
Runs as the file's group. |
| SetUID + SetGID | 6755 |
Runs as both the file owner and the file group. |
Question 14
What are all the groups that you belong to on your GCP VM? Run the id command. How many groups are present on your VM? All the groups are defined in the /etc/group file. Read more about group id's in APUE Section 6.5.
Using the id command
macc@instance-csce-313-1:~/Sandbox/filesystems$ id
uid=1002(macc) gid=1003(macc) groups=1003(macc),4(adm),20(dialout),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),119(netdev),120(lxd),1000(ubuntu),1001(google-sudoers)
Count total groups on your VM:
macc@instance-csce-313-1:~/Sandbox/filesystems$ cat /etc/group | wc -l
64
Question 15
What does the library function makecontext (man 3 makecontext) do? Summarize in a couple of sentences. Don't copy the description from the manual page.
Answer:
makecontext is used to manually set up a user-level execution context (a thread-like state) within a specific memory region. It modifies a context structure—previously initialized by getcontext—so that when it is later activated by setcontext or swapcontext, the program begins executing a specified function with a custom-allocated stack.
Essentially, it "primes" a context to behave like a new entry point, allowing developers to implement cooperative multitasking or "coroutines" by jumping between different execution flows within a single process.
Key Requirements for makecontext
To use it effectively, you must manually handle the following before the call:
- Allocate a Stack: You must assign a memory block to
uc_stack.ss_sp. - Set Stack Size: You must define the size in
uc_stack.ss_size. - Define a Successor: You can set
uc_linkto point to another context that should resume once the current function finishes.
makecontext sets up a user-level execution context so that when the context is activated, it starts running a specific function. It's typically used with getcontext and setcontext/swapcontext to implement user-level threads or coroutines by letting you switch execution between different functions with their own stacks.
Question 16
Given the following code snippet, what will be printed? Read the man page for the system call stat in section 2 of the man pages. You can find more about S_ISREG in APUE Section 4.3.
struct stat sb;
stat("/usr/bin/sudo", &sb);
if (S_ISREG(sb.st_mode)) {
printf("Regular file\n");
}
if (sb.st_mode & S_ISUID) {
printf("Setuid bit is set\n");
}
1. S_ISREG(sb.st_mode)
This macro checks whether the file is a regular file.
/usr/bin/sudois an executable program stored as a regular file, so this condition is true.
So it prints:
Regular file
2. sb.st_mode & S_ISUID
S_ISUID checks whether the setuid bit is set.
- The sudo program normally has the setuid bit enabled so that it can run with root privileges when executed by regular users.
- If you do:
ls -l /usr/bin/sudoyou will see it is-rwsr-xr-x
So this condition is also true, and it prints:
Setuid bit is set
Final output:
Regular file
Setuid bit is set
Question 17
Analyze this code that modifies the permissions:
struct stat sb;
stat("myfile", &sb);
chmod("myfile", sb.st_mode | S_IXUSR | S_IXGRP);
What will happen to the file's permissions? Read the manual page for the system call chmod in section 2.
1. stat("myfile", &sb);
This retrieves the file's metadata and stores it in sb.
The current permission bits are stored in:
sb.st_mode
2. chmod("myfile", sb.st_mode | S_IXUSR | S_IXGRP);
The new mode is computed using the bitwise OR (|) operator.
S_IXUSR→ execute permission for the ownerS_IXGRP→ execute permission for the group
Using | means those bits are added (turned on) while keeping all existing permission bits unchanged.
Result
- The file will gain execute permission for the owner and group.
- All other existing permissions remain the same.
- If the execute bits were already set, nothing changes.
Example:
If the file originally had:
rw-r--r-- (0644)
after the code runs it becomes:
rwxr-xr-- (0754)
The program keeps the current permissions of myfile but ensures that execute permission is set for the owner and the group.
Question 18
A directory has permissions drwxrwsr-x (octal 2775). When a user creates a file in this directory, what group will own the new file? See Resources → Filesystems → u+/g+/t for directories on the class website.
Options:
- The user's primary group
- The directory's group
- The root group
- A new group is created automatically
Overall explanation:
- Key part: setgid bit (2)
- The leading 2 means the setgid bit is set on the directory.
- When setgid is set on a directory: Any new files or subdirectories created inside it inherit the directory’s group ownership, not the creator’s primary group.
- What happens when a user creates a file
- Even if the user belongs to another group, the new file will be assigned the same group as the directory.
- This is commonly used for shared project directories so that all files remain owned by the same group.
Question 19
Which of the following file mode bits has the value 0001 in octal?
Options:
- Owner execute permission
- Group execute permission
- Other execute permission
- Sticky bit
Overall explanation:
the octal value:
0001
means:
- owner: 0
- group: 0
- others: 1
The value 1 corresponds to the execute bit.
Since it appears in the others position, it represents: execute permission for others.
Apparently they were putting padding and not specifying file type so it was instead referring to the owner execute permission?
Question 20
Consider a file with permissions -rwsr-Sr-x (note the capital ‘S’). What does the capital ‘S’ indicate, and what security implications might this have?
What the capital S means
A capital S means the setgid bit is set but the execute bit for the group is not set.
Normally:
s= execute + setuid/setgidS= setuid/setgid set but execute NOT set
So in r-S:
r= group read-= no group writeS= setgid bit is present but the execute bit is missing
Security implication
Because the group execute bit is not set, the file cannot be executed by the group, so the setgid bit will not actually take effect during execution.
This usually indicates a misconfigured permission, where the special bit is set but the file cannot be executed by that group. It doesn’t grant extra privileges but may signal incorrect permission settings that should be fixed.
Question 21
Examine the following code snippet, and read the manual page for the stat system call.
struct stat sb;
stat("/home/user/myfile", &sb);
if (sb.st_mode & S_IRUSR) {
printf("Owner has read permission\n");
}
What does the S_IRUSR constant represent, and what operation is being performed with the & operator?
The S_IRUSR Constant
The S_IRUSR constant and the & operator work together to "query" the file's metadata to see if a specific permission is active.
The S_IRUSR constant represents the Read permission bit for the Owner of the file.
In the <sys/stat.h> header file, this is defined as the octal value 0400. When converted to binary, it is a "mask" where only a single bit is turned on (the bit corresponding to the owner's read access).
The Bitwise & (AND) Operator
The & operator performs a Bitwise AND operation. In this context, it is being used as a Bitmasking tool.
When you perform sb.st_mode & S_IRUSR, the CPU compares the two values bit-by-bit:
- A bit in the result is
1only if that bit is1in bothsb.st_mode(the actual file permissions) andS_IRUSR(the bit we are looking for). - If the owner has read permission, the result of the operation will be exactly 0400 (which is "truthy" in C).
- If the owner does not have read permission, the result will be 0 (which is "falsy" in C).
Visualization of the Logic
Imagine myfile has permissions 0644 (rw-r--r--):
| Variable | Octal | Binary Bits |
|---|---|---|
sb.st_mode |
0644 |
1 1 0 1 0 0 1 0 0 |
S_IRUSR |
0400 |
1 0 0 0 0 0 0 0 0 |
Result of & |
0400 |
1 0 0 0 0 0 0 0 0 |
Because the result is non-zero, the if statement evaluates to true, and the message is printed.
Why not use '=='?
You cannot easily use sb.st_mode == S_IRUSR because st_mode contains all the permissions (and the file type). Using '==' would only be true if the file had only owner-read permissions and absolutely nothing else. The & operator allows you to isolate and check one specific bit regardless of what the other bits are doing.
The
S_IRUSRconstant is a bitmask (with an octal value of 0400) that specifically represents the Read permission for the file's Owner.The
&(Bitwise AND) operator is used to "filter" the file's mode bits. It checks if that specific "Read" bit is flipped "on" in the file's actual permissions.If the bit is there, the result is a non-zero value (which C treats as true), and the
printfruns. If the bit is missing, the result is 0 (which is false), and nothing happens. It’s basically a digital "yes/no" check for that one specific permission.