---
# System prepended metadata

title: Recitation 3

---

# Recitation 3
### 1. Permission Management

File permissions are composed of three parts: owner permissions, group permissions, and other user permissions. Each part has three types of permissions: read, write, and execute.

For example, the permissions of a file represented as `-rwxr-xr--`:
- `-`  The first character indicates the file type. In this case, it's a regular file. If it were a directory, it would be `d`
- `rwx` - The file owner has read, write, and execute permissions.
- `r-x` - The file group has read and execute permissions but not write permission.
- `r--` - Other users have read permission, without write and execute permissions.

#### Changing Permissions with `chmod`

1. **Change Permissions Using Alphabetic Notation**

   - **Add Execute Permission to the Owner**
     ```bash
     chmod u+x filename
     ```
     If the original permission was `rw-r--r--`, the new permission will be `rwxr--r--`.

   - **Remove Write Permission from the Group**
     ```bash
     chmod g-w filename
     ```
     If the original permission was `rwxrwxrwx`, the new permission will be `rwxr-xrwx`.

   - **Add Read Permission to Others**
     ```bash
     chmod o+r filename
     ```
     If the original permission was `rwxr-x---`, the new permission will be `rwxr-x--r`.

2. **Change Permissions Using Numeric Notation**
    The first digit is for owner permissions, the second digit is for group permissions, and the third is for other users. Each permission has a numeric value assigned to it: r (read): 4, w (write): 2, x (execute): 1

   - **Set Read, Write, and Execute Permissions for Owner, Group, and Others**
     ```bash
     chmod 777 filename
     ```
     The permission will be set to `rwxrwxrwx`.

   - **Set Owner to Read, Write, and Execute Permission; Group to Read and Execute Permission; Others to Read Permission**
     ```bash
     chmod 754 filename
     ```
     The permission will be set to `rwxr-xr--`.

#### Practical Example

Assume there is a file named `example.txt` with initial permissions `rw-r--r--`:

- The owner can read and write the file but cannot execute it.
- The group users and other users can only read the file.

We can use the `chmod` command to change these permissions:

```bash
chmod u+x example.txt  # Add execute permission to the owner
chmod g+w example.txt  # Add write permission to the group users
chmod o-w example.txt  # Remove write permission from other users (though they initially don't have write permission)
```

The updated permissions will be `rwxrw-r--`.

- The owner can read, write, and execute the file.
- The group users can read and write the file but cannot execute it.
- Other users can only read the file.

### 2. File Operations in C Language


#### Example 1: Using Predefined File Descriptors

In UNIX and Linux systems, a file descriptor is a non-negative integer that represents the way processes access files, pipes, and network sockets. Here are some common file descriptors:

- 0 - Standard Input (stdin)
- 1 - Standard Output (stdout)
- 2 - Standard Error (stderr)
- 3 - New file (In C language)

When you open a file, the system returns a new file descriptor, typically the smallest unused integer.

**Working Principle**: The `open` function returns a file descriptor representing the opened file. The `read` and `write` functions access the file through the file descriptor. The `close` function closes the opened file descriptor, freeing up resources.

```c
#include <unistd.h>

int main() {
    // Write data to standard output
    write(1, "Hello, World!\n", 14);

    // Write error message to standard error
    write(2, "An error occurred.\n", 19);

    return 0;
}
```

#### Example 2: Reading and Writing Files Using File Descriptors

Here is a C language example demonstrating how to use file descriptors to open, read, write, and close files.

```c
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    int fd = open("example.txt", O_CREAT | O_RDWR, 0644);
    if (fd == -1) {
        perror("Cannot open");
        return 1;
    }

    // Write data to the file
    const char *data = "Hello, World!\n";
    ssize_t written = write(fd, data, 14);
    if (written == -1) {
        perror("Cannot write");
        close(fd);
        return 1;
    }

    // Move the file position pointer to the beginning of the file
    lseek(fd, 0, SEEK_SET);

    // Read data from the file
    char buffer[1024];
    ssize_t bytesRead = read(fd, buffer, sizeof(buffer) - 1);
    if (bytesRead == -1) {
        perror("Cannot read");
        close(fd);
        return 1;
    }
    buffer[bytesRead] = '\0';  // Add the string termination character

    // Print the read data
    printf("%s", buffer);

    // Close the file descriptor
    close(fd);

    return 0;
}
```

In this example:

- The `fcntl.h` header is for `file control options`
- The `open` function is used to open a file and returns a file descriptor `fd`.
- The `write` function uses this file descriptor to write data to the file.
- The `lseek` function is used to move the file position pointer.
- The `read` function uses the same file descriptor to read data from the file.
- The `close` function is used to close the file descriptor and release the resources.
- The `perror` function takes a pointer to a null-terminated string, typically containing a user-defined error message. It's followed by a colon and a space, then followed by a textual representation of the system error information.

#### perror and stderr

- **Returning `-1`**: In the context of system calls (such as `read`, `write`, `open`, etc.) and certain library functions, `-1` typically indicates a failure of the operation. In such cases, the `perror` function can be used or the `errno` variable can be checked to obtain details about the error.

- **File Descriptor `2`**: This is the file descriptor for standard error (stderr). Every UNIX or Linux process starts with three default file descriptors: `0` for standard input, `1` for standard output, and `2` for standard error.

For instance, in the following code:

```c
ssize_t bytesRead = read(fd, buffer, sizeof(buffer));
if (bytesRead == -1) {
    // Here, -1 indicates that the read function failed
    perror("read");
    // perror will write the error message to file descriptor 2, i.e., standard error
}
```

If the `read` function fails, `bytesRead` will be `-1`, and the error can be identified and reported using `perror` or `errno`. The error message will be sent to file descriptor `2` (i.e., standard error).

