archive file extracting in c - c

I'm just trying write c code like tar command in unix. my problem is extracting of archive file. you will see close end of file comment "problem here" . im trying extract archive file. this is binary file. first byte is give us number of files. second byte is first file's names length. example "file.c" length is 6. third byte is first file's name string.so "file.c". and start second file's informations......going last file's informations. so finally start each file contain after and after.
archive file = N-I1-I2....-Ik-B1-B2....-Bk
I = L-S-Z
N is number of files.1 byte
I is information about files.
B is file contains.
L is length of filename. 1 byte
S is filename string
Z is file size
so , i can read N,L,S from binary file but not Z! i couldnt find it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#define BUFSIZE 4096
struct stat st;
struct inputfiles{
int numchar;
char *filename;
unsigned int filesize;
}file[255];
struct outputfiles{
int num_char;
char *file_name;
unsigned int file_size;
}outfile[255];
int main(int argc,char *argv[])
{
int copyfile(char *,char *);
int i,j,k,m,h;
int input_file,output_file;
int fd;
int infile,outfile,arcfile;
char buffer[BUFSIZE];
char n;
char flength;
unsigned int file_len;
char *f_name;
char tempsize;
unsigned int sizeoffile;
ssize_t nread,xread;
input_file=argc-3;
if(argc<=2)
{
fprintf(stderr,"Error: you must enter least 3 argument\n");
exit(1);
}
else if(strcmp(argv[1],"-c")==0)
{
if((outfile=open(argv[2],O_WRONLY | O_CREAT,0644))==-1)
{
fprintf(stderr,"Error: Archive file can't open %s\n",argv[2]);
remove(argv[2]);
exit(1);
}
/*** write number of files into the archive file ***/
write(outfile,(char*)&input_file,sizeof(char)); //UPDATED
j=0;
for(i=3;i<argc;i++)
{
file[j].numchar=strlen(argv[i]);
/**** write filename size into archive file ****/
write(outfile,(char*)&file[j].numchar,sizeof(char)); //UPDATED
file[j].filename=malloc(sizeof(file[j].numchar));
strcpy(file[j].filename,argv[i]);
/**** write filename into the archive file ****/
write(outfile,file[j].filename,file[j].numchar);
stat(argv[i],&st);
file[j].filesize=st.st_size;
/**** write size of file into the archive file ****/
write(outfile,&file[j].filesize,sizeof(int)); //UPDATED HERE IS 4 BYTES
j++;
}
for(m=3;m<argc;m++)
{
if((infile=open(argv[m],O_RDONLY))==-1)
{
fprintf(stderr,"Error: File can't open %s\n",argv[m]);
exit(1);
}
while((nread=read(infile,buffer,BUFSIZE))>0)
{
if(write(outfile,buffer,nread)<nread)
{
fprintf(stderr,"Error : input file size too much\n");
}
if(nread==-1)
{
fprintf(stderr,"Error occurred while reading.\n");
exit(1);
}
}
}
}
/******* Extracting Archive File *********/
else if((strcmp(argv[1],"-x")==0))
{
if(argc!=3)
{
fprintf(stderr,"Error : you must enter 3 argument for extract \n");
exit(1);
}
else
{
if((arcfile=open(argv[2],O_RDONLY))==-1)
{
fprintf(stderr,"Error:File can't open %s\n",argv[2]);
remove(argv[2]);
exit(1);
}
read(arcfile,&n,sizeof(char)); //read first byte of archive file
output_file=(int)n; // get number of output files
printf("there is a %d files.\n",output_file);
for(m=0;m<n;m++) //loop for get information about each output file
{
read(arcfile,&flength,sizeof(char)); //read second byte
file_len=((int)flength); //get filename length
f_name=malloc(file_len+1); //malloc for filename
read(arcfile,f_name,file_len); //read size of filename length bytes and get filename string
read(arcfile,&tempsize,sizeof(char)); //read size of file <--- problem here
sizeoffile=(int)tempsize;
printf("file name length: %d\n",file_len);
printf("file name: %s\n",f_name);
printf("file size: %d\n",sizeoffile);
}
}
}
else {
fprintf(stderr,"invalid command line\n");
exit(1);
}
}

