How to read from pipe into a file? - c

I would like to read from the pipe straight into a file with the code below. base_fd is a pipe.
FILE* fp = fopen("dec_data", "wb+");
int r_result;
int len = msg_length-part-3; //set to 75933
while ((r_result = read(base_fd[0], fp, len))) {
printf("r_result: %d \n", r_result);
len -= r_result;
}
The read seems to happen fine, with r_result showing 65536 and then 10397 as required. However, when I inspect the file I created, it has a size of 0 bytes...

You have a semantic error in your code.
Take a look at the read(2) system call signature:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
The second parameter to the function is a void pointer (void *buf), which is where read will store the count bytes it reads from fd descriptor.
However, a FILE * is an abstraction of the C library. In this answer you can see more of it. The struct FILE in MinGW32 5.1.4 is:
typedef struct _iobuf
{
char* _ptr;
int _cnt;
char* _base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
} FILE;
What read will do is similar to how we copy strings. Consider this function:
void strcpy(char *dst, char *src)
{
while(*src) *dst++ = *src++;
}
This function will copy the contents from src into dst until it finds a NULL terminating byte. This is obviously a very flawed function and should never be used, but illustrates why your example doesn't work.
Under the hood, what read is doing is very similar to this strcpy function: it is overwriting a lot of bytes in memory starting at the address pointed to by the fp pointer. You are effectively losing your reference to the FILE * pointer and the resources associated to it.
I'll bet that if you try to close(fp) after that loop you'll get a segmentation fault (it's Undefined Behavior, but I'll bet anyway).
The right way to do what you want is:
FILE* fp = fopen("dec_data", "wb+");
char *buf;
int r_result;
int len = msg_length - part - 3; //set to 75933
buf = malloc(len);
if(!buf) {
perror("malloc");
exit(EXIT_FAILURE);
}
while ((r_result = read(base_fd[0], buf, len))) {
fprintf(fp, buf);
len -= r_result;
}
free(buf);
close(fp); // now it closes the file pointer

Related

Segmentation fault when initializing pointer to char array

I am trying to write a program that reads text from a file, converts the characters to uppercase and then writes the output on a new file. The code works just fine for the reading and converting to uppercase parts, but for the writing the output part when I create a char* for the name of the output file, I get a segmentation fault.
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
void lowerToUpper(char* temp)
{
char* name;
name = strtok(temp,":");
// Convert to upper case
char* s = name;
while (*s)
{
*s = toupper((unsigned char) *s);
s++;
}
}
int main()
{
int fd;
char* file_name_read = "./test.txt";
fd = open(file_name_read, O_RDONLY);
char* buf_rd;
ssize_t nr;
size_t byte_count = 1000;
off_t offset = 0;
nr = pread(fd, buf_rd, byte_count, offset);
close(fd);
lowerToUpper(buf_rd);
char* file_name_write = "./test_uppercase.txt";
/* CODE FOR WRITING TO THE FILE */
return 0;
}
When I remove the char* file_name_write line, the code works fine. When I include it in the code, I get a segmentation fault.
I have tried
removing the call to the lowerToUpper() inside main
using char file_name_write[] instead of char* file_name_write
using malloc() to allocate space and then assign its value
using different byte_count and offset values
Edit:
The problem was an uninitialized pointer with buf_rd. When I added
char* buf_rd = (char*) malloc(1000 * sizeof(char));
it solved the problem.
Thank you Mr Lister and lurker!
char* buf_rd;
...
nr = pread(fd, buf_rd, byte_count, offset);
You did not allocate memory for buf_rd. It is just a pointer.
You use buf_rd as buffer, but that variable is only declared and never initialized.
The documentation says:
ssize_t pread(int fd , void * buf , size_t count , off_t offset );
pread() reads up to count bytes from file descriptor fd at offset
offset (from the start of the file) into the buffer starting at buf.
The file offset is not changed.
It is expected of you to initialize the a buffer that can be used by the pread function.

how I correctly read struct from a file?

