I'm facing a very odd issue when trying to read a file in C.
I've parsed a file path via a command line argument, and gotten the size using the stat() function, and this works fine. However, after I read the file, all of my integers become arbitrarily large, and I cannot for the life of me figure out why!
Here is the relevant code from my main function:
int main( int argc, char *argv[] ) {
char *filepath = argv[1];
startaddress = strtol(argv[2], &endptra, 16);
endaddress = strtol(argv[3], &endptrb, 16);
int filesize = getfilesize(filepath);
printf("Filesize is %d\n", filesize);
unsigned char *mem = malloc( filesize );
printf("Filesize here is %d\n", filesize);
int size2 = filesize;
int test3 = 18;
printf("Size 2 set to %d\n", size2);
printf("Test 3 set to %d\n", test3);
// READ FILE
loadimage(filepath, &mem, filesize);
printf("Right after load image, file size is %d\n", filesize);
printf("%s\n", strerror(errno));
printf("Filesize is %d\n", filesize);
printf("size2: %d\n", size2);
printf("test3: %d\n", test3);
exit(0);
}
"getfilesize" is a relatively simple function that appears to work well:
int getfilesize(char *path) {
struct stat sbuffer;
int filesize = 0;
filesize = stat(path, &sbuffer);
if (filesize == -1) {
return 0;
} else {
return sbuffer.st_size;
}
}
Here is the loadimage function:
int loadimage(char *path, unsigned char *mem[], int size) {
int fdin, retval;
unsigned char buf[2048];
int nread;
printf("Path is: %s\n", path);
printf("Size is: %d\n", size);
fdin = open(path, O_RDONLY);
printf("fdin: %d\n", fdin);
if(fdin == -1) {
die(strerror( errno ));
}
int count = 0;
nread = read(fdin, buf, 2048);
for(; count < nread; count++) {
mem[count] = &buf[count];
}
if(nread == -1) {
die(strerror( errno ));
}
retval = close(fdin);
printf("Size is now %d\n", size);
return 1;
}
And this is the output of the result:
Filesize is 39
Filesize here is 39
Size 2 set to 39
Test 3 set to 18
Path is: test_file.txt
Size is: 39
fdin: 3
Size is now 39
Right after load image, file size is 32765
Success
Filesize is 32765
size2: 1418855892
test3: 32765
This is baffling to me and I cannot figure it out! It's confusing that even integers that I don't pass to the function are being modified as well. I'm assuming there's some sort of memory overflow happening somewhere, but I'm not used to working in the file system in C.
Thanks!
It seems to me that the problem is here:
int loadimage(char *path, unsigned char *mem[], int size) {
The mem argument should be just a pointer, or just an array, but not both. Aside from that, you're doing the same with the buf local variable, you're dereferencing it more than once when you use it (however that case might be harmless, I'm not sure). loadimage() should be:
int loadimage(char *path, unsigned char *mem, int size) {
int fdin, retval;
unsigned char buf[2048];
int nread;
printf("Path is: %s\n", path);
printf("Size is: %d\n", size);
fdin = open(path, O_RDONLY);
printf("fdin: %d\n", fdin);
if(fdin == -1) {
die(strerror( errno ));
}
int count = 0;
nread = read(fdin, buf, 2048);
for(; count < nread; count++) {
mem[count] = buf[count]; //no need for derefencing
}
if(nread == -1) {
die(strerror( errno ));
}
retval = close(fdin);
printf("Size is now %d\n", size);
return 1;
}
then, when calling it, do not dereference mem:
loadimage(filepath, mem, filesize);
Sorry, I don't have time so I haven't compiled it, but you get the idea, most probably that's the problem.
Related
So I'm having a bit of trouble wrapping my head around growing a buffer, from what I'm seeing I'm definitely reading all of the bytes from the file descriptor, but it seems I'm not storing them in the buffer properly. Can someone help point me in the right direction?
char *read_all(int fd, int *nread){ //nread tracks total bytes read
int max_size = 1;
*nread = 0;
char *buf = malloc(max_size*sizeof(char));
int bytes_read = read(fd, buf, max_size*sizeof(char));
while(bytes_read > 0){
*nread+=bytes_read;
if(*nread >= max_size*sizeof(char)){
max_size*=2;
buf = realloc(buf, max_size*sizeof(char));
}
bytes_read = read(fd, buf, max_size*sizeof(char));
}
return buf;
}
==== EXPECT ==== ==== ACTUAL ====
{ {
// Tests the read_all() function to ensure that // Tests the read_all() function to ensure that
// it properly accumulates all data from an // it properly accumulates all data from an
// arbitrary input FD including allocating memory // arbitrary input FD including allocating memory
// for the data. // for the data.
int fd = open("test-data/quote.txt", O_RDONLY); int fd = open("test-data/quote.txt", O_RDONLY);
int bytes_read = -1; int bytes_read = -1;
char *actual_read = read_all(fd, &bytes_read); char *actual_read = read_all(fd, &bytes_read);
int result = close(fd); int result = close(fd);
printf("result: %d\n", result); printf("result: %d\n", result);
printf("bytes_read: %d\n", bytes_read); printf("bytes_read: %d\n", bytes_read);
actual_read[bytes_read] = '\0'; actual_read[bytes_read] = '\0';
printf("actual_read:\n" ); printf("actual_read:\n" );
printf("--------------------\n" ); printf("--------------------\n" );
printf("%s",actual_read); printf("%s",actual_read);
printf("--------------------\n" ); printf("--------------------\n" );
free(actual_read); free(actual_read);
} }
result: 0 result: 0
bytes_read: 125 bytes_read: 125
actual_read: actual_read:
-------------------- --------------------
Object-oriented programming is an exceptionally bad idea which could | could
only have originated in California. only have originated in California.
-- Edsger Dijkstra -- Edsger Dijkstra
-------------------- --------------------
ALERTS: ALERTS:
(
Somewhat bizzare...
I changed read_all() so it works more like expected: (full here)
char *read_all2(int fd, int *nread){ //nread tracks total bytes read
int max_size = 1;
*nread = 0;
char *buf = malloc(max_size*sizeof(char));
char *ptr = buf;
int bytes_read = 0;
//while(bytes_read > 0)
do
{
fprintf(stderr, "bytes_read=%d\n", bytes_read);
*nread += bytes_read;
ptr += bytes_read;
if(*nread >= max_size*1){
max_size *= 2;
fprintf(stderr, "realloc(buf=%08x, max_size=%d)\n", buf, max_size);
buf = realloc(buf, max_size*1);
}
} while((bytes_read = read(fd, ptr, max_size*1)) > 0);
return buf;
}
but when it realloc(buf, 16); it crashes.
$ gcc -o readynbuf2 readynbuf2.c ; ./readynbuf2
bytes_read=0
bytes_read=1
realloc(buf=016ba008, max_size=2)
bytes_read=2
realloc(buf=016ba008, max_size=4)
bytes_read=4
realloc(buf=016ba008, max_size=8)
bytes_read=8
realloc(buf=016ba008, max_size=16)
*** Error in `./readynbuf2': realloc(): invalid next size: 0x016ba008 ***
I'm out of ideas why would it happen.
Thanks guys, I managed to solve it, the key was passing &buf[*nread] into read().
char *read_all(int fd, int *nread){
int bytes_read = 0, size_mult = 1;
*nread = 0;
char * buf = malloc(1024);
bytes_read = read(fd, &buf[*nread], 256);
while(bytes_read > 0){
*nread += bytes_read;
if(*nread > size_mult*512){
size_mult*=2;
buf = realloc(buf, size_mult*1024);
}
bytes_read = read(fd, &buf[*nread], 256);
}
return buf;
}
I wrote a simple file copy application to measure the effectiveness of using sendfile API over normal read-from-file-and-write-to-socket approach for large files. However upon running the application using both the approaches, I found out that the difference in the amount of time taken for the file copy to get completed is very minimal between the two approaches.
I read from multiple sources that "sendfile" API would give tremendous performance improvement over the normal read-from-file-and-write-to-socket approach. But when I tried to benchmark with a single 2GB file following are the numbers I observed (average of 4 iterations):
Normal read-from-file-and-write-to-socket approach: 17 secs 444840 usecs
sendfile API: 17 secs 431420 usecs
I am running both the server and client pieces of the application on two different machines (Linux kernel version 4.4.162-94.72-default) in an isolated 1Gbps network.
Can someone help me what exactly am doing wrong here or missing here?
Server:
#define _GNU_SOURCE
#include "file_details.h"
void calculate_execution_time(struct timeval start, struct timeval end)
{
struct timeval time_diff;
time_diff.tv_sec = end.tv_sec - start.tv_sec;
time_diff.tv_usec = end.tv_usec - start.tv_usec;
// Adjust the time appropriately
while (time_diff.tv_usec < 0) {
time_diff.tv_sec--;
time_diff.tv_usec += 1000000;
}
printf("total execution time: = %lds.%ldus\n", time_diff.tv_sec, time_diff.tv_usec);
}
int read_from_file_pread(int client_sockfd, char *file_name, int fd, off_t file_size_in_bytes, int chunk_size)
{
ssize_t bytes_read = 0, bytes_sent = 0, total_bytes_sent = 0, bytes_sent_this_itr = 0;
off_t offset = 0;
char *buffer = NULL;
struct timeval start_time, end_time;
buffer = calloc(chunk_size, sizeof(char));
if (buffer == NULL) {
printf("Failed to allocate memory of size: %d bytes\n", chunk_size);
return -1;
}
gettimeofday(&start_time, NULL);
do {
bytes_read = pread(fd, buffer, chunk_size, offset);
switch (bytes_read) {
case -1:
printf("Failed to read from file: %s, offset: %lu, error: %d\n", file_name, offset, errno);
free(buffer);
return -1;
case 0:
printf("Completed reading from file and sending\n");
break;
default:
do {
bytes_sent = send(client_sockfd, buffer, (bytes_read - bytes_sent_this_itr), 0);
if (bytes_sent == -1) {
printf("Failed to send %lu bytes, error: %d\n", (bytes_read - bytes_sent_this_itr), errno);
free(buffer);
return -1;
}
bytes_sent_this_itr += bytes_sent;
} while (bytes_sent_this_itr < bytes_read);
bytes_sent = 0;
bytes_sent_this_itr = 0;
offset += bytes_read;
total_bytes_sent += bytes_read;
break;
}
} while (total_bytes_sent < file_size_in_bytes);
gettimeofday(&end_time, NULL);
printf("File size: %lu bytes, total bytes read from file: %lu, ", file_size_in_bytes, total_bytes_sent);
calculate_execution_time(start_time, end_time);
free(buffer);
return 0;
}
int read_from_file_sendfile(int client_sockfd, char *file_name, int fd, off_t file_size_in_bytes, int chunk_size)
{
ssize_t bytes_sent = 0, total_bytes_sent = 0;
off_t offset = 0;
struct timeval start_time, end_time;
gettimeofday(&start_time, NULL);
do {
bytes_sent = sendfile(client_sockfd, fd, &offset, chunk_size);
if (bytes_sent == -1) {
printf("Failed to sendfile: %s, offset: %lu, error: %d\n", file_name, offset, errno);
return -1;
}
total_bytes_sent += bytes_sent;
} while (total_bytes_sent < file_size_in_bytes);
gettimeofday(&end_time, NULL);
printf("File size: %lu bytes, total bytes read from file: %lu, ", file_size_in_bytes, total_bytes_sent);
calculate_execution_time(start_time, end_time);
return 0;
}
int read_from_file(int client_sockfd, char *file_name, char *type, int chunk_size)
{
int error_code = 0, fd = 0;
ssize_t hdr_length = 0, bytes_sent = 0, file_name_length = strlen(file_name);
struct stat file_stat = {0};
struct file_details *file_details_to_send = NULL;
fd = open(file_name, O_RDONLY, S_IRUSR);
if (fd == -1) {
printf("Failed to open file: %s, error: %d\n", file_name, errno);
return -1;
}
error_code = fstat(fd, &file_stat);
if (error_code == -1) {
printf("Failed to get status of file: %s, error: %d\n", file_name, errno);
close(fd);
return -1;
}
hdr_length = (sizeof(struct file_details) + file_name_length + 1);
file_details_to_send = calloc(hdr_length, sizeof(char));
if (file_details_to_send == NULL) {
perror("Failed to allocate memory");
close(fd);
return -1;
}
file_details_to_send->file_name_length = file_name_length;
file_details_to_send->file_size_in_bytes = file_stat.st_size;
strcpy(file_details_to_send->file_name, file_name);
printf("File name: %s, size: %lu bytes\n", file_name, file_stat.st_size);
bytes_sent = send(client_sockfd, file_details_to_send, hdr_length, 0);
if (bytes_sent == -1) {
printf("Failed to send header of size: %lu bytes, error: %d\n", hdr_length, errno);
close(fd);
return -1;
}
if (strcmp(type, "rw") == 0) {
printf("By pread and send\n");
read_from_file_pread(client_sockfd, file_name, fd, file_stat.st_size, chunk_size);
} else {
printf("By sendfile\n");
read_from_file_sendfile(client_sockfd, file_name, fd, file_stat.st_size, chunk_size);
}
close(fd);
return 0;
}
int main(int argc, char *argv[])
{
...
...
option_value = 1;
error_code = setsockopt(client_sockfd, SOL_TCP, TCP_NODELAY, &option_value, sizeof(int));
if (error_code == -1) {
printf("Failed to set socket option TCP_NODELAY to socket descriptor: %d, error: %d", client_sockfd, errno);
}
read_from_file(client_sockfd, file_name, type, chunk_size);
...
}
Your code almost certainly made a big performance improvement. The problem might be that you're measuring wall time. Consider calling getrusage() instead of gettimeofday(). The ru_utime and ru_stime fields represent how much time the kernel and your program spent doing actual work. sendfile() should make those numbers go down. That way you consume less energy, and free up more resources for other programs on your computer. Unfortunately however it can't make the network go faster. Optimal wall time speed to send 2GB on 1GbPS ethernet assuming zero overhead would be ~9s. You're pretty close.
I want to encrypt/decrypt a long file with RSA (I know AES is better, but this is just for a comparison) in openssl/libcrypto. I am splitting the input file into blocks of size numBlocks = inputFileLength/maxlen+1 where maxlen = 200. I can successfully encode and decode in the same loop as follows:
for (int i = 0; i < chunks; i++)
{
int bytesDone = i * maxlen;
int remainingLen = inLength - bytesDone;
int thisLen;
if (remainingLen > maxlen)
{
thisLen = maxlen;
} else
{
thisLen = remainingLen;
}
if((encBytes=RSA_public_encrypt(thisLen, data + bytesDone, encryptdata + bytesDone,
rsa_public, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
if((decBytes=RSA_private_decrypt(encBytes, encryptdata + bytesDone, decryptdata + bytesDone,
rsa_private, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
}
However, I want to save the encoded buffer encryptdata in a binary file, reading the binary file back and decryption. I try to do this as follows:
for (int i = 0; i < chunks; i++)
{
int bytesDone = i * maxlen;
int remainingLen = inLength - bytesDone;
int thisLen;
if (remainingLen > maxlen)
{
thisLen = maxlen;
} else
{
thisLen = remainingLen;
}
if((encBytes=RSA_public_encrypt(thisLen, data + bytesDone, encryptdata + bytesDone,
rsa_public, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
}
writeFile("encoded.bin",encryptdata,strlen(encryptdata));
size_t size;
unsigned char *readData = readFile("encoded.bin", size);
int inputlen = size;
for (int i = 0; (i * keylen) < inputlen; i++) //keylen = 256
{
int bytesDone = i * keylen;
if((decBytes=RSA_private_decrypt(encBytes, readData + bytesDone, decryptdata + bytesDone,
rsa_private, RSA_PKCS1_PADDING)) == -1)
{
printf("error\n");
}
}
printf("Decrypted text: %s",decryptdata);
The readFile and writeFile functions are as follows:
void writeFile(char *filename, unsigned char *file, size_t fileLength
{
FILE *fd = fopen(filename, "wb");
if(fd == NULL) {
fprintf(stderr, "Failed to open file: %s\n", strerror(errno));
exit(1);
}
size_t bytesWritten = fwrite(file, 1, fileLength, fd);
if(bytesWritten != fileLength) {
fprintf(stderr, "Failed to write file\n");
exit(1);
}
fclose(fd);
}
unsigned char* readFile(char *filename, size_t size) {
FILE *fd = fopen(filename, "rb");
if(fd == NULL) {
fprintf(stderr, "Failed to open file: %s\n", strerror(errno));
exit(1);
}
// Determine size of the file
fseek(fd, 0, SEEK_END);
size_t fileLength = ftell(fd);
fseek(fd, 0, SEEK_SET);
size = fileLength;
// Allocate space for the file
unsigned char* buffer = (unsigned char*)malloc(fileLength);
// Read the file into the buffer
size_t bytesRead = fread(buffer, 1, fileLength, fd);
if(bytesRead != fileLength) {
fprintf(stderr, "Error reading file\n");
exit(1);
}
fclose(fd);
return buffer;
}
However, the decryption fails with the error message segmentation fault (core dump) and the decrypt function only returns -1 for every block. Any help will be appreciated.
ReadFile modifies the parameter "size" which is passed by value, thus when the readfile function returns, size is not affected.
I would change readfile proto as follows :
unsigned char* readFile(char *filename, size_t *size)
and then change the call into
unsigned char *readData = readFile("encoded.bin", &size);
and finally modify the readFile size update to
size = fileLength;
Your have various technical errors in your code like doing a strlen(..) on binary data in this statement:
writeFile("encoded.bin",encryptdata,strlen(encryptdata));
encryptdata is binary data that can include 0 that would be interprited as a string termination by strlen(..)
But the main problem is that you try to use RSA as a block cipher. Your encrypted blocks are bigger that what you encrypt, but you don't handle that in your code. You might be able to get your code to handle this, but the right approach is to use ciphers invented for bulk encryption, like AES. When you do that, you automatically get support for 'blocking' out of the box.
In addition to this you get something like a factor 1000 faster encryption.
This code does not work - issues with passing the data from subroutine to main and allocating memory.
Computations are correct inside the subroutine but the values received by the main are incorrect - variables in main has random values, eg sRates.
#include <stdio.h>
#include <malloc.h>
#include "sndfile.h"
int main(int argc, char *argv[])
{
int sRates , sRatem , ret;
long nSamples=0, nSamplem;
float *datas, *datam;
printf("Read Test\n");
if (argc != 3) {
fprintf(stderr, "Expecting two wav file as argument\n");
return 1;
}
ret = readWav(argv[1], nSamples, sRates, &datas );
if (ret != 0) {
printf("Error\n");
}
// Output Info
printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n",
nSamples, argv[1], sRates, (float)nSamples/sRates);
printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n",
nSamples, argv[1], sRates, (float)nSamples/sRates);
// free(datas);
return 0;
}
int readWav(char *fname, long *numFrames, int *sRate, float **buffer )
{
// Open sound file
SF_INFO sndInfo;
SNDFILE *sndFile = sf_open(fname, SFM_READ, &sndInfo);
if (sndFile == NULL) {
fprintf(stderr, "Error reading source file '%s': %s\n", fname, sf_strerror(sndFile));
return 1;
}
printf("1Format of the audio file = %i\n", sndInfo.format);
printf("2Number of channels = %i\n", sndInfo.channels);
printf("3Sample Rate = %d\n", sndInfo.samplerate);
printf("4 Sample count = %ld\n", (long)sndInfo.frames);
sRate= sndInfo.samplerate;
// Allocate memory
buffer = (float *)malloc(sndInfo.frames * sndInfo.channels * sizeof(float));
if (buffer == NULL) {
fprintf(stderr, "Could not allocate memory for file\n");
sf_close(sndFile);
return 1;
}
// Load data
numFrames = sf_readf_float(sndFile, buffer, sndInfo.frames);
// Check correct number of samples loaded
if (numFrames != sndInfo.frames) {
fprintf(stderr, "Did not read enough frames for source\n");
sf_close(sndFile);
free(buffer);
// return 1;
}
else {
printf("Successfully read file\n");
numFrames = sndInfo.frames;
}
// Output Info
printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n",
// numFrames, fname, sndInfo.samplerate, (float)numFrames/sndInfo.samplerate);
numFrames, fname, sRate, (float)numFrames/sndInfo.samplerate);
sf_close(sndFile);
// return(buffer);
return(0);
}
In C all arguments are passed by-value, so if you want a by-ref-like argument you must pass a pointer. And since you want to return a float* you need to pass a float**.
Actually you are passing that, but you are not using it correctly (please use -Wall or equivalent for your compiler to enable warnings).
The code should like more or less like this:
int readWav(const char *fname, long *numFrames, int *sRate, float **buffer)
{
*buffer = malloc(...);
//if you do not feel comfortable writing `*buffer` everywhere:
float *data = *buffer;
///....
*numFrames = sf_readf_float(...);
///....
*sRate = sndInfo.samplerate;
///....
}
int main()
{
long nSamples;
int sRates;
float *datas;
ret = readWav(argv[1], &nSamples, &sRates, &datas);
//...
}
You have several errors in your code
You don't declare readWav() and you call it from main(), it's working by coincidence, namely because it does return int.
You are passing the address of datas to readWav(), note that &datas has type float ** and readWav() is expecting a float *.
If you had compiler warnings turned on, youl'd have noticed this.
You are passing the value of nSamples and sRate to readWav() and you are expecting the nSamples and sRate in your main to get initialized, you need to pass their addresses instead.
You check the return value of readWav() and yet you still try to acces the datas pointer.
This is a fixed version of your code
#include <stdio.h>
#include "sndfile.h"
int readWav(const char *const fname, long *numFrames, int *sRate, float **buffer);
int main(int argc, char *argv[])
{
int sRates, sRatem, ret;
long nSamples = 0, nSamplem;
float *datas, *datam;
printf("Read Test\n");
if (argc != 3) {
fprintf(stderr, "Expecting two wav file as argument\n");
return 1;
}
ret = readWav(argv[1], &nSamples, &sRates, &datas);
if (ret != 0) {
printf("Error\n");
return 1;
}
// Output Info
printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n",
nSamples, argv[1], sRates, (float)nSamples/sRates);
printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n",
nSamples, argv[1], sRates, (float)nSamples/sRates);
free(datas);
return 0;
}
int readWav(const char *const fname, long *numFrames, int *sRate, float **buffer)
{
// Open sound file
SF_INFO sndInfo;
if ((sRate == NULL) || (numFrames == NULL) || (buffer == NULL)) {
fprintf(stderr, "Invalid arguments passed to readWav()\n");
return 1;
}
SNDFILE *sndFile = sf_open(fname, SFM_READ, &sndInfo);
if (sndFile == NULL) {
fprintf(stderr, "Error reading source file '%s': %s\n", fname, sf_strerror(sndFile));
return 1;
}
printf("1Format of the audio file = %i\n", sndInfo.format);
printf("2Number of channels = %i\n", sndInfo.channels);
printf("3Sample Rate = %d\n", sndInfo.samplerate);
printf("4 Sample count = %ld\n", (long)sndInfo.frames);
// Allocate memory
*buffer = malloc(sndInfo.frames * sndInfo.channels * sizeof(float));
if (*buffer == NULL) {
fprintf(stderr, "Could not allocate memory for file\n");
sf_close(sndFile);
return 1;
}
*sRate = sndInfo.samplerate;
// Load data
*numFrames = sf_readf_float(sndFile, *buffer, sndInfo.frames);
// Check correct number of samples loaded
if (*numFrames != sndInfo.frames) {
fprintf(stderr, "Did not read enough frames for source\n");
sf_close(sndFile);
free(*buffer);
}
else {
printf("Successfully read file\n");
*numFrames = sndInfo.frames;
}
// Output Info
printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n",
*numFrames, fname, *sRate, (float)*numFrames/sndInfo.samplerate);
sf_close(sndFile);
return(0);
}
Tip: You should try to write your function in such a way that it has only one exit point, I like using goto for that, despite what religious programmers believe about goto, it makes your code more readable consistent and maintainable.
What I mean is you can have a label where you return the error code from the function and do all the cleanup, something like this
int function()
{
/* set errorCode */
if (firstFailureCondition == 1)
goto cleanup;
if (secondFailureCondition == 1)
goto cleanup;
.
.
.
if (nthFailureCondition == 2)
goto cleanup;
cleanup:
/* do your cleanup */
return errorCode;
}
I am trying to print a partition table using C programming language, everything seems to work fine: Opening and reading, but I don't understand why it is printing garbage values.
Here is the code:
struct partition
{
unsigned char drive;
unsigned char chs_begin[3];
unsigned char sys_type;
unsigned char chs_end[3];
unsigned char start_sector[4];
unsigned char nr_sector[4];
};
int main()
{
int gc = 0, i = 1, nr = 0, pos = -1, nw = 0;
int fd =0;
char buf[512] ;
struct partition *sp;
printf("Ok ");
if ( (fd = open("/dev/sda", O_RDONLY | O_SYNC )) == -1)
{
perror("Open");
exit(1);
}
printf("fd is %d \n", fd);
pos = lseek (fd, 0, SEEK_CUR);
printf("Position of pointer is :%d\n", pos);
if ((nr = read(fd, buf, sizeof(buf))) == -1)
{
perror("Read");
exit(1);
}
close(fd);
printf("Size of buf = %d\n and number of bytes read are %d ", sizeof(buf), nr);
if ((nw = write(1, buf, 64)) == -1)
{
printf("Write: Error");
exit(1);
}
printf("\n\n %d bytes are just been written on stdout\n", nw,"this can also be printed\n");
printf("\n\t\t*************Partition Table****************\n\n");
for (i=0 ; i<4 ; i++)
{
sp = (struct partition *)(buf + 446 + (16 * i));
putchar(sp -> drive);
}
return 0;
}
It is printing garbage instead of partition table.
I might have some basic understanding issues but I searched with Google for a long time but it did not really help. I also saw the source code of fdisk but it is beyond my understanding at this point. Could anyone please guide me? I am not expecting someone to clear my mistake and give me the working code. Just a sentence or two - or any link.
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
struct partition
{
unsigned char boot_flag; /* 0 = Not active, 0x80 = Active */
unsigned char chs_begin[3];
unsigned char sys_type; /* For example : 82 --> Linux swap, 83 --> Linux native partition, ... */
unsigned char chs_end[3];
unsigned char start_sector[4];
unsigned char nr_sector[4];
};
void string_in_hex(void *in_string, int in_string_size);
void dump_partition(struct partition *part, int partition_number);
void dump_partition(struct partition *part, int partition_number)
{
printf("Partition /dev/sda%d\n", partition_number + 1);
printf("boot_flag = %02X\n", part->boot_flag);
printf("chs_begin = ");
string_in_hex(part->chs_begin, 3);
printf("sys_type = %02X\n", part->sys_type);
printf("chs_end = ");
string_in_hex(part->chs_end, 3);
printf("start_sector = ");
string_in_hex(part->start_sector, 4);
printf("nr_sector = ");
string_in_hex(part->nr_sector, 4);
}
void string_in_hex(void *in_string, int in_string_size)
{
int i;
int k = 0;
for (i = 0; i < in_string_size; i++)
{
printf("%02x ", ((char *)in_string)[i]& 0xFF);
k = k + 1;
if (k == 16)
{
printf("\n");
k = 0;
}
}
printf("\n");
}
int main(int argc, char **argv)
{
int /*gc = 0,*/ i = 1, nr = 0, pos = -1/*, nw = 0*/;
int fd = 0;
char buf[512] ;
struct partition *sp;
int ret = 0;
printf("Ok ");
if ((fd = open("/dev/sda", O_RDONLY | O_SYNC)) == -1)
{
perror("Open");
exit(1);
}
printf("fd is %d\n", fd);
pos = lseek (fd, 0, SEEK_CUR);
printf("Position of pointer is :%d\n", pos);
if ((nr = read(fd, buf, sizeof(buf))) == -1)
{
perror("Read");
exit(1);
}
ret = close(fd);
if (ret == -1)
{
perror("close");
exit(1);
}
/* Dump the MBR buffer, you can compare it on your system with the output of the command:
* hexdump -n 512 -C /dev/sda
*/
string_in_hex(buf, 512);
printf("Size of buf = %d - and number of bytes read are %d\n", sizeof(buf), nr);
/*if ((nw = write(1, buf, 64)) == -1)
{
printf("Write: Error");
exit(1);
}
printf("\n\n%d bytes are just been written on stdout\nthis can also be printed\n", nw);
*/
//printf("\n\t\t*************Partition Table****************\n\n");
printf("\n\t\t*************THE 4 MAIN PARTITIONS****************\n\n");
/* Dump main partitions (4 partitions) */
/* Note : the 4 partitions you are trying to dump are not necessarily existing! */
for (i = 0 ; i < 4 ; i++)
{
sp = (struct partition *)(buf + 446 + (16 * i));
//putchar(sp->boot_flag);
dump_partition(sp, i);
}
return 0;
}