When you write out the filename and file sizes, you are writing them as ints, taking up 4 bytes:
write(outfile,&file[j].numchar,sizeof(file[j].numchar) /* = sizeof(int) */);
...
write(outfile,&file[j].filesize,sizeof(file[j].filesize) /* = sizeof(int) */);
but when you read them back out, you expect them to be chars, taking up a single byte:
read(arcfile,&flength,sizeof(char));
...
read(arcfile,&tempsize,sizeof(char));
Try either writing out the size as a single byte, or better, just use 4 bytes for the filename and file sizes. (better because then you don't have to worry about files and filenames being too long)
To write out the file name and lengths as single bytes, cast them to chars:
char to_write = file[j].numchar;
write(outfile, &to_write, sizeof(char));
...
to_write = file[j].filesize;
write(outfile, &to_write, sizeof(char));

i got it.problem is my struct definiton. i gotta define unsigned char numchar, not int numchar!. finally. thanks your help my friend.

Related

Bad file descriptor error by working on files

C.
bad file descriptor error by working on files.
This is an assignment for college. I need to compress file txt and then to uncompress it. The compress method working fine
and it compresses by the idea that the last binary digit (Msb) is zero always in any ASCII char.
Does anybody know why it happens?
The problem happens when I do fgetc(input_file_8to7) in the uncompress method
The mainly problem is that i get -1 from the 2 fgetc(input_file_8to7) in uncompresd method
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdint.h>
the input for the uncompress is the output of the compress , the input is txt file that conatain the next 2 lines:
A hex dump is a hexadecimal view of computer data, from memory or from a computer file.
***compres method***
void compress8to7(FILE *input,FILE* output8to7)
{
// 0x00 87 00 87 00 87 00 87 ll
uint64_t magic=0x87008700870087ll;
uint64_t inputsize=0;
fwrite(&magic,sizeof (magic),1,output8to7);
fwrite(&inputsize,sizeof(inputsize),1,output8to7);
unsigned char st;
unsigned char st2;
char check;
char check2;
char shift=7;
char shift_st=0;
unsigned char inbfile;
// will contain the resullt of the asked new binary lines comprees
int breakflag=0;
int breakflag2=0;
int cnt=-1;
//this parameter will help to know when we dont need to move 1 back in
the pointer of input file
while(1) {
cnt++;
if (ftell(input)>1 && cnt%7!=0) //
{
fseek(input,-1 ,SEEK_CUR) ;
}
check = fgetc(input);
st=check;
if(check2==EOF){breakflag2=1;}
check2 = fgetc(input);
> //if the length is odd number check2 will get the eof
st2=check2;
if(check==EOF){breakflag=1;}
st2=st2<<shift;
> //move the digit to the right position
bit manipulation
st=st>>shift_st;
shift_st++;
if(shift_st==7)
{shift_st=0;}
shift=shift-1;
if(shift==0)
shift=7;
if(breakflag2!=1)
{inbfile=st2|st;
}else{ inbfile=st; }
fwrite(&inbfile, sizeof(inbfile),1,output8to7);
write to the file
if(feof(input))
{
inputsize= ftell(input);
fseek(output8to7,8,SEEK_SET);
fwrite(&inputsize,sizeof (inputsize),1,output8to7);
// if(breakflag==1)
break;}
}
}
*** uncompress method***
the problem is in this method
void uncompress8to7 (FILE *input_file_8to7 ,FILE *output_file_txt){
char st;
char st2;
char check;
char check2;
char shift2 = 7;
char shift_st = 0;
char shift_helper=7;
char shift_helper2=6;
char sthelper;
char sthelper2;
char inbfile; // will contain the resullt of the asked new binary lines comprees
int breakflag = 0;
int breakflag2 = 0;
int cnt = -1;//this parameter will help to know when we dont need to move 1 back in the pointer of input file
rewind(input_file_8to7);
printf("%d",ftell(input_file_8to7));
fseek(input_file_8to7,16,SEEK_SET);
printf("\n%d",ftell(input_file_8to7));
int a=0;
while(1) {
cnt++;
if(cnt>1) //
{fseek(input_file_8to7,-1 ,SEEK_CUR);}
printf("\n%d",ftell(input_file_8to7));
from that fgetc i get the bad file descriptor erorr
check = fgetc(input_file_8to7);
if(ferror(input_file_8to7)){
perror("eror by perror");
printf("file erorr");}
// printf("\n%d",ftell(input_file_8to7));
st = check;
check2 = fgetc(input_file_8to7);
st2 = check2;
if(cnt<2)
fseek(input_file_8to7,0,SEEK_SET);
if(check2==EOF){
breakflag2 = 1;
}
sthelper2=st2;
sthelper2=sthelper2>>shift_helper2;
st2=st2<<shift2;
st2=st2>>shift2;
sthelper=st;
sthelper=sthelper>>shift_helper;
sthelper=shift_helper<<shift_helper-1;
st=st<<shift_st;// to make all zero after the msb
st=st>>shift_st;// to make all zero after the msb
shift_helper2--;
if(shift_helper==-1)
{shift_helper2=6;}
shift_helper--;
if(shift_helper==-1){
shift_helper=7;
}
shift_st++;
if(shift_st==7)
{shift_st=0;}
shift2=shift2-1;
if(shift2==0)
shift2=7;
if(breakflag2==1)
{break;}
if(cnt%7==0){
inbfile=st;
}else{
inbfile=sthelper|st2;
}
writing to the file
fwrite(&inbfile,sizeof(inbfile),1,output_file_txt);
break the loop when we got to the end of file
if(feof(input_file_8to7))
{ break;}
}
}
***main***
int main(int argc, char **argv) {
char* input=NULL;
char* output8to7=NULL;
input=argv[1];
output8to7=argv[2];
open files
FILE* inputfile = fopen(input, "r");
if(inputfile==NULL)
{
printf("couldnt open input file ");
exit(-1);
}
FILE* file8to7=fopen(output8to7, "wb");
if(file8to7==NULL)
{
printf("couldnt open output file");
printf(output8to7);
exit(-1);
}
compress
compress8to7(inputfile,file8to7);
FILE* file8to7input=fopen("exampleout.bin", "ab");
FILE* output_file=fopen("UNoutput_file2.txt", "wb");
if(output_file==NULL)
{printf("couldnt open output file");
exit(-1);
}
uncompress8to7(file8to7input,output_file);
fclose(output_file);
fclose(file8to7input);
fclose(inputfile);
fclose(file8to7);
return 0;
}
This is the code to open the file:
FILE* file8to7input=fopen("exampleout.bin", "ab");
This opens it as an output file in append mode. You're trying to read from it in the uncompress8to7() function. You need to open it as in input file in read mode. Change that line to:
FILE* file8to7input=fopen("exampleout.bin", "rb");

How to print a substring in C

simple C question here!
So I am trying to parse through a string lets say: 1234567W
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
//pointer to open file
FILE *op;
//open file of first parameter and read it "r"
op = fopen("TestCases.txt", "r");
//make an array of 1000
char x[1000];
char y[1000];
//declare variable nums as integer
int nums;
//if file is not found then exit and give error
if (!op) {
perror("Failed to open file!\n");
exit(1);
}
else {
while (fgets(x, sizeof(x), op)) {
//pounter to get the first coordinate to W
char *p = strtok(x, "W");
//print the first 3 digits of the string
printf("%.4sd\n", p);
}
}
return 0;
My output so far shows: "123d" because of the "%.4sd" in the printf function.
I now need to get the next two numbers, "45". Is there a regex expression I can use that will allow me to get the next two digits of a string?
I am new to C, so I was thinking more like "%(ignore the first 4 characters)(print next 2 digits)(ignore the last two digits)"
input: pic
output: pic
Please let me know.
Thanks all.
printf("Next two: %.2s\n", p + 4); should work.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
//pointer to open file
FILE *op;
//open file of first parameter and read it "r"
op = fopen("TestCases.txt", "r");
//make an array of 1000
char x[1000];
char y[1000];
//declare variable nums as integer
int nums;
//if file is not found then exit and give error
if (!op) {
perror("Failed to open file!\n");
exit(1);
}
else {
while (fgets(x, sizeof(x), op)) {
//pounter to get the first coordinate to W
char *p = strtok(x, "W");
//print the first 3 digits of the string
printf("%.4sd\n", p);
printf("Next two: %.2s\n", p + 4);
}
}
return 0;
}
Side note: I added a missing stdio.h include. Please turn on compiler warnings, since this error would've been caught by them.