I have this kind of struct:
typedef struct {
char a[MAX];
char b[MAX];
int c;
} mys;
and this functions:
mys* search_m(FILE *fp, int m)
{
mys* s;
s=(mys *)malloc(sizeof(mys));
if(s){
for(int i=0;i<m;i++)
fread(s,sizeof(mys),1,fp);
}else{
printf("Error during allocation\n");
}
return s;
}
void search_s(FILE *fp, char *c)
{
mys s;
int count=0;
while(fread(&s,sizeof(mys),1,fp)==1){
if(strcmp(s.b,c)==0){
show_s(s,count);
}
count++;
}
return;
}
that's a part of my program. During the input fase (when I write data on my file) I don't have any problem ( using fread) but I have some problem reading it.
The my function search_s execute and find the value every time that I call it, but the search_m function seems that can't read anby data in my file and since it's practically the same things that I did on search_s I don't know where is my mistake.
In my main when I call seach_m I do this:
s=*search_ID(f_ptr,m);
show_s(s,m);
I don't think that the problem is in the main since the fread in the search_m function doesn't load any data (it stops on the first try).
Where is my mistake? I thought that it was all right
PS before calling this function I open the file and I check for errors and after I close the file.
EDIT:
I'm opening the file with this:
f_ptr=fopen(argv[1],"rb");
(It doesn't work (also) if I only use "r")
argv[1] is the name of my file
PS m is the number of the element in the file that I want to read.
(I read every time one block untile I don't get the m-esimo element)
My file contains only struct of that type.
The following line does not allocate enough memory.
s=(mys *)malloc(sizeof(mys));
You are allocating memory for just object. As a result, you are accessing more memory than you allocated, which causes undefined behavior.
You need to allocate memory for m objects.
s = malloc(sizeof(mys)*m);
See Do I cast the result of malloc? to understand why you should not cast the return value of malloc.
Also, make sure that you read into the appropriate slot of the allocated memory.
mys* search_m(FILE *fp, int m)
{
mys* s = malloc(sizeof(mys)*m);
if(s){
for(int i=0;i<m;i++)
fread(s+i, sizeof(mys), 1, fp); // Use s+i
}else{
printf("Error during allocation\n");
}
return s;
}
You can compress that to just one call to fread.
mys* search_m(FILE *fp, int m)
{
mys* s = malloc(sizeof(mys)*m);
if(s){
fread(s, sizeof(mys), m, fp);
}else{
printf("Error during allocation\n");
}
return s;
}
This is how you would read and write a struct to a file. You should then be able to open your file with fopen and call read_data and write_data for each of your data structures. Once read_data returns 0, it has reached EOF. This can be error prone though, as this depends on the size of the struct. If its size change between versions of your application, it might not be able to deserialize the struct correctly.
struct st_data
{
char str[25];
int i;
int j;
};
typedef struct st_data data_t;
size_t write_data(data_t *data, FILE *stream)
{
return fwrite(data, sizeof(*data), 1, stream);
}
size_t read_data(data_t *data, FILE *stream)
{
return fread(data, sizeof(*data), 1, stream);
}
void search(char *str, FILE *stream)
{
data_t data;
size_t n_read = read_data(&data, stream);
while (n_read > 0)
{
if (strcmp(data.str, str) == 0)
{
// handle data
}
n_read = read_data(&data, stream);
}
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
fprintf(stderr, "ERROR: requires a single argument");
exit(-1);
}
FILE *stream = fopen("data.txt", "rb+");
search(argv[1], stream);
fclose(stream);
exit(0);
}

C Pointer of array of strings garbled when retreived later

I have read a lot of the answers on the theoretical issues with memory allocation to pointer to arrays, but have not been able to fix my code...so turning to you.
I have an array of strings in a STRUCT, which I need to write to and read from. Declared as:
typedef struct client_mod
{
/* Client ad_file */
char *ad_filenames[10];
/* Client's current ad array index*/
unsigned int ad_index;
} client;
Then , inside a function , I assign values to pointer:
static int get_spots (client_mod *client)
{
char buf[512];
FILE *ptr;
if ((ptr = popen("php /media/cdn/getspot.php", "r")) != NULL) {
/* Read one byte at a time, up to BUFSIZ - 1 bytes, the last byte will be used for null termination. */
size_t byte_count = fread(buf, 1, 512 - 1, ptr);
/* Apply null termination so that the read bytes can be treated as a string. */
buf[byte_count] = 0;
}
(void) pclose(ptr);
// parse extracted string here...
int i = 0;
client->ad_filenames[i] = strdup(strtok(buf,"|"));
while(client->ad_filenames[i]!= NULL && i<5)
{
client->ad_filenames[++i] = strdup(strtok(NULL,"|"));
if (client->ad_filenames[i] != NULL && strlen(client->ad_filenames[i]) > 5) {
LOG("TESTING FOR CORRECT FILE NAMES %s\n", client->ad_filenames[i]);
}
}
}
The problem comes when I retreive the values later:
/* in looping code block */
LOG("Checking file under index = %d, file is %s", client->ad_index, client->ad_filenames[client->ad_index]);
The first two members of the array are retreived normally, everything after that is garbled.
I would appreciate any guidance. Thanks!
I understand this probablby comes from undefined behaviour of assigning directly to the pointer, but I can't figure out how to solve it.
I think the problem is with assigning to this struct element.
char *ad_filenames[10];
ad_filenames is an array of 10 of pointer to characters.
What that means is that memory allocation is needed for each index.
Something like
client->ad_filenames[0] = strdup(var1);
strdup() does both malloc() and strcpy() within this function.
client should be a variable name. You already defined client as a type.
Here is working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct client_mod
{
/* Client ad_file */
char *ad_filenames[10];
/* Client's current ad array index*/
unsigned int ad_index;
}CLIENT1;
CLIENT1 *client;
int func( char *var1 ) {
client->ad_filenames[0] = strdup(var1);
}
int
main(void)
{
char str1[10];
client = malloc( sizeof client );
strcpy( str1, "Hello" );
func( str1 );
printf("%s\n", client->ad_filenames[0] );
free(client->ad_filenames[0]);
free (client);
}
Your problem is with the line,
size_t byte_count = fread(buf, 1, 1000 - 1, ptr);
Read the man fread page,
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
you read 1000-1 members of size 1 into buf, which is only allocated buf[512], either expand buf or decrease fread 3rd argument,
buf[1000+1];
size_t byte_count = fread(buf, 1, sizeof(buf)-1, ptr);

What is the correct way to free output buffer after call to openssl::i2d_X509?

I want to encode X509 structure into DER bytes. Following source code example from the openssl (version > 0.9.7) man page I need to do (if I would i2d_X509 to allocate memory on its own):
int len;
unsigned char *buf;
buf = NULL;
len = i2d_X509(x, &buf);
if (len < 0)
/* error */
However, it is not completely clear (but I assume it is needed to call OPENSSL_free) from the documentation what is the right way to free memory after I am done with buf.
What is the correct way to free buf?
Short answer: OPENSSL_free must be used to free buf.
Long answer:
IMPLEMENT_ASN1_FUNCTIONS macro is expanded to definition of i2d_X509 function. The example below demonstrates that, put following source code into a source.c:
#include <openssl/asn1t.h>
IMPLEMENT_ASN1_FUNCTIONS(X509)
After execution of gcc -E source.c the macro is expanded to:
X509 *d2i_X509(X509 **a, const unsigned char **in, long len) { return (X509 *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, (&(X509_it))); }
int i2d_X509(X509 *a, unsigned char **out) { return ASN1_item_i2d((ASN1_VALUE *)a, out, (&(X509_it))); }
X509 *X509_new(void) { return (X509 *)ASN1_item_new((&(X509_it))); }
void X509_free(X509 *a) { ASN1_item_free((ASN1_VALUE *)a, (&(X509_it))); }
The point of interest is definition of i2d_X509, in turn that function calls ASN1_item_i2d. As per source code of openssl, ASN1_item_i2d is a function defined in tasn_enc.c file:
static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out,
const ASN1_ITEM *it, int flags)
{
if (out && !*out) {
unsigned char *p, *buf;
int len;
len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags);
if (len <= 0)
return len;
buf = OPENSSL_malloc(len);
if (buf == NULL)
return -1;
p = buf;
ASN1_item_ex_i2d(&val, &p, it, -1, flags);
*out = buf;
return len;
}
return ASN1_item_ex_i2d(&val, out, it, -1, flags);
}
The branch if (out && !*out) is used in a case described in the original question (buf is NULL). So, internally, openssl allocates memory for the buf using OPENSSL_malloc, and as a consequence OPENSSL_free must be used to deallocate memory.
Note: I looked at the source code of openssl available on the GH at the current time.

