Cannot include libexif in C on Kali linux - c

I'm trying to include libexif to my project in C, I add whole libexif folder to my project folder, then used ./configure and then make command as README told me to do so. Still I'm getting warnings while I try to compile my programm.
Warining:
In file included from main.c:5:
libexif-0.6.24/libexif/exif-data.h:31:10: fatal error: libexif/exif-byte-order.h: Nie ma takiego pliku ani katalogu
31 | #include <libexif/exif-byte-order.h>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
Photo of my project folder
And my code:
#include<stdlib.h>
#include<stdio.h>
#include<ncurses.h>
#include<string.h>
#include"libexif-0.6.24/libexif/exif-data.h"
//#include"DevIL/include/IL/il.h"
//Function that allow user to open folder where he want to do something with photos. It returns pointer to file with list of all files that are in folder pointed by user
FILE *openFolder(char* destination){
char c;
char *systemInput=malloc(sizeof(char)*123);
strcat(systemInput,"ls ");
strcat(systemInput,destination);
strcat(systemInput," > systemOutput.txt");
system(systemInput);
FILE *file=fopen("systemOutput.txt","r");
free(systemInput);
return file;
}
//Function that allows to show photo
void showPhoto(char* userInput, char* destination){
char *systemInput=malloc(sizeof(char)*150);
strcat(systemInput,"open ");
strcat(systemInput,destination);
strcat(systemInput,userInput);
system(systemInput);
free(systemInput);
free(userInput);
return;
}
int main(){
//defining variables
char* userInput=malloc(sizeof(char)*100);
char* destination=malloc(sizeof(char)*100);
char c;
//opening ncurses window
initscr();
refresh();
//asking user for folder path which contain photos
printw("EXIF file reader\n\n");
printw("Please enter the folder path where the photos are located:\n");
scanw("%s", destination);
FILE *file=openFolder(destination);
while(1){
clear();
printw("EXIF file reader\n\nType numer of action that you want to perform\n\n");
printw("1. Open photo\n");
printw("\n\n\n\n\n\n\n\n Press q to exit programm");
c=getch();
if(c=='1'){
clear();
userInput=malloc(sizeof(char)*100);
printw("EXIF file reader\n\n");
if(file){
while((c=getc(file))!=EOF){
printw("%c", c);
}
}
printw("\n\n");
printw("Please enter photo that you want to open:\n");
scanw("%s", userInput);
showPhoto(userInput,destination);
}
else if(c=='q'){
free(destination);
free(userInput);
endwin();
}
}
}
I'm sorry if this is some trivial problem, but I'm new to C and using external libraries.

Invalid arguments to strcat():
char *systemInput=malloc(sizeof(char)*123);
strcat(systemInput,"ls ");
The strcat() function appends the src string to the dest string,
overwriting the terminating null byte ('\0') at the end of dest,
and then adds a terminating null byte.
But the contents of systemInput are uninitialized. So this invokes undefined behaviour.
But you do not need malloc() here, just allocate an array of fixed size.
Ignoring the return value of library functions:
FILE *file=fopen("systemOutput.txt","r");
The call to fopen() might fail for around 45 different reasons. Your code should check its return value. It returns NULL to signal failure.
Similarly, you do not check the result of malloc().
Memory leak:
I do not understand the point of:
userInput=malloc(sizeof(char)*100);
This overwrites the value of userInput. You have now lost all access to the original memory and have no way to free() it. (Have leaked memory)
Double free():
You already free()d userInput in showPhoto, so why are trying to free() it again in main()? It will corrupt the heap and result in undefined behaviour (yes, again).
That being said, you have to specify some compiler options and link with the library, as this comment mentions:
I think you'll need to add something like -Llibexif-0.6.24 to your
compiler options (assuming gcc, might be different for others) so it
can pick up other exif-related header files. Do this in your Makefile
(in CFLAGS), or in your CMakeLists.txt, or whatever is appropriate for
your build system.
– #pmacfarlane

Related

Please explain What's wrong with this C code?

