Input-output system calls in C | Create, Open, Close, Read, Write

Input-output system calls in C | Create, Open, Close, Read, Write

System calls in C are requests made by a program to the operating system kernel for services it can’t access directly. These services go beyond input and output devices and include functions like process control, file management, memory management, and inter-process communication. In C programming, various functions, such as create, open, read, and write, are used for input/output system calls.

Important Terminology

What is the File Descriptor?

The file descriptor is basically an integer that would identify an open file of the process.

A file descriptor table is a collection of integer array indices where each index corresponds to a file descriptor. Each element in this table is a pointer to a file table entry. In an operating system, there is one unique file descriptor table for each process.

A file table entry is an in-memory structure representing an open file. It is created when a program requests to open a file. These entries maintain information about the file, including the current file position.

Standard File Descriptors: When a process starts, it automatically has three standard file descriptors open: 0, 1, and 2. These are often referred to as stdin (0), stdout (1), and stderr (2). By default, each of these descriptors points to a file table entry for a file named /dev/tty.

/dev/tty: This is an in-memory surrogate for the terminal. In other words, it’s a representation in the computer’s memory that stands for the terminal device. The terminal, in this context, is a combination of a keyboard and a video screen where the user interacts with the system.

  1. Read from stdin (fd 0):
    When you type on the keyboard, the program reads from standard input (stdin), linked to file descriptor 0, and saves it from the file named /dev/tty.
  2. Write to stdout (fd 1):
    Output you see on the screen is written to standard output (stdout), associated with file descriptor 1, and comes from the file named /dev/tty.
  3. Write to stderr (fd 2):
    Error messages you see on the screen are written to standard error (stderr), linked to file descriptor 2, and also come from the file named /dev/tty.

Input/Output System Calls

There are 5 Input/Output system calls.

1. Create

The creat() function in C is used to create a new empty file. It allows us to specify the permissions and the name of the file we want to create. This function is defined in the <unistd.h> header file, and the flags used as arguments are defined in the <fcntl.h> header file. The creat() function is a system call for file creation in C programming.

Syntax of create() in C

int create(char *filename, mode_t mode);

Parameter

  • filename:It refers to the  name of the file which you want to create
  • mode: It is the permissions of the new file.

Return Value

When creating or opening a file, the first unused file descriptor is often returned, starting with 3 (as 0, 1, and 2 are typically reserved for stdin, stdout, and stderr). If there’s an error, the function returns -1.

How C create() works in OS

  1. Create a new empty file on the disk.
  • Use a file creation function, such as creat() or open() with appropriate flags, to create a new file on the disk.

2.Create a file table entry.

  • The operating system creates an in-memory structure called a file table entry to represent the newly created file. This structure holds information about the file, such as the current file position.

3.Set the first unused file descriptor to point to the file table entry.

  • The operating system assigns the next available file descriptor (starting from 3, as 0, 1, and 2 are often reserved for stdin, stdout, and stderr) to the newly created file. This file descriptor now points to the file table entry in memory.

4.Return the file descriptor used, -1 upon failure.

  • If the file creation and descriptor assignment are successful, return the newly assigned file descriptor. Otherwise, return -1 to indicate an error.

In C, this process might involve using functions like creat(), open(), and checking the return values for success or failure.

2. C open

The open() function in C is used to open a file for reading, writing, or both. It is also capable of creating the file if it does not exist. This function is defined in the <unistd.h> header file, and the flags passed as arguments are defined in the <fcntl.h> header file. When using open(), you can specify flags to control the file opening mode, and it’s important to note that additional flags are needed to create a file if it doesn’t exist.

Syntax of open() in C

int open (const char* Path, int flags);


  • Path: Specify the path to the file you want to open. Use an absolute path (starting with “/”) when not working in the same directory as the C source file. Use a relative path (just the file name with extension) when working in the same directory.
  • Flags: Flags are used to specify how you want to open the file. You can choose from various flags based on your requirements.
FlagsDescription
O_RDONLYIt will Open the file in read-only mode.
O_WRONLYIt will Open the file in write-only mode.
O_RDWRIt will Open the file in read and write mode.
O_CREATIt can Create a file if it doesn’t exist.
O_EXCLIt can Prevent creation if it already exists.
O_ APPENDIt will Open the file and places the cursor at the end of the contents.
O_ASYNCIt will Enable input and output control by signal.
O_CLOEXEC
It will Enable close-on-exec mode on the open file.

