How to map an empty file using mmap - c

I am trying to create an empty file if it does not exists. And than map it using mmap() so, that i can pass it to my other program for writing. I am not sure which arguments for mmap are suitable for an empty file. My code works for non empty files but gives error "Invalid argument" if file is empty
Code program1 (only creates an empty file if not exists)
int i;
int fd = open("/home/sungmin/dummy_programs/dummy.txt", O_RDONLY | O_CREAT, 0777);
char *pmap;
pid_t child;
if (fd == -1)
{
perror("Error opening file for writing");
exit(EXIT_FAILURE);
}
struct stat fileInfo = {0};
if (fstat(fd, &fileInfo) == -1)
{
perror("Error getting the file size");
exit(EXIT_FAILURE);
}
/*if (fileInfo.st_size == 0)
{
fprintf(stderr, "Error: File is empty, nothing to do\n");
exit(EXIT_FAILURE);
}*/
pmap = mmap(0, fileInfo.st_size, PROT_READ | PROT_EXEC , MAP_ANONYMOUS, fd, 0);
if (pmap == MAP_FAILED)
{
close(fd);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
/* Calling fork function */
if((child=fork())==0){
printf("Iam Child process\n\n");
static char *argv[]={"This is some sample text. I need to write this text in my dummy file.","/home/sungmin/dummy_programs/dummy.txt",NULL};
execv("/home/sungmin/dummy_programs/pro2",argv);
exit(127);
}
else {
printf("Iam parent, waiting for child process to exit\n\n");
waitpid(child,0,0);
printf("Existing parent\n\n");
}
/* Don't forget to free the mmapped memory*/
if (munmap(pmap, fileInfo.st_size) == -1)
{
close(fd);
perror("Error un-mmapping the file");
exit(EXIT_FAILURE);
}
/* Un-mmaping doesn't close the file, so we still need to do that.*/
close(fd);
Code program2 (opens same file as program1 and writes text passed by program1)
size_t i;
int fd;
char *pmap;
pid_t child;
struct stat fileInfo = {0};
const char *text = argv[0];
fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600);
if (fd == -1)
{
perror("Error opening file for writing");
exit(EXIT_FAILURE);
}
size_t textsize = strlen(text) + 1; // + \0 null character
if (lseek(fd, textsize-1, SEEK_SET) == -1)
{
close(fd);
perror("Error calling lseek() to 'stretch' the file");
exit(EXIT_FAILURE);
}
if (write(fd, "", 1) == -1)
{
close(fd);
perror("Error writing last byte of the file");
exit(EXIT_FAILURE);
}
pmap = mmap(0, textsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (pmap == MAP_FAILED)
{
close(fd);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
/* Writting users text to file */
for (i = 0; i < textsize; i++)
{
pmap[i] = text[i];
}
// Write it now to disk
if (msync(pmap, textsize, MS_SYNC) == -1)
{
perror("Could not sync the file to disk");
}
/* Don't forget to free the mmapped memory*/
if (munmap(pmap, textsize) == -1)
{
close(fd);
perror("Error un-mmapping the file");
exit(EXIT_FAILURE);
}
/* Un-mmaping doesn't close the file, so we still need to do that.*/
close(fd);

You need to use truncate to extend the file length after creating it before mapping it.
Yes, the function name sounds wrong, but truncate can actually set the file length to any number. Be sure to use a multiple of 4K for best results.
Then, if you want to keep the mapping open to see data between Program 1 and 2, you need to get rid of ANONYMOUS and map with MAP_SHARED in Program 1. A mapping that isn't shared will not show changes made by other programs. Or it might, if it has to reload from disk. It's weird, don't mix SHARED and not-SHARED mappings.
Once you've changed Program 1 to use truncate, take that lseek and write code out of Program 2. The file will already have been created and extended by Program 1.

Related

Pipe does not give the same result every time in C

I am trying to read a file by the parent process, send the content to two child processes and child processes write content to a shared memory segment. However, at each run, I get different outputs and I cannot figure out why.
I use two named pipes and after writing to shared memory, the parent process opens the shared memory and reads the content of each memory.
The first child writes to memory as it gets but the second child converts to hexadecimal.
Here is my main function; assume that stringtohex() works correctly.
int main()
{
pid_t pid_1, pid_2;
int fd, sd; // pipes
const int SIZE = 4096;
const char infile[] = "in.txt";
FILE *tp; // file pointers
pid_1 = fork();
if (pid_1 < 0)
{
fprintf(stderr, "Fork 1 failed");
return(1);
}
if (pid_1 > 0)
{
pid_2 = fork();
if (pid_2 < 0)
{
fprintf(stderr, "Fork 2 failed");
return(1);
}
if (pid_2 > 0) // parent
{
tp = fopen(infile, "r");
if (tp == 0)
{
fprintf(stderr, "Failed to open %s for reading", infile);
return(1);
}
mknod(PIPE_NAME_1, S_IFIFO | 0666, 0);
mknod(PIPE_NAME_2, S_IFIFO | 0666, 0);
fd = open(PIPE_NAME_1, O_WRONLY);
sd = open(PIPE_NAME_2, O_WRONLY);
if (fd > 0 && sd > 0)
{
char line[300];
while (fgets(line, sizeof(line), tp))
{
int len = strlen(line);
int num_1 = write(fd, line, len);
int num_2 = write(sd, line, len);
if (num_1 != len || num_2 != len)
perror("write");
else
printf("Ch 1: wrote %d bytes\n", num_1);
printf("Ch 2: wrote %d bytes\n", num_2);
}
close(fd);
close(sd);
}
fclose(tp);
wait(NULL);
int shm_fd = shm_open("Ch_1", O_RDONLY, 0666);
if (shm_fd == -1)
{
fprintf(stderr, "Failed: Shared Memory 1");
exit(-1);
}
int shm_sd = shm_open("Ch_2", O_RDONLY, 0666);
if (shm_sd == -1)
{
fprintf(stderr, "Failed: Shared Memory 2");
exit(-1);
}
void *ptr = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED)
{
printf("Map failed 1\n");
return -1;
}
void *ptr2 = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_sd, 0);
if (ptr2 == MAP_FAILED)
{
printf("Map failed 2\n");
return -1;
}
fprintf(stdout, "Normal input: \n%s\n", ptr);
fprintf(stderr, "Hexadecimal: \n%s\n", ptr2);
}
else // second child
{
// open shared memory segment
int shm_child_2 = shm_open("Ch_2", O_CREAT | O_RDWR, 0666);
// configure the size of the shared memory segment
ftruncate(shm_child_2, SIZE);
// map the pointer to the segment
void *ptr_child_2 = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_child_2, 0);
if (ptr_child_2 == MAP_FAILED)
{
printf("Map failed 3\n");
return -1;
}
// configure named pipe
mknod(PIPE_NAME_2, S_IFIFO | 0666, 0);
sd = open(PIPE_NAME_2, O_RDONLY);
if (sd > 0) // reading from pipe
{
int num;
char s[300];
while ((num = read(sd, s, sizeof(s))) > 0)
{
// convert to hexadecimal
char hex[strlen(s) * 2 + 1];
stringtohex(s, hex);
// write into segment
sprintf(ptr_child_2, "%s", hex);
ptr_child_2 += strlen(s) * 2;
}
close(sd);
}
exit(0);
}
}
else // first child
{
// create shared memory segment
int shm_child_1 = shm_open("Ch_1", O_CREAT | O_RDWR, 0666);
// configure the size of the shared memory segment
ftruncate(shm_child_1, SIZE);
// map the pointer to the segment
void *ptr_child_1 = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_child_1, 0);
if (ptr_child_1 == MAP_FAILED)
{
printf("Map failed 4\n");
return -1;
}
// configure named pipe
mknod(PIPE_NAME_1, S_IFIFO | 0666, 0);
fd = open(PIPE_NAME_1, O_RDONLY);
if (fd > 0) // reading from pipe
{
int num;
char s[300];
while ((num = read(fd, s, strlen(s))) > 0)
{
// write into segment
sprintf(ptr_child_1, "%s", s);
ptr_child_1 += strlen(s);
}
close(fd);
}
exit(0);
}
return 0;
}
For example input file has:
Harun
sasmaz
59900
1234
Aaaa
Results are:
Normal input:
HARUN
sasmaz
59900
1234
Aaaa4
Hexadecimal:
484152554E0A7361736D617A0A35393930300A313233340A41616161
or
Normal input:
HARUN
sasmaz
asmaz59900
1234
Aaaa
Hexadecimal:
484152554E0A7361736D617A0A35393930300A0A313233340A41616161FF03