What I am trying is to get all the file present in a directory and then add a .enc extension to this file. Example- Let File.txt is present then I will perform some encryption related task and after that the new file name would be File.txt.enc
Here is my code:
#include <dirent.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
DIR *d;
struct dirent *dir;
char *name;
int val;
d = opendir(".");
if (d)
{
while ((dir = readdir(d)) != NULL)
{
name=dir->d_name;
printf("File Found:%s\n",name);
strcat(name,".enc");
val=rename(dir->d_name,name);
if(val==0)
printf("Encrypted File:%s\n",name);
else
perror("Error: ");
}
closedir(d);
}
return(0);
}
But I am getting a output like this......
File Found:write_pgm_img.c
Error: : No such file or directory
File Found:realloc.c
Error: : No such file or directory
File Found:getusage.txt
Error: : No such file or directory
File Found:directory.c
Error: : No such file or directory
As you can see "No such file or directory" error. But I can't understand why?? Please explain.Thanks in advance.
You are messing up pointers and memory content:
name=dir->d_name;
printf("File Found:%s\n",name);
strcat(name,".enc");
val=rename(dir->d_name,name);
After the first line, name and dir->d_name point to the same memory address. This means you try to add a suffix to the memory where dir->d_name is located.
You cannot expect that memory to be large enough to hold your suffix. (But in this case this does not cause the problem as your file names seem to be short enough)
Also your update will affect both name and dir->d_name in the same way which makes renaming pointless because you try to rename getusage.txt.enc to getusage.txt.enc
A possible solution could be:
char name[sizeof(dir->d_name)+4];
while ((dir = readdir(d)) != NULL)
{
strcpy(name, dir->d_name);
printf("File Found:%s\n",name);
strcat(name,".enc");
val=rename(dir->d_name,name);
Your name & dir->d_name have the same address. Hence strcat(name,".enc"); will update both name & dir->d_name and the source will have the prefix '.enc'
I think perhaps you're assuming that name=dir->d_name creates some new piece of data called name. It's an easy enough mistake to make, because in many programming languages that's exactly what would happen. In C though, you've just set a pointer called name to refer to the existing data called d_name.
If you want to append something to d_name, you probably need to copy it to a char * that references a piece of storage large enough to hold it, and the suffix, and the terminating null, and then copy the suffix onto the end of that new storage. Something like:
char *new_name = malloc (strlen (dir->d_name) + strlen (suffix) + 1);
strcpy (new_name, dir->d_name);
strcat (new_name, suffix);
...
free (new_name);
Probably there are many other ways to achieve the same thing. The fundamental point is that assigning pointer types in C does not allocate or duplicate storage.
Since name may not have a larger size, strcat(name,".enc"); will may write past that size and causes UB. As others point out, this does not cause the ENOENT error you get (assuming you use linux).
To fix that you have to create a new, large enough buffer and copy the new name to it. This would also fix the error you get because this way you do not overwrite the old name.

C - Unlink/Remove produces error for filenames with spaces

I am trying to make a function in C to erase all the contents of a temp folder and to erase the folder.
Whilst I already have successfully created the code to cycle through the files and to erase the folder (it is pretty much straight forward) I am having trouble erasing the files using unlink.
Here is the code that I am using:
int delete_folder(char *foldername) {
DIR *dp;
struct dirent *ep;
dp=opendir(foldername);
if (dp!=NULL) {
readdir(dp); readdir(dp);
while (ep=readdir(dp)) {
char* cell = concatenate(concatenate(foldername, "\\"), "Bayesian Estimation.xlsx");//ep->d_name);
printf("%s\n", cell);
remove(cell);
printf("%s\n", strerror(errno));
}
closedir(dp);
}
if (!rmdir(foldername)) {return(0);} else {return(-1);}
}
The code that I wrote is fully functional for all files but those which include spaces in the filename. After some testing, I can guarantee that the unlink functions eliminates all files in the folder (even those with special characters in the filename) but fails if the filename includes a space (however, for this same file, if I remove the space(s), this function works again).
Has anyone else encountered this problem? And, more importantly, can it be solved/circunvented?
(The problem remains even if I introduce the space escape sequences directly)
The error presented by unlink is "No such file or directory" (ENOENT). Mind you that the file is indeed at the referred location (as can be verified by the code outputing the correct filename in the variable cell) and this error also occurs if I use the function remove instead of unlink.
PS: The function concatenate is a function of my own making which outputs the concatenation of the two input strings.
Edit:
The code was written in Codeblocks, in Windows.
Here's the code for the concatenate function:
char* concatenate(char *str1, char *str2) {
int a1 = strlen(str1), a2 = strlen(str2); char* str3[a1+a2+1];
snprintf(str3, a1+a2+2, "%s%s", str1, str2);
return(str3);
}
Whilst you are right in saying that it is a possible (and easy) memory leak, the functions' inputs and outputs are code generated and only for personal use and therefore there is no great reason to worry about it (no real need for foolproofing the code.)
You say "using unlink()" but the code is using remove(). Which platform are you on? Is there any danger that your platform implements remove() by running an external command which doesn't handle spaces in file names properly? On most systems, that won't be a problem.
What is a problem is that you don't check the return value from remove() before printing the error. You should only print the error if the function indicates that it generated an error. No function in the Standard C (or POSIX) library sets errno to zero. Also, errors should be reported on standard error; that's what the standard error stream is for.
if (remove(cell) != 0)
fprintf(stderr, "Failed to remove %s (%d: %s)\n", cell, errno, strerror(errno));
else
printf("%s removed OK\n", cell);
I regard the else clause as a temporary measure while you're getting the code working.
It also looks like you're leaking memory like a proverbial sieve. You capture the result of a double concatenate operation in cell, but you never free it. Indeed, if the nested calls both allocate memory, then you've got a leak even if you add free(cell); at the end of the loop (inside the loop, after the second printf(), the one I deconstructed). If concatenate() doesn't allocate new memory each time (it returns a pointer to statically allocated memory, then I think concatenating a string with the output of concatenate() is also dangerous, probably invoking undefined behaviour as you copy a string over itself. You need to look hard at the code for concatenate(), and/or present it for analyis.
Thank you very much for all your input, after reviewing your comments and making a few experiments myself, I figured out that remove/unlink was not working because the filename was only temporarily saved at variable cell (it was there long enough for it to be printed correctly to console, hence my confusion). After appropriately storing my filename before usage, my problem has been completely solved.
Here's the code (I have already checked it with filenames as complex as I could make them):
int delete_folder(char* foldername) {
DIR *dp;
struct dirent *ep;
dp=opendir(foldername);
if (dp!=NULL) {
readdir(dp); readdir(dp);
while (ep=readdir(dp)) {
char cell[strlen(foldername)+1+strlen(ep->d_name)+1];
strcpy(cell, concatenate(concatenate(foldername, "\\"), ep->d_name));
unlink(cell);
printf("File \"%s\": %s\n", ep->d_name, strerror(errno));
}
closedir(dp);
}
if (!rmdir(foldername)) {return(0);} else {return(-1);}
}
I realize it was kind of a noob mistake, resulting from my being a bit out of practice for a while in programming in C, so... Thank you very much for your all your help!

Simple History To Remember Last Command Executed

I am trying to simulate a shell terminal in c, one of the functionalities is to be provide a simple memory to remember the last command executed. So how I am going about is:
Every time the user enters a command (String) the string is saved in a file (command_histroy.txt)
If the user enters "r" (command=="r"), the terminal calls the function getSavedCommand(), as I am only saving only one command so my function is:
char* getSavedCommand(void){
char cmd[1000];
int i=0;
char* filename = "files/command_history.txt";
FILE* file = fopen(filename,"r");
if(file!=NULL){
int c;
do{
c = fgetc(file);
cmd[i]=c;
i++;
} while (c != EOF);
}else{
puts("Error Reading file");
}
return cmd;
}
So as in the file "command_history.txt", there is only one line stored, I reassumed that it would return this one line in an array of chars. To test I printed the results:
cmd = getSavedCommand();
printf("|%s|",cmd);
And the result I get is:
arj#arj-Inspiron-1545:~/projet$ ./a.out
|ls -l /home/arj
�|
arj#arj-Inspiron-1545:~/projet$
What I want is:
|ls -l /home/arj|
I think the EOF is creating the problem. Can someone help me?
One of the problem is you don't null terminate your array before returning. You need something like cmd[i] = '\0' at the end.
One more serious problem is you are returning a pointer to an object that is destroyed when the function returns. cmd object has automatic storage and is destroyed at the end of the function. Use malloc to allocate the array, or pass a pointer to the array as the argument of your getSavedFunction.
This functionality (plus command line edition, and a slew of other goodies) is the whole point of GNU readline (if on Linux, it is probably provided as a prebuilt package) or its BSD clone libedit (probably already available on BSD Unix).

'fopen' in C can't open existing file in current directoy on Unix

I am using fopen(3) in C to read file and process it. The file is present in current working directory where the binary exists, but I am unable to read the file (Linux environment / Cygwin environment).
Here is the sample code:
C code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
FILE *inFile;
static char fileName[255];
int process_file(FILE *inFile)
{
char ch;
inFile = fopen(fileName,"r");
if (inFile == NULL)
{
perror(fileName);
exit(1);
}
else
{
// Process file
}
fclose(inFile);
return 0;
}
int main(int argc, char *argv[])
{
printf("Enter filename to process \n");
scanf("%s", fileName);
process_file(inFile);
getchar();
return 0;
}
I have file permissions set to 777 in the current directory. The resulting binary as well as my source code reside in this directory where the input file exits. Why is the file not opened?
Update :
This question was written in few years back and this code could be improved a lot.
1. The process file should accept char * or char array instead of file pointer
2. unused variables can be removed
3. unused libraries or include files can be removed
4. Can make use of argv to accept filename with path from cmdline
5. return instead of exit in process_file and also proper return code instead of returning 0 from process_file.
I should have asked this question little more elaborate...
I had three functions to process the same file, like process_fil1e1(), process_file2() and process_file3() even though I called fclose() in all three functions. Somehow the file handle was not closed that properly or the file pointer pointed to EOF or some undefined behavior. It was not working fine.
When I used a single process file and rewind() together, it worked fine...
Be sure to input file name with its extension. This may cause problems with reading the file.
If you know the extension of the file you can input only the name and after that make the program add the extension. After scanf("%s", fileName); add strcat(fileName, ".txt"); if you want to enter only the name without extension and the file you read has extension .txt.
Your inFile and fileName variables are extern so you don't need to have arguments for the function process_file();, any function can access those variables.
You can change function int process_file(); to void process_file(); and delete return 0, you don't need that.
You have declared the inFile and fileName as global. You should change your function prototype from
int process_file(FILE *inFile)
to
int process_file()
This would at least make your program more clear. Now regarding your problem: It would almost certain be that you are doing something wrong in the input file (like not putting in the file extension) in your input. Remember, you need to pass the complete file name (including the extension which on some systems like Windows (by default) would be hidden). Otherwise, the logic looks correct to me, and it should work fine.

fopen doesn't open

I am using Code::Blocks and have set the command-line arugments via the IDE. I have also opened the executable with the proper argument and I can't manage to get a non-NULL on fopen() return. I've tried hard-coding the filename also with no success. The platform is Windows XP SP3.
The first is the one that fails, when i hardcoded it i used double backlash. Also i never knew if the second works because i never managed to start the process by opening the first one.
Obviously i put the text file in the same directory that the executable and rebuilt the executable many times, but it still doesn't work.
EDIT: I added the perror("fopen"); line in the if(finput==NULL) block. This is the output.
http://prntscr.com/h71pa
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define first_part_url "[url=http://magiccards.info/query?q="
#define second_part_url "&v=card&s=cname]"
#define end_bracket "[/url]\n"
#define output_file_prefix "output_"
char* get_card(FILE* finput);
int main(int n, char* arguments[])
{
FILE* finput;
FILE* foutput;
short int counter;
char* output_filename;
char* finalstring;
for(counter=1; counter<n; counter++)
{
finput=fopen(arguments[counter], "r");
if (finput==NULL)
{
printf("Unable to open ");
puts(arguments[counter]);
perror("fopen");
break;
}
strcpy(output_filename, output_file_prefix);
strcat(output_filename, arguments[counter]);
if((foutput=fopen(output_filename, "w"))==NULL)
{
printf("There was an error while trying to open ");
puts(arguments[counter]);
printf(" .\n");
break;
}
while(!feof(finput))
{
finalstring=get_card(finput);
fputs(finalstring, foutput);
while(((fgetc(finput))!='\n')||feof(finput));
}
printf("Autocarding ");
puts(arguments[counter]);
printf(" was a success.\n");
fclose(foutput);
}
if(finput!=NULL)
{
fclose(finput);
free(finalstring);
}
return 0;
}
char* get_card(FILE* finput)
{
char* currentcard;
char* finalstring;
currentcard=(char*)malloc(sizeof(char)*150);
fgets(currentcard, 150, finput);
/* Allocates the exact amount of space needed for the final string*/
finalstring=(char*)malloc(sizeof(char)*(strlen(first_part_url)+strlen(second_part_url)+strlen(end_bracket)+strlen(currentcard)));
/* Get all the final forum link together*/
strcat(finalstring, first_part_url);
strcat(finalstring, currentcard);
strcat(finalstring, second_part_url);
strcat(finalstring, end_bracket);
free(currentcard);
return finalstring;
}
The error you are getting, "No such file or directory" indicates that the file name you're trying to open doesn't exist.
In this case, it's probably because the program's current working directory is not the same as the directory containing the executable file.
This
finput=fopen(arguments[counter], "r");
Will only fail if you do not supply correct filenames (e.g. if there are non-ASCII characters in the names or the names do not include the correct path, fopen() opens files in the current directory if no path is specified in the file name).
This
output_filename=(char*)malloc(sizeof(arguments[counter]));
most likely does not allocate enough space for a name because arguments[counter] is a pointer, and sizeof() of a pointer is not the same as strlen(that_same_pointer) + 1.
This
output_filename=output_file_prefix;
loses the just allocated memory because you are reassigning the pointer output_filename to point to some other place, output_file_prefix ("output_").
After the above this
strcat(output_filename, arguments[counter]);
is likely going to crash your program because this is going to attempt to overwrite a string literal ("output_"), doing which causes undefined behavior per the C standard.
You have to allocate enough cumulative space for the strings that you want to concatenate and you have to concatenate them in the allocated space.
To save you even more trouble, here's another problem:
finput=fopen(arguments[counter], "r");
...
while(!feof(finput))
feof() only works after at least one read from a file. This has been asked ans answered multiple times.
Try changing
for(counter=1; counter<n; ++n)
{
to
for(counter=1; counter<n; ++counter)
It appears the code loops infinitely, therefore it would exhaust the possible elements in your argument array causing a NULL pointer to be returned.

Resources