calling fclose on a memstream FILE causes segmentation fualt - c

I have an interface that only prints strings to a file and Im working on a embedded system so opening a file is not an option
I created a virtual file in a memory using open_memstream , and after using the file and parsing the string the program fails on fclose causing a segmentation fault
here's the code :
/*
* Creating a temp file in memory
*/
FILE * mem_stream;
char * mem_buf;
size_t mem_len;
mem_stream = open_memstream(mem_buf,&mem_len);
XMLDoc_print(doc, mem_stream, NULL, NULL, 0, 0 ,0);
XMLDoc_free(doc);
/*
* Reading the temp file
*/
fseek(mem_stream,0,SEEK_END);
long file_size = ftell(mem_stream);
rewind(mem_stream);
char * contents = malloc( (file_size+1) * sizeof(char) );
fread(contents, sizeof(char), file_size, mem_stream);
/*
* closing the file
*/
fclose(mem_stream);
contents[file_size] = 0;
printf("\n THE RESULT XML IS : %s \n" , contents);
If i comment the fclose(mem_stream); line the program works fine , is this an option ? if not how can i fix this.

mem_stream = open_memstream(mem_buf,&mem_len); this line should be like this :
mem_stream = open_memstream(&mem_buf,&mem_len);
as said in the function's documentation
/* Open a stream that writes into a malloc'd buffer that is expanded as
necessary. *BUFLOC and *SIZELOC are updated with the buffer's location
and the number of characters written on fflush or fclose. */
extern FILE *open_memstream (char **__bufloc, size_t *__sizeloc) __THROW __wur;
the char ** __bufloc is an address to a char * buffer.

Related

heap-buffer-overflow with fprintf