O_NONBLOCK
It will Disable the blocking of the file opened.

O_TMPFILE
Create an unnamed temporary file at the specified path.

How C open() works in OS

  1. Find the existing file on the disk.
  • This involves searching for and identifying the file you want to access. You can use the file’s path, either absolute or relative, depending on your current working directory.

2.Create a file table entry.

  • The operating system creates an in-memory structure called a file table entry to represent the existing file. This structure contains information about the file, such as the current file position.

3.Set the first unused file descriptor to point to the file table entry.

  • The operating system assigns the next available file descriptor (typically starting from 3) to the existing file. This file descriptor now points to the file table entry in memory.

4.Return the file descriptor used, -1 upon failure.

  • If the file is successfully opened and a file descriptor is assigned, return the file descriptor. Otherwise, return -1 to indicate an error.

Example of C open()

/ C program to illustrate 
// open system call 
#include <errno.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <unistd.h> 
  
extern int errno; 
  
int main() 
{ 
    // if file does not have in directory 
    // then file foo.txt is created. 
    int fd = open("foo.txt", O_RDONLY | O_CREAT); 
  
    printf("fd = %d\n", fd); 
  
    if (fd == -1) { 
        // print which type of error have in a code 
        printf("Error Number % d\n", errno); 
  
        // print program detail "Success or failure" 
        perror("Program"); 
    } 
    return 0; 
}

Output

fd = 3

3. C close

The close() function in C is used to inform the operating system that you have finished using a file descriptor and want to close the associated file. This function is defined in the <unistd.h> header file.

Syntax of close() in C

int close(int fd);

Parameter

  • fd: It represents the File descriptor of the file that you want to close.

Return Value

  • 0 on success.
  • -1 on error.

How C close() works in the OS

  1. Destroy file table entry referenced by element fd:
    • Ensure that no other process is pointing to the file table entry.
    • Remove or destroy the file table entry associated with the specified file descriptor (fd).
  2. Set element fd of the file descriptor table to NULL:
    • Update the file descriptor table, setting the entry corresponding to fd to NULL. This indicates that the file descriptor is no longer associated with any file.

Example 1: close() in C

// C program to illustrate close system Call 
#include <fcntl.h> 
#include <stdio.h> 
#include <unistd.h> 
  
int main() 
{ 
    int fd1 = open("foo.txt", O_RDONLY); 
    if (fd1 < 0) { 
        perror("c1"); 
        exit(1); 
    } 
    printf("opened the fd = % d\n", fd1); 
  
    // Using close system Call 
    if (close(fd1) < 0) { 
        perror("c1"); 
        exit(1); 
    } 
    printf("closed the fd.\n"); 
}

Output

opened the fd = 3
closed the fd.

Example 2

// C program to illustrate close system Call  
#include<stdio.h>  
#include<fcntl.h>  
int main()  
{  
    // assume that foo.txt is already created  
    int fd1 = open("foo.txt", O_RDONLY, 0);  
    close(fd1);  
      
    // assume that baz.tzt is already created  
    int fd2 = open("baz.txt", O_RDONLY, 0);  
      
    printf("fd2 = % d\n", fd2);  
    exit(0);  
}  

Output

fd2 = 3

When the program starts, file descriptors 0, 1, and 2 are already used. So, the first available file descriptor is 3. After closing and setting them to NULL, the next open() gets file descriptor 3. That’s why the output of this program is 3.

4. C read

The read() function in C reads a specified number of bytes (cnt) from the file associated with the file descriptor (fd) into the memory area pointed to by buf. A successful read() also updates the access time for the file. This function is defined in the <unistd.h> header file.

Syntax of read() in C

size_t read (int fd, void* buf, size_t cnt);

Parameters

  • fd: This is the file descriptor of the file from which you want to read data.
  • buf: The buffer is where the data will be read into. It’s a designated memory area.
  • cnt: This represents the length of the buffer, specifying how much data you want to read.

Important Points

  • buf: Make sure that buf points to a safe memory location and has enough space (at least as much as cnt) to avoid any problems.
  • fd: Use a valid file descriptor from open(). If fd is not valid (NULL), reading will cause an error.
  • cnt: This is how many bytes you want to read. But, keep in mind, the actual number of bytes read may be less than what you asked for
#include <unistd.h> 
  