How to detect which piece of my code is generating "Fatal error: glibc detected an invalid stdio handle" error?

I'm trying to code a simple program to copy a file into another using 2 processes.
I want to use shared memory to open both files and get a piece of shared memory of 1Byte to be used as exchange memory in a mutually exclusive way.
So the main process should open both files and put them in shared memories;
fork twice, I obtain 2 processes A and B.
Process A should read 1 byte of the first file, put it in the shared exchange memory and unlock the mutex for process B.
Process B should copy the file from the shared exchange memory and put it in its file and unlock the mutex for process A.
And so on.
#define SIZE 4096
void reader_process(FILE* fptr,char*exch, sem_t*mut){
while(1){
sem_wait(mut);
*exch = (char) getc(fptr);
sem_post(mut+1);
}
}
void writer_process(FILE* fptr,char*exch, sem_t*mut){
if(*exch == EOF){
printf("done\n");
exit(0);
}
while(1){
sem_wait(mut);
putc((int)*exch,fptr);
sem_post(mut-1);
}
}
int main(int argc, char *argv[]){
FILE* shared_f_ptr[2];
pid_t pid;
//2 files name.
char *files[2];
int fd[2];
//open files.
files[0] = argv[1];
printf("%s\n",files[0]);
FILE* fpointer1 = fopen(files[0],"r+");
if (fpointer1 == NULL){
perror("fopen\n");
exit(-1);
}
fd[0] = fileno(fpointer1);
files[1] = argv[2];
printf("%s\n",files[1]);
FILE* fpointer2 = fopen(files[1],"r+");
if (fpointer2 == NULL){
perror("fopen\n");
exit(-1);
}
fd[1] = fileno(fpointer2);
//shared File pointers.
shared_f_ptr[0] = (FILE*)mmap(NULL, SIZE*sizeof(char),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
fd[0], 0);
if (shared_f_ptr[0] == MAP_FAILED){
perror("mmap\n");
exit(-1);
}
shared_f_ptr[1] = (FILE*)mmap(NULL, SIZE*sizeof(char),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
fd[1], 0);
if (shared_f_ptr[1] == MAP_FAILED){
perror("mmap\n");
exit(-1);
}
//shared mem for 1B exchange.
char *shared_exchange = (char*)mmap(NULL, sizeof(char),
PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS,
-1, 0);
if (shared_exchange == MAP_FAILED){
perror("mmap\n");
exit(-1);
}
//mutex.
sem_t *mut = (sem_t*)mmap(NULL, 2*sizeof(sem_t),
PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS,
-1, 0);
sem_init(&mut[0],1,0);
sem_init(&mut[1],1,0);
//fork.
pid = fork();
if (pid == 0) {
reader_process(shared_f_ptr[0],
shared_exchange, &mut[0]);
}
if (pid == -1){
perror("fork\n");
exit(-1);
}
else pid = fork();
if (pid == 0) writer_process(shared_f_ptr[1],
shared_exchange, &mut[1]);
if (pid == -1){
perror("fork\n");
exit(-1);
}
else{
sem_post(&mut[0]);
}
}
I don't expect the error i am getting Fatal error: glibc detected an invalid stdio handle but i don't really know how to find what's causing the problem.
Don't do this:
//shared File pointers.
shared_f_ptr[0] = (FILE*)mmap(NULL, SIZE*sizeof(char),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
fd[0], 0);
if (shared_f_ptr[0] == MAP_FAILED){
perror("mmap\n");
exit(-1);
}
shared_f_ptr[1] = (FILE*)mmap(NULL, SIZE*sizeof(char),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
fd[1], 0);
if (shared_f_ptr[1] == MAP_FAILED){
perror("mmap\n");
exit(-1);
}
Use this instead:
shared_f_ptr[0] = fpointer1;
shared_f_ptr[1] = fpointer2;
Don't use the file descriptors underlying each FILE. Instead, simply use the FILE itself.
Also, instead of using fpointer1 and fpointer2, just use shared_f_ptr[0] and shared_f_ptr[1].
This is a possible definition of the FILE structure:
typedef struct _IO_FILE
{
int __fd;
int __flags;
int __unget;
char *__buffer;
struct {
size_t __orig;
size_t __size;
size_t __written;
} __bufsiz;
fpos_t __fpos;
} FILE;
As you can see, it's a structure, not just a flat pointer.