I'm updating my question, very sorry for asking it the wrong way.
Now I could distill my problem into a single self-contained piece of code:
#include <stdio.h>
#include <stdlib.h>
static __inline__ char* fileRead(char* file){
FILE* fp;
long fileSize;
char* fileContents;
fp = fopen ( file , "rb" );
if(!fp){
perror(file);
exit(1);}
/* this block writes the size of the file in fileSize */
fseek( fp , 0L , SEEK_END);
fileSize = ftell( fp );
rewind( fp );
/* allocate memory for entire content */
fileContents = malloc(fileSize+1);
if(!fileContents){
fclose(fp);
fputs("memory alloc fails",stderr);
exit(1);}
/* copy the file into the buffer */
if(fread(fileContents, fileSize, 1, fp) != 1){
fclose(fp);
free(fileContents);
fputs("entire read fails",stderr);
exit(1);}
/* close the file */
fclose(fp);
return fileContents;}
int main (){
char* head10 = "";
char* fileName = "testhtml.html";
FILE* out = fopen(fileName, "w");
head10 = fileRead("head10.html");
printf("%s\n", head10);
out = fopen(fileName, "wb");
fprintf(out, "%s\n", head10);
fclose(out);
free(head10);
return 0;}
Here the head10.html file.
I'm compiling it with -fsanitize=address, and I'm getting an heap-buffer-overflow.
The error seems to be caused at the line fprintf(out, "%s\n", head10);.
head10 is the only malloc'd variable, so that makes sense.
I can print it without problems with printf, but when I try to write it to file with fprintf, an heap-buffer-overflow is generated.
===EDIT===
Looks like the problem came from using fprintf with a malloc'd var, as fprintf itself uses malloc under the hood, so the original alloc gets lost, and memory leaks.
So i rewrote my functions without using malloc:
#define _POSIX_C_SOURCE 200809L /* for getline() */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static __inline__ void fileReset(char* fileName){
FILE* out = fopen(fileName, "w");
fwrite("" , sizeof(char) , strlen("") , out );
fclose(out);}
static __inline__ void fileAppend(char* fileName, char* string){
FILE* out = fopen(fileName, "a"); /* using "a" to APPEND */
if(fwrite(string , sizeof(char) , strlen(string) , out ) != strlen(string)){
printf("==file write error\n");
exit(EXIT_FAILURE);}
fclose(out);}
static __inline__ void fileAppendFile(char* source, char* dest){
FILE* in = fopen(source, "r");
char *line = NULL;
size_t len = 0;
size_t read;
while ((read = getline(&line, &len, in)) != -1) {
fileAppend(dest, line);}
free(line);
fclose(in);}
int main (){
char* fileName = "testhtml.html";
char* theme = "dark";
fileReset(fileName);
fileAppendFile("head10.html", fileName);
fileAppend(fileName, theme);
return 0;}
Thanks a lot for all the help, very noob here, didn't know what -lasan was, now I know what an invaluable tool!
==EDIT-2==
As pointed out by EmployedRussian, the problem in the original code was NOT fprintf, but the lack of a terminating '\0', look at their answer below, it does fix my original code :)
Looks like the problem came from using fprintf with a malloc'd var, as fprintf itself uses malloc under the hood, so the original alloc gets lost, and memory leaks.
I am afraid you learned the wrong lesson here.
While fprintf may indeed use malloc under the hood, your problem doesn't have anything to do with that.
I created a head10.html file containing abc\n (4 characters). Running your program with that input file produced:
==10173==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000015 at pc 0x7fb5db2c7054 bp 0x7ffd44e74de0 sp 0x7ffd44e74590
READ of size 6 at 0x602000000015 thread T0
#0 0x7fb5db2c7053 (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x4d053)
#1 0x5654101dd435 in main /tmp/foo.c:43
#2 0x7fb5db0dde0a in __libc_start_main ../csu/libc-start.c:308
#3 0x5654101dd199 in _start (/tmp/a.out+0x1199)
0x602000000015 is located 0 bytes to the right of 5-byte region [0x602000000010,0x602000000015)
allocated by thread T0 here:
#0 0x7fb5db381628 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x107628)
#1 0x5654101dd2db in fileRead /tmp/foo.c:20
#2 0x5654101dd425 in main /tmp/foo.c:42
#3 0x7fb5db0dde0a in __libc_start_main ../csu/libc-start.c:308
So the problem is that you allocated 5 bytes (as expected), but fprintf tried to read 6th character from that buffer.
Why would it do that? Because the format you used: %s expects to find a terminating NUL character (i.e. it expects a properly terminated C-string), and you gave it a pointer to non-terminated string with the following bytes:
a b c \n X
What value does the fifth byte contain? It's undefined (it came from malloc, and no value was written into it). Since that value is not NUL, fprintf tries to read the next (6th) byte, and that's when Address Sanitizer signals the error and aborts your program.
The correct fix is to NUL-terminate the string, like so:
if (fread(fileContents, fileSize, 1, fp) != 1){ ... handle error
fileContents[fileSize] = '\0'; // NUL-terminate the string.

Displaying content of file in C - write access error

I am trying to print the entire contents of a file in C that was stored in a previous function. The file size was read and dynamic memory allocation was used accordingly to create space relative to the file size. A pointer (fp) was then used to point to the newly allocated space. Then, the contents of the file were read into the new space. (I think this is where my error is).
// gloabl variables
unsigned char *fp = 0; //pointer to navigate through the opened file.
unsigned char *fileStart = 0; // pointer to save the start address of the file, in case you need to go back to start of file
unsigned char fileSize = 0; // stores the size of file
/* Use dynamic memory allocation to store the entire contents of the file and let that memory be pointed by 'fp'.
Save the start of file in 'fileStart' so that you use it to go to start of file in other functions.
After opening the file, read the file size and use it for dynamic memory allocation to read entire file. */
void loadFile(const char *filename)
{
FILE *p = fopen(filename, "rb");
if (p == NULL) {
printf("File not created, errno = %d\n", errno);
return 1;
}
fseek(p, 0, SEEK_END); // seek to end of file
fileSize = ftell(p); // get current file pointer
fseek(p, 0, SEEK_SET); // seek back to beginning of file
printf("File loaded. File size = %#x bytes\n", fileSize);
fp = malloc(fileSize + 1);
fread(fp, fileSize, 1, p);
fileStart = &fp;
fclose(p);
}
/*Display file in hex.
Display neatly the content of the file as seen in hex editor.
Even after closing the file with fclose(), we have the contents of the file in memory pointed by 'fp' (or 'fileStart' in loadFile()).
So you don't have to open and read the file again.*/
void displayBmpFile()
{
printf("Hex view of loaded bmp file: \n");
while(!feof(fileStart))
printf("%d\t", fgetc(fileStart));
}
I recognize the error is in my first function. First, I am not sure if the contents of the file were stored properly. If the contents were stored properly, is fp correctly pointing to the file? Lastly, if everything previously is working correctly, does fileStart correctly point to the beginning of the file?
(The file is a small hex file of four square colors).
change unsigned char fileSize = 0; to size_t fileSize = 0;
(your bitmap will surely be larger that 255 bytes.)
Then (2) in void displayBmpFile() do size_t n = fileSize; unsigned char *p = fileStart;and while (n--) printf("%hhu\t", *p++);

Program copying files incorrectly

So for an assignment in my Systems class, we have to make a program that takes a file in a given source and copies it to a given destination using one of three copyfile() functions.
When running the program in the command line, it will take in three arguments: ./cptest, the input file location, and the output file location, as well as two optional arguments: the number for which copyfile() function you would like to use as well as the buffer size.
If you choose 1 for the copyfile() function parameter, the program should copy the file using formatted I/O (file handles), and then copy the file one character at a time.
If you choose 2 for the copyfile() function parameter, the program should copy the file using integer file descriptors, and then copy the file one character at a time.
If you choose 3 for the copyfile() function parameter, the program should allocate a buffer of size equal to what size you put in for the buffer size parameter (say 1024), then use read() to read from the input file up to that many bytes at a time.
If you do not put in a third parameter (copyfile() function number), then the program will automatically use copyfile3() with whatever buffer size you decided with the fourth parameter.
If you do not enter a fourth parameter (buffer size), then the program will set it to 1024 by default and use it if necessary (not needed for copyfile1() or 2()).
Before and after each copyfile() function is called, the program uses gettimeofday() to make a timestamp. The program then makes a new timestamp to find how long the copying took using the difference in seconds and microseconds between the after timestamp and the before timestamp, then prints all this information out.
For example if I put in: ./cptest ~/My_Documents/photo.JPG ~/assig6/photo.JPG 3
The program should return:
Timestamp Before Copying:
Seconds: 1425150842, Microseconds: 914511
Timestamp After Copying:
Seconds: 1425150842, Microseconds: 927662
Copying took 0 seconds, 13151 microseconds
So now that you know what the program does, let's get down to the issue. Every time I run the programs with any of the copyfile() functions, be it 1, 2, or 3, technically speaking, the copying works fine, the file ends up in the correct destination, and the program returns all the correct information in terms of the timestamps.
However, in reality, it does not work, as when I use copyfile1(), it copies all of the bytes, but when I try to open the file - say a .jpg - it says that it can't view the file because it appears to be damaged, corrupted, or too large. When I use copyfile2() and copyfile3(), the file in the destination has only 1 KB, and when I don't pass in a third or fourth parameter, the output file has 0 KB. The same thing happens with word documents.
Is there a reason why it copies the files fine but the file is damaged in the process? It seems as though the code is right but the end result is not.
Here's the main file cptest.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include "cptest.h"
/** cptest.cpp
* A file copying program.
* Derived partially from caesar.cpp by Horstmann and Budd from big C++
*/
/** Prints usage instructions.
* #param program_name the name of this program
*/
void usage(char* program_name) {
// Prints out usage instructions if incorrect number of parameters is passed in
printf("Usage: %s infile outfile copy_function_number buffer_size \n", program_name);
}
/** Prints file opening error message
* #param filename the name of the file that could not be opened
*/
void open_file_error(char* filename) {
// Error message if unable to open the file
printf("Error opening file %s\n", filename);
}
/** Main program: copies a file.
* #param argc Number of command-line arguments (including program name).
* #param argv Array of pointers to character arays holding arguments.
* #return 0 if successful, 1 if failure.
*/
int main(int argc, char* argv[]) {
char* infilename; // Name of input file
char* outfilename; // Name of output file
int copy_function_number; // Chooses which copy function is used based on argv[3]
int buffer_size; // Size of buffer
int returnstatus; // 0 or 1 depending on success or failure to copy the file to the destination
struct timeval* before = malloc(sizeof(struct timeval)); // Struct for time before copying is done
struct timeval* after = malloc(sizeof(struct timeval)); // Struct for time after copying is done
if (argc != 3 && argc != 4 && argc != 5) {
usage(argv[0]); // Must have 2, 3, or 4 arguments in addition to ./cptest.
return 1; // Failure!
}
infilename = argv[1]; // Sets first parameter to the input file name
outfilename = argv[2]; // Sets second parameter to the output file name
if(argv[3] == NULL) {
copy_function_number = 3; // Program uses copyfile3 if no third parameter is entered
}
else {
copy_function_number = atoi(argv[3]); // Otherwise program uses whatever function is passed by third parameter
}
if (argv[4] == NULL) {
buffer_size = 1024; // Sets buffer size to 1024 if no fourth parameter is entered
}
else {
buffer_size = atoi(argv[4]); // Otherwise buffer size is whatever user enters as fourth parameter
}
if (copy_function_number == 1) {
gettimeofday(before, NULL); // Get timestamp before the copying
// Perform the copying with copyfile1() if the third parameter is 1
returnstatus = copyfile1(infilename, outfilename);
gettimeofday(after, NULL); // Get timestamp after the copying
}
if (copy_function_number == 2) {
gettimeofday(before, NULL); // Get timestamp before the copying
// Perform the copying with copyfile2() if the third parameter is 2
returnstatus = copyfile2(infilename, outfilename);
gettimeofday(after, NULL); // Get timestamp after the copying
}
if (copy_function_number == 3) {
gettimeofday(before, NULL); // Get timestamp before the copying
// Perform the copying with copyfile3() if the third parameter is 3
returnstatus = copyfile3(infilename, outfilename, buffer_size);
gettimeofday(after, NULL); // Get timestamp after the copying
}
else {
if (copy_function_number != 1 || copy_function_number != 2 || copy_function_number != 3 || argv[3] == NULL) {
gettimeofday(before, NULL); // Get timestamp before the copying
// Perform the copying with copyfile3() if no third parameter is entered
returnstatus = copyfile3(infilename, outfilename, buffer_size);
gettimeofday(after, NULL); // Get timestamp after the copying
}
}
struct timeval *copytime = difference_in_time(before, after); // Struct for time after copying is done
// Print out information of the timestamp before copying
printf("Timestamp Before Copying: \n Seconds: %d, Microseconds: %d\n", before->tv_sec, before->tv_usec);
// Print out information of the timestamp after copying
printf("Timestamp After Copying: \n Seconds: %d, Microseconds: %d\n", after->tv_sec, after->tv_usec);
// Print out information of the difference between the timestamps (how long the copying took)
printf("Copying took %d seconds, %d microseconds\n", copytime->tv_sec, copytime->tv_usec);
return returnstatus; // 0 if successful copy, 1 if unsuccessful.
}
/** Copies one file to another using formatted I/O, one character at a time.
* #param infilename Name of input file
* #param outfilename Name of output file
* #return 0 if successful, 1 if error.
*/
int copyfile1(char* infilename, char* outfilename) {
FILE* infile; //File handle for source.
FILE* outfile; // File handle for destination.
infile = fopen(infilename, "r"); // Open the input file.
if (infile == NULL) {
open_file_error(infilename); // Error message if there was a problem opening the input file.
return 1; // Failure!
}
outfile = fopen(outfilename, "w"); // Open the output file.
if (outfile == NULL) {
open_file_error(outfilename); // Error message if there was a problem opening the output file.
return 1; // Failure!
}
int intch; // Character read from input file. must be an int to catch EOF.
unsigned char ch; // Character stripped down to a byte.
// Read each character from the file, checking for EOF.
while ((intch = fgetc(infile)) != EOF) {
ch = (unsigned char) intch; // Convert to one-byte char.
fputc(ch, outfile); // Write out.
}
fclose(infile); // Close the input file.
fclose(outfile); // Close the output file.
return 0; // Success!
}
/** Copies one file to another using integer file descriptors instead of file handles, one character at a time.
* #param infilename Name of input file
* #param outfilename Name of output file
* #return 0 if successful, 1 if error.
*/
int copyfile2(char* infilename, char* outfilename) {
int infile; //File handle for source.
int outfile; // File handle for destination.
// Allocates a buffer for the chars that will be read from the input and written to the output.
char buffer[1024];
infile = open(infilename, O_RDONLY); // Open the input file.
if (infile < 0) {
open_file_error(infilename); // Error message if there was a problem opening the input file.
return 1; // Failure!
}
outfile = open(outfilename, O_WRONLY | O_CREAT); // Open the output file.
if (outfile < 0) {
open_file_error(outfilename); // Error message if there was a problem opening the output file.
return 1; // Failure!
}
int intchin; // Character read from input file. must be an int to catch EOF.
int intchout; // Character written to the output file. must be an int to catch EOF.
// Size of the buffer so that when you are copying extremely large files, it does not have to go through 200000 loop iterations
int buffer_size = 1024;
unsigned char ch; // Character stripped down to a byte.
// Read each character from the file, checking for 0.
while ((intchin = read(infile, buffer, buffer_size)) != 0) {
ch = (unsigned char) intchin; // Convert to one-byte char.
intchout = write(outfile, buffer, ch); // Write out.
}
close(intchin); // Close the input file.
close(intchout); // Close the output file.
return 0; // Success!
}
/** Copies one file to another using integer file descriptors, buffer_size characters at a time.
* #param infilename Name of input file
* #param outfilename Name of output file
* #param buffer_size Size of the buffer for reading and writing
* #return 0 if successful, 1 if error.
*/
int copyfile3(char* infilename, char* outfilename, int buffer_size) {
int infile; //File handle for source.
int outfile; // File handle for destination.
// Allocates a buffer of size buffer_size for the chars that will be read from the input and written to the output.
char* buffer = (char*) malloc(sizeof(char)* buffer_size);
infile = open(infilename, O_RDONLY); // Open the input file.
if (infile < 0) {
open_file_error(infilename); // Error message if there was a problem opening the input file.
return 1; // Failure!
}
outfile = open(outfilename, O_WRONLY | O_CREAT); // Open the output file.
if (outfile < 0) {
open_file_error(outfilename); // Error message if there was a problem opening the output file.
return 1; // Failure!
}
int intchin; // Character read from input file. must be an int to catch EOF.
int intchout; // Character written to the output file. must be an int to catch EOF.
unsigned char ch; // Character stripped down to a byte.
// Read each character from the file, checking for 0.
while ((intchin = read(infile, buffer, buffer_size)) != 0) {
ch = (unsigned char) intchin; // Convert to one-byte char.
intchout = write(outfile, buffer, ch); // Write out.
}
close(intchin); // Close the input file.
close(intchout); // Close the output file.
free(buffer); // Free the buffer that was allocated.
return 0; // Success!
}
/** Makes a new timeval struct that determines the difference between two timestamps
* #param time1 Struct containing the information for the first timestamp
* #param time2 Struct containing the information for the second timestamp
* #return The struct made using the two parameters
*/
struct timeval* difference_in_time(struct timeval* time1, struct timeval* time2) {
struct timeval* copytime = malloc(sizeof(struct timeval)); // Allocates a struct to hold the difference between the two timestamps.
if ((time2->tv_sec - time1->tv_sec) < 0) {
// Error message for if the first timestamp entered was before the second timestamp.
printf("Seconds value is negative! time1 should be before time2!\n");
}
if ((time2->tv_usec - time1->tv_usec) < 0) {
// Handles if the difference in microseconds between the second and first timestamps would be negative, subtracting 1 from the seconds.
copytime->tv_sec = (time2->tv_sec - time1->tv_sec) - 1;
// Handles if the difference in microseconds between the second and first timestamps would be negative, subtracting the difference from 1000000.
copytime->tv_usec = 1000000 - (time2->tv_usec - time1->tv_usec);
}
else {
// Otherwise the seconds for the third timestamp is the difference between the seconds of the second and first timestamps.
copytime->tv_sec = (time2->tv_sec - time1->tv_sec);
// Otherwise the microseconds for the third timestamp is the difference between the microseconds of the second and first timestamps.
copytime->tv_usec = (time2->tv_usec - time1->tv_usec);
}
return copytime; // Return the new timestamp created.
}
Here's the header file cptest.h:
#ifndef CPTEST_H
#define CPTEST_H
// function prototypes
void usage(char* program_name);
void open_file_error(char* filename);
int copyfile1(char* infilename, char* outfilename);
int copyfile2(char* infilename, char* outfilename);
int copyfile3(char* infilename, char* outfilename, int buffer_size);
struct timeval* difference_in_time(struct timeval* time1, struct timeval* time2);
#endif
And here's the makefile:
cptest: cptest.o
gcc -g cptest.o -o cptest
cptest.o: cptest.c cptest.h
gcc -c -g cptest.c
clean:
rm -f *.o cptest
docs:
doxygen
chmod a+r html/*
cp -p html/* ~/public_html/cs2303assig6
EDIT: Thought it might be easier to show you what happens using the readme.txt we need to include with our program as an example. Shortened it down to the useful information so you don't have to through more walls of text.
Original:
Name: *My name*
Section: CS2303 C01
What Program Does: *Explanation of what program does*
Example: *Example of what should show up when running program in the command line*
Results: *Test data for time it took for each function and using different buffer sizes to find most efficient function and buffer size*
Compiling:
To compile the code, use 'make' in the command line. The makefile should already link all of the .o files to the executable, so the work is done for you.
Result when using copyfile1():
so the work is done for you.S2303 C01
What Program Does: *Explanation of what program does*
Example: *Example of what should show up when running program in the command line*
Results: *Test data for time it took for each function and using different buffer sizes to find most efficient function and buffer size*
Compiling:
To compile the code, use 'make' in the command line. The makefile should already link all of the .o files to the executable, so the work is done for you.
Result when using copyfile2() and 3():
so the work is done for you.
copyfile2 and 3 are completely broken because they cast the number of characters read into a char. As the buffer size is often 1024, this cast gives a result of 0 so nothing is written.
For copyfile 1, I'd recommend opening the files with a binary flag ("rb" or "wb") although I'm not convinced that is the issue.

print out contents of archived files in C

I have the same question posted here:
How to print the name of the files inside an archive file?
but those answers don't necessarily address the problem. I have an archived file week.a and I'd like to print out the names of the files inside that archive, called mon.txt, and fri.txt.
It should work just like the ar -t command, except I'm not allowed to use that.
What I've tried:
My first attempt was to create a for loop and print out the arguments, but then I realized the file is already archived by that point, and so that wouldn't work.
My second attempt was to look at the print_contents function of ar, which I've listed below:
static void
print_contents (bfd *abfd)
{
size_t ncopied = 0;
char *cbuf = (char *) xmalloc (BUFSIZE);
struct stat buf;
size_t size;
if (bfd_stat_arch_elt (abfd, &buf) != 0)
/* xgettext:c-format */
fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
if (verbose)
printf ("\n<%s>\n\n", bfd_get_filename (abfd));
bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
size = buf.st_size;
while (ncopied < size)
{
size_t nread;
size_t tocopy = size - ncopied;
if (tocopy > BUFSIZE)
tocopy = BUFSIZE;
nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd);
if (nread != tocopy)
/* xgettext:c-format */
fatal (_("%s is not a valid archive"),
bfd_get_filename (bfd_my_archive (abfd)));
/* fwrite in mingw32 may return int instead of size_t. Cast the
return value to size_t to avoid comparison between signed and
unsigned values. */
if ((size_t) fwrite (cbuf, 1, nread, stdout) != nread)
fatal ("stdout: %s", strerror (errno));
ncopied += tocopy;
}
free (cbuf);
}
But with this route, I don't really know what a lot of that code means or does (I'm very new to C). Could someone help make sense of this code, or point me in the right direction for writing my program? Thank you.
Based on format at wikipedia.org/wiki/Ar_(Unix), the basic shape of your program will be:
fopen(filename)
fscanf 8 characters/* global header */
check header is "!<arch>" followed by LF
while not at end of file /* check return value of fcanf below */
fscanf each item in file header
print filename /* first 16 characters of file header */
check magic number is 0x60 0x0A
skip file size characters /* file contents - can use fseek with origin = SEEK_CUR */
fclose(file)
Refer to the C stdio library documentation for details of functions needed. Or see Wikipedia C file input/output
int counting(FILE *f)
{
int count=0;
rewind(f);
struct ar_hdr myheader;
fseek(f,8,SEEK_CUR);
while(fread(&myheader,sizeof(struct ar_hdr),1,f)>0)
{
long test;
test = atol(myheader.ar_size);
fseek(f,test,SEEK_CUR);
count++;
}
printf("count is : %d\n",count);
return count;
}
this code i had written to count the number of files in archive.. u can use the same to print the file names inside it as well