Tried to call text file and copy the text file to my new variable in C programming

my text file is "Foo bar!!", name foo.txt
So i want to create a new variable in my main function and copy the text file into new variable.
#include <stdio.h>
#include <stdlib.h>
FILE *fopen_with_error (const char *f, const char *mode){
FILE *fp;
if((fp = fopen(f,mode)) == NULL){
printf("Error opening %s\n",f);
exit(EXIT_FAILURE);
}
return fp;
}
int main(int argc, char* argv[]){
FILE *fp;
int a, num;
if(argc != 2){
printf("Usage: program input file\n");
return 0;
}
fp = fopen_with_error(argv[1],"rb");
}
I want to store the copied text into 'a' variable.
I tried to use fread function but everytime i try, it fails somehow.
In addition to using stat to obtain the number of bytes in the file to accurately size your buffer for reading the file into a single variable, you can also use fseek and ftell to accomplish the same thing.
The bigger issue is that you post the contents of a text file with a single-line (e.g. "Foo bar!!") and then proceed to explain you want to read the entire file into a variable. For binary input, that makes more sense. For text, you generally want to read and store individual lines rather than a file-at-once.
(you can store an entire text file line-by-line by using a pointer to pointer to char and allocating pointer and then storage for each line)
Now, don't get me wrong, you can do either, but if you need specific information from each line, and the lines differ in length, etc.., it is a whole lot easier to iterate over pointers than it is trying to scan through one giant buffer of text picking out newlines. You can think through what you need to do with the data you read from the file and make the call.
As your question is written, the basic approach is simply to open the file in binary mode, fseek forward to the end of file, use ftell to report the number of bytes in the file, allocate/validate memory to hold the file, and then read the file using fread into the allocated block of memory. (note: mmap provides another option as well)
Putting that pieces together, you could do something like the following:
#include <stdio.h>
#include <stdlib.h>
char *read_file (char* fname, size_t *nbytes)
{
long bytes = 0;
char* file_content;
FILE *file = fopen(fname, "rb");
if (!file) /* validate file open for reading */
return NULL;
fseek (file, 0, SEEK_END); /* fseek end of file */
if ((bytes = ftell (file)) == -1) { /* get number of bytes */
fprintf (stderr, "error: unable to determine file length.\n");
return NULL;
}
fseek (file, 0, SEEK_SET); /* fseek beginning of file */
/* allocate memory for file */
if (!(file_content = malloc (bytes))) { /* allocate/validate memory */
perror ("malloc - virtual memory exhausted");
return NULL;
}
/* read all data into file in single call to fread */
if (fread (file_content, 1, (size_t)bytes, file) != (size_t)bytes) {
fprintf (stderr, "error: failed to read %ld-bytes from '%s'.\n",
bytes, fname);
return NULL;
}
fclose (file); /* close file */
*nbytes = (size_t)bytes; /* update nbytes making size avialable */
return file_content; /* return pointer to caller */
}
int main (int argc, char **argv) {
size_t nbytes;
char *content;
if (argc < 2) { /* validate required argument givent */
fprintf (stderr, "error: insufficient input. filename req'd.\n");
return 1;
}
if ((content = read_file (argv[1], &nbytes))) { /* read/validate */
printf ("read %zu bytes of data from %s\n"
"------content------\n%s\n-------------------\n",
nbytes, argv[1], content);
free (content);
}
return 0;
}
Example Input File
$ cat dat/foo.txt
"Foo bar!!"
Example Use/Output
$ ./bin/freadbinfoo dat/foo.txt
read 12 bytes of data from dat/foo.txt
------content------
"Foo bar!!"
-------------------
Don't forget to use a memory use & error checking program (like valgrind on Linux) to insure there are no memory errors and that you have freed all memory you have allocated.
Here's a simple example of how to do this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
int main(int argc, char **argv) {
char *fname = "./someFileNameHere";
struct stat st;
stat(fname, &st);
char *content = malloc(st.st_size+1);
content[st.st_size] = 0;
FILE *infile = fopen(fname, "rb");
size_t read = fread(content, sizeof(char), st.st_size, infile);
fclose(infile);
puts(content);
return 0;
}
I've left all of the necessary error handling to you.