int main() 
{ 
    int fd, sz; 
    char* c = (char*)calloc(100, sizeof(char)); 
  
    fd = open("foo.txt", O_RDONLY); 
    if (fd < 0) { 
        perror("r1"); 
        exit(1); 
    } 
  
    sz = read(fd, c, 10); 
    printf("called read(% d, c, 10). returned that"
           " %d bytes were read.\n", 
           fd, sz); 
    c[sz] = '\0'; 
    printf("Those bytes are as follows: % s\n", c); 
  
    return 0; 
}

Output

called read(3, c, 10).  returned that 10 bytes  were read.
Those bytes are as follows: 0 0 0 foo.

5. C write

Writes cnt bytes from buf to the file or socket associated with fd. cnt should not be greater than INT_MAX (defined in the limits.h header file). If cnt is zero, write() simply returns 0 without attempting any other action. The write() is also defined inside <unistd.h> header file.

Syntax of write() in C

size_t write (int fd, void* buf, size_t cnt); 

Parameters

  • fd: It is referred as the file descriptor
  • buf: It is the buffer to write data to.
  • cnt: It is the length of the buffer.

Return Value

  • It will returns the number of bytes written on success.
  • It will return 0 on reaching the End of File.
  • return -1 on error.
  • return -1 on signal interrupts

Important Points about C write

  • File Open: Make sure the file is opened for writing before using write().
  • Buffer Size: Ensure that the size of buf is at least as large as specified by cnt to prevent overflow.
  • Writing Bytes: cnt is the number of bytes you want to write. The return value is the actual number of bytes written, which might be less than cnt if there are fewer bytes available.
  • Signal Interruption: If a signal interrupts the write():
    • If no data is written, it returns -1 and sets an error code.
    • If some data is written before the interruption, it returns the number of bytes written before being interrupted.

Example of write() in C

// C program to illustrate  
// write system Call  
#include<stdio.h>  
#include <fcntl.h>  
main()  
{  
int sz;  
  
int fd = open("foo.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);  
if (fd < 0)  
{  
    perror("r1");  
    exit(1);  
}  
  
sz = write(fd, "hello skillvertex\n", strlen("hello skillvertex\n"));  
  
printf("called write(% d, \"hello skillvertex\\n\", %d)."
    " It returned %d\n", fd, strlen("hello skillvertex\n"), sz);  
  close(fd);  
}

Output

called write(3, "hello skillvertex\n", 12).  it returned 11

Hence, we can view the file foo.txt after running the code, you will get output a “hello skillvertex“. If foo.txt file already contains some content in it then the write a system call that can overwrite the content and all previous content will be deleted and only “hello skillvetex” content will have in the file.

Example: Print “hello world” from the program without using any printf function.

// C program to illustrate 
// I/O system Calls 
#include <fcntl.h> 
#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
  
int main(void) 
{ 
    int fd[2]; 
    char buf1[12] = "hello world"; 
    char buf2[12]; 
  
    // assume foobar.txt is already created 
    fd[0] = open("foobar.txt", O_RDWR); 
    fd[1] = open("foobar.txt", O_RDWR); 
  
    write(fd[0], buf1, strlen(buf1)); 
    write(1, buf2, read(fd[1], buf2, 12)); 
  
    close(fd[0]); 
    close(fd[1]); 
  
    return 0; 
}

Output

hello world

Whereas, buf1 array’s string  will print “hello world” is first written into stdin fd[0] then after that this string will write into stdin to buf2 array. After that write into buf2 array to the stdout and print output “hello world“.

FAQ- Input-output system calls in C | Create, Open, Close, Read, Write

Q1. How to create open close read and write files in C?

Ans. fopen() – It will create a new file or open a existing file.
fclose() – f close() will close a file.
getc() – It can reads a character from a file.
putc() – It will writes a character to a file.
fscanf() – It will reads a set of data from a file.
fprintf() – It will writes a set of data to a file.

Q2. What does write () do in C?

Ans. write() attempts to write a specified number of bytes from a buffer to a file associated with an open file descriptor.

Q3. What is input and output in C language?

Ans. In C, you can use input and output functions to work with strings. Two common functions are gets() for reading strings and puts() for writing strings in an unformatted way.

Hridhya Manoj

Hello, I’m Hridhya Manoj. I’m passionate about technology and its ever-evolving landscape. With a deep love for writing and a curious mind, I enjoy translating complex concepts into understandable, engaging content. Let’s explore the world of tech together

Leave a Comment