How to read a text file and write the content into another text file using stdio.h C library

I have written a function as follows to read a text file and write the content into another text file with a different file name:
The read file function:
char *getFileContent (const char *fileName)
{
char errorBuffer[50];
//Prepare read file
FILE *pReadFile;
long bufferReadSize;
char *bufferReadFile; //This variable is going to be returned as file content
size_t readFileSize;
pReadFile = fopen (fileName, "rb");
if (pReadFile != NULL)
{
// Get file size.
fseek (pReadFile , 0 , SEEK_END);
bufferReadSize = ftell (pReadFile);
rewind (pReadFile);
// Allocate RAM to contain the whole file:
bufferReadFile = (char*) malloc (sizeof(char) * bufferReadSize);
if (bufferReadFile != NULL)
{
// Copy the file into the buffer:
readFileSize = fread (bufferReadFile, sizeof(char), bufferReadSize, pReadFile);
if (readFileSize == bufferReadSize)
{
return bufferReadFile;
fclose (pReadFile);
free (bufferReadFile);
} else {
//fread failed
sprintf (errorBuffer, "File reading failed for file:\n%s", fileName);
MessageBox (NULL, errorBuffer, "Error file reading", MB_ICONERROR | MB_OK);
}
} else {
//malloc failed
sprintf (errorBuffer, "Memory allocation failed for file:\n%s", fileName);
MessageBox (NULL, errorBuffer, "Error memory allocation", MB_ICONERROR | MB_OK);
}
} else {
//fopen failed
sprintf (errorBuffer, "File opening failed for file:\n%s", fileName);
MessageBox (NULL, errorBuffer, "Error file opening", MB_ICONERROR | MB_OK);
}
}
The write file code:
//Get file content from read file
char *fileContent = getFileContent (readFileName);
FILE *pWriteFile = fopen (writeFileName, "wb");
fwrite (fileContent, sizeof (char), strlen (fileContent), pWriteFile);
fclose (pWriteFile);
They successfully work together to read and write files. However, in the written file, at the end of it, some strange characters come out like this:
ýýýý««««««««îþîþîþ
Please kindly help me solve this problem. How can I avoid the final strange characters in the written file when they were not there in the original file?
fwrite (fileContent, sizeof (char), strlen (fileContent), pWriteFile);
strlen() doesn't work here because fileContent contains binary data. The binary data could contain a null byte which would mean strlen() would be too short, or it may not contain a null byte which means strlen() would read past fileContent until it finds a null byte. This would be a reason why you see garbage at the end.
Note also, in your read routine, that the fclose() and the free() never happen because they come after the return statement. But, note that you can't free() the data until after you write it.
On the other hand, if it's not a binary file, all you need is a terminating 0 at the end of the data and then strlen() would work. So in your read, you need to alloc another byte and make sure that byte is zero:
bufferReadFile = (char*) malloc (sizeof(char) * bufferReadSize + 1); // note the + 1
bufferReadFile[bufferReadSize] = 0; // the terminating null byte.

Resources