Bus error. Cannot access memory

I'm getting bus error.
While debugging the snippet below and stepping to the end of writeDmpFile I'm getting:
writeDmpFile (tree=0x56a310, filename=0x7fffffffd450 "20140318.221058") at unzipper_m1.c:146
146 }
(gdb) n
Cannot access memory at address 0x38353031323236
The file is written though, but program ends with bus error.
Here the code:
typedef struct dmpParams_t
{
char buff[6000000];
size_t *size;
}dmpParams_t;
int writeFile(char *name, unsigned char *buff, size_t *size,const char *dir )
{
FILE * pFile;
chdir (dir);
pFile = fopen ( name, "wb");
fwrite (buff , sizeof(unsigned char), *size, pFile);
fclose (pFile);
return 1;
}
int writeDmpFile(GTree *tree, char *filename)
{
char dmpfilename[32];
dmpfilename[0] ='\0';
dmpParams_t params;
params.buff[0] ='\0';
size_t size =0;
params.size=&size ;
g_tree_foreach(tree, (GTraverseFunc)writeDmpFileLine, &params);
sprintf (dmpfilename, "InstrumentList_FULL.csv_%.*s", 15, filename);
writeFile(dmpfilename, ( unsigned char *)params.buff, &size , dmpdir);//(size_t *)params.size, dmpdir);
}
It looks like a buffer overrun of dmpfilename. You allocated an array of length 32. You then format it with "InstrumentList_FULL.csv_%.*s". That's 24 characters, plus 15 for the filename, plus a null terminator. That's more than 32.
Increase the size of the buffer.
Oh, and dmpParams_t is, er, rather large. Perhaps there's a stack overflow when you allocate one of those as a local.
Some other comments:
You could usefully use const a bit more.
Declaring size as size_t* in the struct is a bit odd. You pass the address of the struct to g_tree_foreach. I'd declare size as size_t and let g_tree_foreach modify the value.
Likewise, it seems odd that you pass the address of size to writeFile. Again a const value seems to make more sense.

Resources