C language help:How to store strings from a .txt file into a character array? This .txt file is read from a command line argument btw.

I need to create a program that will read in a .txt file using the command line arguments and then encrypt the message in that txt file.
I used pointer to open the txt file and I opened it successfully. But I need to store the message (consists of many paragraphs) into an array of single characters so that I can start my encryption.
For example, if the message is: I love dogs
I want to store that message into an array of characters such as:
char word[5000];
char word[0] = I;
char word[1] = l;
char word[2] = o;
etc....
I tried to use a for loop to store the message into single character array, but when I tried to print out the array it does not show on my command line.
How can I store the message from the .txt file into a single character array?
this is my code:
int main(int argc, char*argv[])
{
int a;
printf("The number of arguements is :%d \n", argc);
for(a=0; a<argc; a++)
{
printf("argc %d is %s \n",a, argv[a]);
}
//This section uses file pointer to read from a text file and then display it
printf("\n");
char * fname= argv[1];
FILE *fptr= fopen(fname, "r");
char word[5000];
int c;
if (fptr==0)
{
printf("Could not open file\n");
}else
{
printf("FILE opened successfully \n");
}
while (fgets(word, 5000, fptr) !=NULL)
{
printf("%s \n", word);
}
fclose(fptr);
Your while loop uses fgets that is intended to read line by line. If you want an array of characters that represents the bytes of the file, use fread. First you'll need to know how big the file is; use stat or fstat for that.
#include <stat.h>
struct stat statbuf;
int FS;
char* buffer
if (fstat(fileno(fptr),&statbuf)){
... handle error
}
FS = statbuf.st_size;
Then, for the file size now in FS, allocate some bytes
buffer = (char*) malloc(FS)
Then read the contents
fread(buffer, 1, FS, fptr)

reading first line of a file in c

I am very new to C and I am having trouble with the most fundamental ideas in C. We are starting structures and basically the assignment we are working on is to read a delimited file and save the contents into a structure. The first line of the file has the number of entries and alls that I am trying to do at the moment is get the program to read and save that number and print it out. Please do not assume I know anything about C I really am very new to this.
This code is giving me a segmentation fault
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct info{
char name[100];
char number[12];
char address[100];
char city[20];
char state[2];
int zip;
};
int strucCount;
char fileText[1];
int main(char *file)
{
FILE *fileStream = fopen(file, "r");
fgets(fileText, 1, fileStream);
printf("\n%s\n",fileText);
fclose(fileStream);
}
Here is the sample file
4
mike|203-376-5555|7 Melba Ave|Milford|CT|06461
jake|203-555-5555|8 Melba Ave|Hartford|CT|65484
snake|203-555-5555|9 Melba Ave|Stamford|CT|06465
liquid|203-777-5555|2 Melba Ave|Barftown|CT|32154
Thanks for everyones comments, they helped a lot, sorry to Jim. I am working on very little sleep and didn't mean to offend anyone, I am sure we have all been there haha.
SUGGESTION:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINE 80
#define MAXRECORDS 10
struct info{
char name[100];
char number[12];
char address[100];
char city[20];
char state[2];
int zip;
};
int
main(int argc, char *argv[])
{
FILE *fp = NULL;
int nrecs = 0;
char line[MAXLINE];
struct info input_records[MAXRECORDS];
/* Check for cmd arguments */
if (argc != 2) {
printf ("ERROR: you must specify file name!\n");
return 1;
/* Open file */
fp = fopen(argv[1], "r");
if (!fp) {
perror ("File open error!\n");
return 1;
}
/* Read file and parse text into your data records */
while (!feof (fp)) {
if (fgets(line, sizeof (line), fp) {
printf("next line= %s\n", line);
parse(line, input_records[nrecs]);
nrecs++;
}
}
/* Done */
fclose (fp);
return 0;
}
fclose(fileStream);
}
Key points:
Note use of "argc/argv[]" to read input filename from command line
line, nrecs, etc are all local variables (not globals)
Check for error conditions like "filename not given" or "unable to open file"
Read your data in a loop, until end of input file
Parse the data you've read from the text file into an array of binary records (TBD)

Resources