c - can't read pointers from struct using mmap

I'm trying to store a graph on file using mmap so i read and write more quickly but i can't read fields struct fields that are created using malloc (and i can't make them an array)
the problem is i can't read back the filed map[i].nodes->vertexKey from the file
(i think because is because it was created using malloc)
my code is :
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#define COUNT 10
#define FILESIZE ( COUNT * sizeof(struct vertex))
struct node{
int vertexKey ;
struct node *nextNode;
};
struct vertex {
int vertexKey;
struct node *nodes;
};
int readMmap(){
const char *filepath = "/tmp/mmapped.bin";
int fd = open(filepath, O_RDWR , (mode_t)0600);
if (fd == -1)
{
perror("Error opening file for writing");
exit(EXIT_FAILURE);
}
struct stat fileInfo = {0};
if (fstat(fd, &fileInfo) == -1)
{
perror("Error getting the file size");
exit(EXIT_FAILURE);
}
if (fileInfo.st_size == 0)
{
fprintf(stderr, "Error: File is empty, nothing to do\n");
exit(EXIT_FAILURE);
}
printf("File size is %ji\n", (intmax_t)fileInfo.st_size);
struct vertex *map = mmap(0, FILESIZE , PROT_READ, MAP_SHARED, fd, 0);
if (map == MAP_FAILED)
{
close(fd);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
for (off_t i = 0; i < COUNT; i++)
{
printf("%d |", map[i].vertexKey );
// i can't read map[i].nodes->vertexKey
printf("%d \n", map[i].nodes->vertexKey );
printf("\n" );
}
// Don't forget to free the mmapped memory
if (munmap(map, fileInfo.st_size) == -1)
{
close(fd);
perror("Error un-mmapping the file");
exit(EXIT_FAILURE);
}
// Un-mmaping doesn't close the file, so we still need to do that.
close(fd);
return 0;
}
int writeMmap(){
const char *filepath = "/tmp/mmapped.bin";
int fd = open(filepath, O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600);
if (fd == -1){
perror("Error opening file for writing");
exit(EXIT_FAILURE);
}
if (lseek(fd, FILESIZE-1, SEEK_SET) == -1){
close(fd);
perror("Error calling lseek() to 'stretch' the file");
exit(EXIT_FAILURE);
}
if (write(fd, "", 1) == -1){
close(fd);
perror("Error writing last byte of the file");
exit(EXIT_FAILURE);
}
struct vertex *map = mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
close(fd);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < COUNT; i++){
struct vertex ss ;
ss.vertexKey=i;
struct node *n1 = (struct node*)malloc(sizeof(struct node));
n1->nextNode =NULL ;
n1->vertexKey=i*10 ;
ss.nodes = n1 ;
map[i] = ss;
}
// Write it now to disk
if (msync(map, 100, MS_SYNC) == -1)
{
perror("Could not sync the file to disk");
}
// Don't forget to free the mmapped memory
if (munmap(map, 100) == -1)
{
close(fd);
perror("Error un-mmapping the file");
exit(EXIT_FAILURE);
}
// Un-mmaping doesn't close the file, so we still need to do that.
close(fd);
return 0;
}
How fast does this really need to be? Using a memory image for your persistent format is a problematic practice -- you need it to be a pretty big win in the larger scheme of things for it to be worthwhile, if it is even possible at all.
If you want a persistent representation of your data, then that representation needs to be self-contained. Pointers per se cannot be supported, but in their place you can use indexes into tables (effectively arrays) of objects. Better would be if indexing were implicit, but that may not be sufficient for you. I apologize for being vague, but I'd need to understand the characteristics of your data much better before I could suggest any specifics.

Why does mmap() fail with permission denied for the destination file of a file copy program?

I'd like to give a try at copying the contents of a file over to another one by using memory mapped I/O in Linux via mmap(). The intention is to check by myself if that's better than using fread() and fwrite() and how would it deal with big files (like couple of GiBs for example, since the file is read whole I want to know if I need to have such amount of memory for it).
This is the code I'm working with right now:
// Open original file descriptor:
int orig_fd = open(argv[1], O_RDONLY);
// Check if it was really opened:
if (orig_fd == -1) {
fprintf(stderr, "ERROR: File %s couldn't be opened:\n", argv[1]);
fprintf(stderr, "%d - %s\n", errno, strerror(errno));
exit(EX_NOINPUT);
}
// Idem for the destination file:
int dest_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
// Check if it was really opened:
if (dest_fd == -1) {
fprintf(stderr, "ERROR: File %s couldn't be opened:\n", argv[2]);
fprintf(stderr, "%d - %s\n", errno, strerror(errno));
// Close original file descriptor too:
close(orig_fd);
exit(EX_CANTCREAT);
}
// Acquire file size:
struct stat info = {0};
if (fstat(orig_fd, &info)) {
fprintf(stderr, "ERROR: Couldn't get info on %s:\n", argv[1]);
fprintf(stderr, "%d - %s\n", errno, strerror(errno));
// Close file descriptors:
close(orig_fd);
close(dest_fd);
exit(EX_IOERR);
}
// Set destination file size:
if (ftruncate(dest_fd, info.st_size)) {
fprintf(stderr, "ERROR: Unable to set %s file size:\n", argv[2]);
fprintf(stderr, "%d - %s\n", errno, strerror(errno));
// Close file descriptors:
close(orig_fd);
close(dest_fd);
exit(EX_IOERR);
}
// Map original file and close its descriptor:
char *orig = mmap(NULL, info.st_size, PROT_READ, MAP_PRIVATE, orig_fd, 0);
if (orig == MAP_FAILED) {
fprintf(stderr, "ERROR: Mapping of %s failed:\n", argv[1]);
fprintf(stderr, "%d - %s\n", errno, strerror(errno));
// Close file descriptors:
close(orig_fd);
close(dest_fd);
exit(EX_IOERR);
}
close(orig_fd);
// Map destination file and close its descriptor:
char *dest = mmap(NULL, info.st_size, PROT_WRITE, MAP_SHARED, dest_fd, 0);
if (dest == MAP_FAILED) {
fprintf(stderr, "ERROR: Mapping of %s failed:\n", argv[2]);
fprintf(stderr, "%d - %s\n", errno, strerror(errno));
// Close file descriptors and unmap first file:
munmap(orig, info.st_size);
close(dest_fd);
exit(EX_IOERR);
}
close(dest_fd);
// Copy file contents:
int i = info.st_size;
char *read_ptr = orig, *write_ptr = dest;
while (--i) {
*write_ptr++ = *read_ptr++;
}
// Unmap files:
munmap(orig, info.st_size);
munmap(dest, info.st_size);
I think it may be a way of doing it but I keep getting an error trying to map the destination file, concretely code 13 (permission denied).
I don't have a clue on why is it failing, I can write to that file since the file gets created and all and the file I'm trying to copy is just a couple of KiBs in size.
Can anybody spot the problem? How come I had permission to map the original file but not the destination one?
NOTE: If anyone is to use the loop to copy bytes posted in the question instead of memcpy for example, the loop condition should be i-- instead to copy all contents. Thanks to jxh for spotting that.
From the mmap() man page:
EACCES A file descriptor refers to a non-regular file. Or MAP_PRIVATE
was requested, but fd is not open for reading. Or MAP_SHARED
was requested and PROT_WRITE is set, but fd is not open in
read/write (O_RDWR) mode. Or PROT_WRITE is set, but the file is
append-only.
You are opening your destination file with O_WRONLY. Use O_RDWR instead.
Also, you should use memcpy to copy the memory rather than using your own loop:
memcpy(dest, orig, info.st_size);
Your loop has an off by 1 bug.
This works for me. Note that I had to open the destination O_RDWR. I suspect the kernel attempts to map whole pages from the file into memory (reading it) because you're updating it a byte or word at a time, and that might not change the whole page.
A couple of other points:
You don't need to close and unmap stuff on error if you're just going to exit.
Use memcpy and don't write your own byte-copying loop. Memcpy will be a lot better optimised in general. (Though it's not always the absolute best.)
You might want to read the source code to FreeBSD's "cp" utility. Take a look here and search for the use of mmap. http://svnweb.freebsd.org/base/stable/9/bin/cp/utils.c?revision=225736&view=markup
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
int s, d;
struct stat st;
void *sp, *dp;
s = open(argv[1], O_RDONLY);
if (s == -1) {
perror("open source");
exit(1);
}
d = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644);
if (d == -1) {
perror("open destintation");
exit(1);
}
if (fstat(s, &st)) {
perror("stat source");
exit(1);
}
if (ftruncate(d, st.st_size)) {
perror("truncate destination");
exit(1);
}
sp = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, s, 0);
if (sp == MAP_FAILED) {
perror("map source");
exit(1);
}
dp = mmap(NULL, st.st_size, PROT_WRITE | PROT_READ, MAP_SHARED, d, 0);
if (dp == MAP_FAILED) {
perror("map destintation");
exit(1);
}
memcpy(dp, sp, st.st_size);
return 0;
}
Original File: O_RDONLY open, MAP_PRIVATE mmap
destination file: O_WRONLY open, MAP_SHARED mmap
You need to open with O_RDWR flag for using MAP_SHARED.
Don't you actually need to do MAP_FILE | MAP_SHARED ?

