Skip to content

Instantly share code, notes, and snippets.

@lynnporu
Last active November 11, 2020 13:38
Show Gist options
  • Save lynnporu/0cb091a71a8e1574dcae3e39a3952b9a to your computer and use it in GitHub Desktop.
Save lynnporu/0cb091a71a8e1574dcae3e39a3952b9a to your computer and use it in GitHub Desktop.
Linux file mapping
/*
Does not supposed to be compiled as main.
Contains methods for dealing with Linux file mappings.
*/
#include "io.h"
extern int errno;
char IO_CUT_EOF = 1;
/*
* Read `stream` to `msg` and write bytes read to `size`.
* This function is kinda dirty, just delete it if you won't need
* any stdin reading. */
void readstream(char** msg, size_t* size, FILE* stream){
// one more bit for \0
char buffer[IO_MAX_FGETS_SIZE + 1];
*size = (size_t)0;
*msg = malloc(1024);
if(*msg == NULL){
EMERGENCY("Memory error")
exit(EXIT_FAILURE);
}
*msg[0] = '\0';
// Here we going to read IO_MAX_FGETS_SIZE to the buffer and copy it to the
// message.
while(fgets(buffer, IO_MAX_FGETS_SIZE, stream)){
char** old = msg;
// WARNING: this code suppose cut_eof only takes 0 or 1
*size += strlen(buffer) - IO_CUT_EOF;
*msg = realloc(*msg, sizeof(char) * *size);
if(*msg == NULL){
EMERGENCY("Cannot reallocate")
free(old);
exit(EXIT_FAILURE);
}
memcpy(*msg, buffer, sizeof(char) * *size);
}
}
/*
* Create mapping to given `dest` of the file with given `addr`.
* For common tasks use o_flags = O_RDONLY and map_flags = PROT_READ.
* Size of the fill will be written to `fsize`.
* If map_flags contains PROT_WRITE file will be truncated to
* `desired_length` size. */
void openfmap(
mapstream_t* dest, char* addr,
int o_flags, mode_t o_mode, int map_flags,
off_t desired_length
){
int handle;
struct stat filestat;
if((handle = open(addr, o_flags, o_mode)) < 0){
EMERGENCY("Cannot open '%s'", addr);
exit(EXIT_FAILURE);
}
if(map_flags & PROT_WRITE)
if(ftruncate(handle, desired_length) < 0){
EMERGENCY("Cannot resize '%s'", addr);
exit(EXIT_FAILURE);
}
fstat(handle, &filestat);
dest->fsize = filestat.st_size;
if(
(dest->map = mmap(
0, dest->fsize,
map_flags, MAP_SHARED,
handle, 0
)) == MAP_FAILED
){
EMERGENCY("Cannot map '%s'", addr);
exit(EXIT_FAILURE);
}
close(handle);
dest->cursor = 0;
}
/*Close file mappings but do not free *src. */
void closefmap(mapstream_t* src){
if(munmap(src->map, src->fsize) < 0){
EMERGENCY("Cannot unmap file at %p", src->map);
exit(EXIT_FAILURE);
}
}
#ifndef H_IO
#define H_IO
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#define IO_MAX_FGETS_SIZE 0xffff
// Prints text to the fout variable or stdout if
// print_to_file evaluates to 0.
#define IO_PRINT(format, ...) \
fprintf( \
print_to_file ? fout : stdout, \
format, __VA_ARGS__);
// If cut_eof == 1, the very last symbol of the message (EOF or \0) will
// be erased.
extern char IO_CUT_EOF;
extern int errno;
/*Print fail message with errno to stderr, can be
* used for debugging. */
#define EMERGENCY(msg, ...) \
fprintf( \
stderr, \
"FAIL: " msg "; errno: %d\n", \
__VA_ARGS__ __VA_OPT__(,) errno \
);
/*This structure was desired to handle file mapping. */
typedef struct {
// In my opinion, it is convenient to handle file mapping as uint8_t*,
// because it's just a set of 8-bit bytes after all. But you can change
// it to void* in case it's more preferable for you.
uint8_t* map;
// True length of the file.
off_t fsize;
// Current cursor of reading/writing process. You're free to change this
// value.
off_t cursor;
// This variable may be used in algorithms that calculates new length of the
// file only once and want it to be stored somewhere globally (like MD5 or
// RC5).
off_t sizeslot1;
} mapstream_t;
// See for function description in io.c file.
void openfmap(
mapstream_t* dest, char* addr,
int o_flags, mode_t o_mode, int map_flags,
off_t desired_length
);
void closefmap(mapstream_t* src);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment