How to write file at specific position? - c

I made a function in C to create a file using Unix command dd:
dd if=/dev/zero of=file.data bs=8 count=32
This works and created file.data with size 256 bytes and if I open the file I can see it's empty.
Now I want to write to a specific position in this file using fseek and fwrite, but whenever I try to write to a position different from 0, it does nothing.
For example, If I want to write to position 2, I must also write to position 0 and 1.
void createFile() {
char command[100];
sprintf(comando, "dd if=/dev/zero of=file.data bs=8 count=32");
system(command);
}
void writeFile(int position, char * data) {
FILE * file = fopen("file.data", "r+");
fseek(file, position, SEEK_SET);
fwrite(data, strlen(data), 1, file);
fclose(file);
}
Some examples
Input:
writeFile(0, "0");
writeFile(1, "1");
writeFile(2, "2");
output > 012
Input:
writeFile(2, "2");
writeFile(1, "1");
writeFile(0, "0");
output > 012
Input:
writeFile(1, "1");
writeFile(2, "2");
output > empty
Is there some way to write into the file without having to write into the previous positions also?

You don't have to do anything special. Your code works, as long as you know how to demonstrate that it works. Here's a mildly extended version of it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void createFile(void)
{
char command[100];
sprintf(command, "dd if=/dev/zero of=file.data bs=8 count=32"); // Typo fixed!
system(command);
}
static void writeFile(int position, char *data)
{
FILE *file = fopen("file.data", "r+");
fseek(file, position, SEEK_SET);
fwrite(data, strlen(data), 1, file);
fclose(file);
}
int main(void)
{
createFile();
system("odx file.data");
writeFile(2, "012");
system("odx file.data");
return 0;
}
The odx command is a hex dump program; you could use od -c or xxd -g1 instead.
The sample output is:
32+0 records in
32+0 records out
256 bytes transferred in 0.000109 secs (2349544 bytes/sec)
0x0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
* (15)
0x0100:
0x0000: 00 00 30 31 32 00 00 00 00 00 00 00 00 00 00 00 ..012...........
0x0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
* (14)
0x0100:
The first three lines are from dd. I'm not convinced that using dd is necessary, but it does no great harm. The next three lines indicate that the first 16 bytes in the file are all zero bytes, and that this pattern repeats for 15 more lines, and then you reach EOF at offset 0x100 (25610). The next four lines show that there are 2 null bytes, then the three digits 012, then all null bytes to the end of file.

Related

I'm losing binary data when using fseek in c

I wrote a function that is responsible for moving to a binary file and editing its bytes
int replace(FILE *binaryFile, long offset, unsigned char *replaced, int length) {
if (binaryFile != NULL) {
for (int i = 0; i < length; i++) {
fseek(binaryFile, offset + i, SEEK_SET);
fwrite(&replaced[i], sizeof(*replaced), 1, binaryFile);
}
fclose(binaryFile);
return 0;
}
else return -1;
}
When I use this function, I encounter a strange problem
All data in the file is filled with NULL bytes
And only one of the addresses in the file changes
Example:
FILE* fp = fopen("target.bin", "wb");
replace(fp, 0x57d8b0, "\x1E\xFF\x2F\xE1", 4);
replace(fp, 0x57c770, "\x01\x00\xA0\xE3\x1E\xFF\x2F\xE1", 8);
Result:
0x57c770: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
...
0x57d8a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x57d8b0: 1e ff 2f e1
Correct result:
0x57c770: 01 00 A0 E3 1E FF 2F E1 ...
...
0x57d8a0: 9c c4 0a ea 70 d2 68 00 44 d4 68 00 10 d1 68 00
0x57d8b0: 1e ff 2f e1 18 b0 8d e2 02 8b 2d ed 18 d0 4d e2
Please help me to solve the function problem or other problems.
wb is not correct. It clobbers the file.
From here,
Mode
Meaning
Explanation
If already exists
If does not exist
"r"
read
Open a file for reading
read from start
failure to open
"w"
write
Create a file for writing
destroy contents
create new
"a"
append
Append to a file
write to end
create new
"r+"
read extended
Open a file for read/write
read from start
error
"w+"
write extended
Create a file for read/write
destroy contents
create new
"a+"
append extended
Open a file for read/write
write to end
create new
You want r+b.
Also, you close the file handle in replace, which is premature. This should be done outside of replace, after you're done with the handle.
As an aside, you shouldn't be doing a number of seeks and writes of length one equal to length; you should be doing one seek and one write of length length.

Lock a certain range in a file using `fcntl` and `F_OFD_SETLK`

Objective
I want to open a file multiple times, but each fd should be only allowed to write to a specific range.
Background
I have an EEPROM which contains multiple "partitions", where each partition holds different information.
I want to avoid that one partition overflows to a different one, or one partition can read other information and misinterpret them.
My Problem
I wanted to use fcntl along with F_OFD_SETLK so that I can lock a specific range on each opened fd.
Locking works as intended and trying to lock an already locked range will result in EAGAIN, which is expected.
What is not so obvious for me is, that I can write to a range that is locked by a different fd.
Question
Is it possible to lock a certain range in a file so that it is not writeable by a different opened fd?
If not, is there a different way to achieve my goal?
Code:
Link to onlinegdb: https://onlinegdb.com/ewE767rbu
#define _GNU_SOURCE 1
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void ex(const char *what)
{
perror(what);
exit(1);
}
static void lock_range(int fd, off_t start, off_t len)
{
struct flock ff = {
.l_type = F_WRLCK,
.l_whence = SEEK_SET,
.l_start = start,
.l_len = len,
};
if (fcntl(fd, F_OFD_SETLK, &ff) < 0)
perror("fcntl");
}
static void write_at(int fd, const char *str, off_t offset)
{
if (pwrite(fd, str, strlen(str), offset) < 0)
perror("pwrite");
}
int main()
{
int firstfd = open("/tmp/abc.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
if (firstfd < 0)
ex("open");
if (ftruncate(firstfd, 0x1000) < 0)
ex("ftruncate");
lock_range(firstfd, 0, 0x800);
lock_range(firstfd, 0, 0x800); // check if I can aquire the lock multiple times
int secondfd = open("/tmp/abc.txt", O_RDWR);
if (secondfd < 0)
ex("open");
lock_range(secondfd, 0, 0x800); // this one fails on purpose
lock_range(secondfd, 0x800, 0);
lock_range(firstfd, 0x801, 1); // and this one fails on purpose
write_at(firstfd, "hallo", 0);
write_at(firstfd, "hallo", 0x900); // this should fail, but doesn't
write_at(secondfd, "welt", 0); // this should fail, but doesn't
write_at(secondfd, "welt", 0x900);
close(firstfd);
close(secondfd);
system("hexdump -C /tmp/abc.txt"); // just for visualization
}
Output:
fcntl: Resource temporarily unavailable
fcntl: Resource temporarily unavailable
00000000 77 65 6c 74 6f 00 00 00 00 00 00 00 00 00 00 00 |welto...........|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000900 77 65 6c 74 6f 00 00 00 00 00 00 00 00 00 00 00 |welto...........|
00000910 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00001000
Please note welto which is hallo overriden by welt. I expected hallo at 0x0 and welt at 0x900.
Locks come in two flavours: mandatory locks, and advisory locks. These are advisory locks. This means they prevent others from obtaining a lock. Period. They don't prevent writes or any other form of modification.
If not, is there a different way to achieve my goal?
Don't ignore failures to obtain a lock.

Segmentation fault(core dumped ) error while reading a python generated binary array in C [duplicate]

This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed 3 years ago.
I am trying to load a 2D array created by numpy and read the elements in C, but I get Segmentation fault(core dumped ) error while running it. The code goes by the lines of
#include <stdio.h>
#include <string.h>
int main(){
char *file;
FILE *input;
int N1, N2, ii, jj;
float element;
strcpy(file, "/home/caesar/Desktop/test.bin");
input = fopen(file, "rb");
fread(&N1, sizeof(int), 1, input);
fread(&N2, sizeof(int), 1, input);
float memoryarray[N1][N2];
for(ii= 0; ii<N1; ii++){
for(jj=0; jj<N2; jj++){
fread(&element, sizeof(float), 1, input);
memoryarray[ii][jj]= element;
}
}
printf("%f", memoryarray[2][3]);
fclose(input);
return 0;
}
This is the starting for a task where I will have to read elements from matrices of the form 400*400*400 or so. The idea is to read all elements from the file and store it in memory and then read from memory index wise when necessary, for example, here i am trying to access and print the element in the second row third column.
P.S: I am quite new to pointers.
Dear all, I tried the methods you said., here is the modified version of the code, the segmentation fault error is gone but the output is either all zeros, or is just plain garbage values.
I ran the executable three times and the outputs I got were
Output1: -0.000000
Output 2: 0.000000
Output 3 : -97341413674450944.000000
My array contains integers btw
Here is the modified version of the code
#include <stdio.h>
#include <string.h>
void main(){
const char file[] ="/home/caesar/Desktop/test.bin";
FILE *input;
int N1, N2, ii, jj;
float element;
//strcpy(file, "/home/caesar/Desktop/test.bin");
input = fopen(file, "r");
fread(&N1, sizeof(int), 1, input);
fread(&N2, sizeof(int), 1, input);
float memoryarray[N1][N2];
for(ii= 0; ii<N1; ii++){
for(jj=0; jj<N2; jj++){
fread(&element, sizeof(float), 1, input);
memoryarray[ii][jj]= element;
}
}
printf("%f", memoryarray[1][2]);
fclose(input);
Also here is the hex dump of the file that i am trying to open. Some of you asked me to verify whether fopen() is working or not, i checked, it is working.
00000000 00 00 40 40 00 00 40 40 01 00 00 00 00 00 00 00 |..##..##........|
00000010 02 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 |................|
*
00000030 04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 |................|
00000040 05 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 |................|
00000050
So here is my problem in brief. I have multidimensional arrays of double precision floats written to a file using python. I want to take those files and access the elements whenever necessary by using the index of the elements to get the values. Any C code to do so would solve my problem.
Here is the python code i am using to write the file
with open('/home/caesar/Desktop/test.bin', 'wb') as myfile:
N= np.zeros(2, dtype= np.float32, order= "C")
N[0]= 3
N[1]= 3
a= [[1,2,3],[2,3,4], [4,5,6]]
N.astype(np.float32).tofile(myfile)
b= np.asarray(a)
b.tofile(myfile)
strcpy(file, "/home/caesar/Desktop/test.bin");
This writes to a garbage memory address.
You should either declare file as an array of suitable size, like this:
char file[100];
or
initialize the char pointer directly with the path like this (and get rid of the strcpy):
const char *file = "/home/caesar/Desktop/test.bin";
or the best, as per common consensus (refer comments):
fopen("/home/caesar/Desktop/test.bin", "rb");

fwrite in binary mode of ints not writing proper number of bytes

I am not able to understand the fread fwrite behavior of the following code snippet, exemplified by the code is straightforward:
#include <stdio.h>
int main(void)
{
FILE *fp;
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int temp[100] = {0};
int i;
fp = fopen("testdata.bin","wb");
if( fp!= NULL ) {
fwrite( arr,sizeof(int), 10, fp);
fclose(fp);
}
fp = fopen("testdata.bin","rb");
if( fp!= NULL ) {
fread( temp,sizeof(int), 10, fp);
fclose(fp);
}
for(i=0;i<100;i++)
printf("%#x,",temp[i]);
printf("\b \n");
return 0;
}
The output on stdout is:
0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
which makes sense. However, when I open the testdata.bin file, I see only two bytes for value (int) where I expect 4 bytes as size of int is 4 on my machine.
Here is the content of testdata.bin:
0x00000001: 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00
0x00000010: 09 00 0a 00
I would have expected
0x00000001: 01 00 00 00 02 00 00 00 03 00 00 00 ...
Any ideas?
I think fwrite is working fine. Change the declaration of temp so the type is an array of one-byte unsigned characters:
unsigned char temp [100] = {0} ;
The current version of the code displays a four-byte integer each time in the print statement. This will confirm that the contents of the file are as you expect. On my machine:
0x1,0,0,0,0x2,0,0,0,0x3,0,0,0,0x4,0,0,0,0x5,0,0,0,0x6,0,0,0,0x7,0,0,0,0x8,0,0,0,0x9,0,0,0,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

Strange 0x0D being added to my binary file

I have this strange problem:
I write 16 chars to a binary file and then I write 3 integers but when I open my file with some binary file viewer, I see an extra byte is added (which equals 0x0D).
Here's my code:
for(i = 0; i < 16; i++)
{
if(i < strlen(inputStr))
{
myCharBuf[0] = inputStr[i];
}
else
{
myCharBuf[0] = 0;
}
fwrite(myCharBuf, sizeof(char), 1, myFile);
}
myIntBuf[0] = inputNumber1;
fwrite(myIntBuf, sizeof(int), 1 ,myFile);
myIntBuf[0] = inputNumber2;
fwrite(myIntBuf, sizeof(int), 1 ,myFile);
myIntBuf[0] = inputNumber3;
fwrite(myIntBuf, sizeof(int), 1 ,myFile);
I get the following byte-values:
61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0D 0A 00 00 00 05 00 00 00 08 00 00 00
When I expect:
61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0A 00 00 00 05 00 00 00 08 00 00 00
Does anyone have an idea why it might happen?
0A is the line feed character and 0D is the carriage return. These are usually associated with text mode.
Have you opened the file in binary mode? (e.g. fopen("foo.txt", "wb"))
When you open the file, open for writing as binary "wb":
fopen(filename, "wb");
When you open in text mode, translation of Line Feeds (0A) and Carriage Returns (0D) occurs.
fopen the file in binary mode with "wb".
fopen(filename, "wb");
otherwise, the code in the library will do automatic line end translation (on windows you are on Windows, are you not? that means translate '\n' to '\r' '\n').
I believe that your inputStr variable contains a newline character and it is written to the binary file as carriage return and linefeed - binary '0D' followed by '0A'.
For eg, the following program writes 16 characters and 3 numbers as follows.
FILE *fp;
fp = fopen("sample.bin", "wb+");
if(fp == NULL)
{
printf("Cannot create a file\n");
return;
}
int i;
char c[1] = {'A'};
for(i = 0; i < 16; i++)
{
fwrite(c, sizeof(char), 1, fp);
c[0]++;
}
int ip[1] = {1};
fwrite(ip, sizeof(int), 1, fp);
fwrite(ip, sizeof(int), 1, fp);
fwrite(ip, sizeof(int), 1, fp);
fclose(fp);
If the 'sample.bin' file is viewed using a dump program such as 'od', it gives the content as follows.
od -t x1 -c sample.bin
0000000 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50
A B C D E F G H I J K L M N O P
0000020 01 00 00 00 01 00 00 00 01 00 00 00
001 \0 \0 \0 001 \0 \0 \0 001 \0 \0 \0
0000034
MS-DOS (and so today with Windows), when writing a file in text mode, adds an 0x0D before every 0x0A. In other words, it processes arbitrary data streams as they go to and from store and messes with their data - utterly, utterly insane.
Open the file in binary mode for non-insane handling.
This code
#include <stdio.h>
#define SECTORSIZE 512 // bytes per sector
int main(int argc, char *argv[])
{
FILE *fp; // filepointer
size_t rdcnt; // num. read bytes
unsigned char buffer[SECTORSIZE];
if(argc < 2)
{
fprintf(stderr, "usage:\n\t%s device\n", argv[0]);
return 1;
}
fp = fopen(argv[1], "rb");
if(fp == NULL)
{
fprintf(stderr, "unable to open %s\n",argv[1]);
return 1;
}
rdcnt = fread(buffer, 1, SECTORSIZE, fp);
if(rdcnt != SECTORSIZE)
{
fprintf(stderr, "reading %s failed\n", argv[1]);
fclose(fp);
return 1;
}
fwrite(buffer, 1, SECTORSIZE, stdout);
fclose(fp);
return 0;
}
kindly taken from here
https://redeaglesblog.wordpress.com/2011/04/05/sektoren-eines-datentragers-lesen/
reads the boot sector from any given disk
Pasted as it is in your preferred C (ANSI) IDE or editor, it compiles and works either in windows (mingw passing \.\PhysicalDriveX) and linux (gcc passing /dev/sdX)
But it works like a charm ONLY in Linux while it anyway inserts/adds an x0D preceding any x0A despiting the fp = fopen(argv[1], "rb");
I've compiled it from code::blocks with mingw as readsect.exe and run it reading the boot sector of my hard drive
c:\readsect.exe \\.\PhysicalDrive0 > read.bin
The file read.bin results with a lenght of 515 bytes instead than 512.
With an HEX editor able to open physical drives, I've compared my boot sector content with the read.bin one.
Well, every x0A in the physical boot sector (x0A is found 3 times), in the read.bin file is dumped as x0D + X0A. So I have three x0D, three bytes more.
Googleing, it looks like a widely reported problem.
Do any of you have found a fix?
Maybe stdio.h needs a fix for the windows environment?
Thank you

Resources