How to rewrite full content of a file in C

I have text file which uses for ajax source. Every 1 sec browser sends ajax request to read actual data from this file.
Also I have deamon written on C which writes actual data to that file. Look at the following code:
static void writeToFile_withLock(const char * file_path, const char * str)
{
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0 };
int fd;
const char * begin = str;
const char * const end = begin + strlen(str);
fl.l_pid = getpid();
if ((fd = open(file_path, O_CREAT | O_WRONLY)) == -1) {
perror("open");
exit(1);
}
printf("Trying to get lock...\n");
if (fcntl(fd, F_SETLKW, &fl) == -1) {
perror("fcntl");
exit(1);
}
printf("got lock\n");
printf("Try to write %s\n", str);
while (begin < end)
{
size_t remaining = end - begin;
ssize_t res = write(fd, begin, remaining);
if (res >= 0)
{
begin += res;
continue; // Let's send the remaining part of this message
}
if (EINTR == errno)
{
continue; // It's just a signal, try again
}
// It's a real error
perror("Write to file");
break;
}
fl.l_type = F_UNLCK; /* set to unlock same region */
if (fcntl(fd, F_SETLK, &fl) == -1) {
perror("fcntl");
exit(1);
}
printf("Unlocked.\n");
close(fd);
}
The problem: If former data was > the new data then old several symbols keeped at the end of the file.
How I can rewrite full file content?
Thanks in advance.
Add O_TRUNC to the open() call...
O_TRUNC
If the file already exists and is a regular file and the open mode
allows writing (i.e., is O_RDWR or O_WRONLY) it will be truncated to
length 0. If the file is a FIFO or terminal device file, the O_TRUNC
flag is ignored. Otherwise the effect of O_TRUNC is unspecified.
You basically have two options. Either set the O_TRUNC bit of the 2nd parameter of open to discard all content when you open the file, or call ftruncate when you are finished to discard the content of the file that you do not want. (Or use truncate, but since you already have an open file descriptor, there's no advantage to doing that.)

Resources