C:Workshop:2018:D1

De wiki-prog
Aller à : navigation, rechercher


Introduction

The purpose of this session is to practice on basic I/O.

Low-level file I/O

Basics

This part is just there to test basic operations on file.

You'll need the following operations (check man pages)

  • open(2)
  • stat(2)
  • read(2)
  • write(2)
  • lseek(2)

For these exercises, you must not use functions from stdio.h.

  • Write a Hello world program whose output is in a file.
  • Write a program that take a file name on the command line and prints its size
  • Write a program that take a file name and a position on the command line and print the single byte at that position in the file.

All errors should be managed using the command err(3).

mygetline

Take a look at the manual page of getline(3).

  • Your goal is to write, using only read(2), the following function:
size_t mygetline(int fd, char **line);

mygetline(fd, &line) will read from the file descriptor fd the next line (until the next '\n' or the end of the file.) The function will allocate using malloc (or similar) a pointer and put it into line, the function returns the size of the allocated area.)


The cat(1) Program

The purpose of this exercise is to simulate the cat(1) program. We'll start with a generic cat function that reads from a file descriptor and write the content on a second file descriptor.

  • Write the following function:
void cat(int fdin, int fdout);

The cat function reads bytes from fdin to fdout until it reaches the end of the file. In case of error while reading or writting, the function should ends, with a correct error message, the program using err(3).

  • Write the main program:

You should now write the main program. This program takes a file path as parameter, opens it for reading (using open_for_reading) and passes the file descriptor as the input file descriptor for your cat function, and passes STDOUT_FILENO as the output file descriptor.

  • Add the -E option

Read the manual page of cat(1), and add the option -E to your program.

  • Add the standard input as a possible input.

If there's no input file name, or if the input is -, use STDIN_FILENO as input.

Reading file content

The purpose of this exercise is to read integers from a file using functions from stdio.h, store them in an array, sort this array and print the result on the standard output, one number per line. The input file contains only a list of integer, one per line, like this one:

4
8
7
9
5
1
3
10
2
6

BMP file reading

Our purpose now is to read the content of a BMP file, using mmap(2). First, we need to build structures to handle the BMP headers. We'll limit our code on the most common BMP format (there're 7 variations of the second header, you can change the color depth, add compression … )

Here is our data structures for the two header of the BMP format:

struct bmp_img_head {
  unsigned int          header_size;
  unsigned int          width;
  unsigned int          height;
  short int             planes;
  short int             bit;
  unsigned int          comp_method;
  unsigned int          image_size;
  int                   hres;
  int                   vres;
  unsigned int          color_number;
  unsigned int          important_color;
};
 
struct bmp_header {
  short                 padding;   // trick to align header
  char                  magic[2];
  unsigned int          file_size;
  unsigned int          reserved;
  unsigned int          offset;
  struct bmp_img_head   dib;
  unsigned char         data[4];   // entry point for data
};

Your goal is to:

  • Check the file size using stat(2) (read the manual page carefully)
  • Open the file for reading and writing using open(2)
  • Map the file using mmap(2) (you'll need to write to the memory area)
  • Use the pointer returned by mmap(2) (read later for the padding trick)
  • Close the file descriptor using close(2)
  • Convert, in place, the image to grey (using the method already seen before)
  • Unmap the file using munmap(2)

There's few details you need to take care of:

  • When mapping the file, you should use the protection modes PROT_READ and PROT_WRITE and the flag MAP_SHARED in order to be able to modify the file.
  • The BMP header was design in 16bits world, thus the header is not correctly aligned. One solution is to pad the structure with 2 bytes at the beginning. Once you get the pointer from mmap(2), call it p, you should use the address (struct bmp_header*)((char*)p - 2) as the pointer to your structure.
  • You're goal is to override the content of the file, so take care to work on a copy of your BMP file to be able to restore it each time you're screwing it.
  • To access pixel, it's pretty easy: the data are made of groups of 3 bytes (one per color) representing the pixels, lines after lines. If the length of the line (in bytes) is not a multiple of 4, there will be some 0 at the end of the current line, before the beginning of the next one.