C fopen() - Possible issue with absolute path [duplicate] - c

This question already has answers here:
Returning a string from function
(3 answers)
Closed 7 years ago.
I'm currently using Code::Blocks 13.12 (compiler: GNU GCC) under Windows 10.
I'm trying to open a file and load its content, but fopen gives me troubles. The 'input.txt' exists in the same directory as my executable. I've already checked the permissions.
Function for getting the path:
char* getFileName()
{
char *fileName; /* the path of the .txt file */
char path[MAX_PATH];
/* get the path of the executable */
GetModuleFileName(NULL, path, MAX_PATH);
/* remove the name of the executable from the path */
PathRemoveFileSpec(path);
/* check case where path is directory root */
if(PathIsRoot(path))
strcat(path, "\\*");
/* add the name of the .txt file to the path */
strcat(path, "\\input.txt");
/* not sure if needed */
path[strlen(path)] = '\0';
fileName = strdup((char *) path);
return fileName;
}
Function for loading the contents of the file:
bool loadDict(char *fileName)
{
FILE *fp; /* file stream */
char line[LINE_SIZE]; /* each line of the file */
// other variables
/* try to open file for reading */
if((fp = fopen(fileName, "r")) == NULL)
{
fprintf(stderr, "Error: Could not open the file '%s' to read\n", fileName);
return false;
}
// stuff done
/* file is no longer needed, close it */
if(fclose(fp))
{
fprintf(stderr, "Error: Could not close the file '%s' to read\n", fileName);
return false;
}
return true; /* in case no problem has occured */
}
Main:
int main()
{
char *fileName;
fileName = getFileName();
/* try to load the dictionary into memory */
if(!loadDict(fileName))
{
fprintf(stderr, "Error: The dictionary could be not loaded into memory.\nProgram terminating...\n");
return 1;
}
// other stuff
return 0;
}
I'm getting both errors (could not open the file, could not load). I've already tried replacing '\' with '/' or using double slashes without success.
FILE *fp = fopen("path\\input.txt", "r");
Any help would be appreciated.

You're returning the address of a local variable in getFileName, which results in undefined behavior. This is a common pitfall in C.
You need to either: A) Allocate the string on the heap (using e.g. malloc) and return it.B) Have getFileName take a pointer to a caller-allocated buffer which it then populates.
Also, when debugging problems like this, don't just assume everything is working. Use printf to see what the value of filename is before you try to fopen it.

Your array path is a local variable whose scope is limited to function getFileName. Don't return its address .
Instead pass it from the calling function.

Related

File name variable in file path in C

So I am writing a program that uses text files. I have a line of code that goes like this.
pfw = fopen(fileName, "w");
I am trying to make that program to create a txt file in this relative path
./TextFiles/
I have no idea how to implement a fileName variable in the file path.
I usually do it like this when I have static fileName and program doesn't ask me to give it a file name or where fileName is not a variable and it works.
pfw = fopen("./TextFiles/fileName.txt", "w");
#define the relative path if configuration files are not being used
#define BASE_DIR "./TextFiles/"
char* finalName = malloc (strlen(BASE_DIR) + strlen(fileName) + 1);
if (!finalName) { /* error handling */ }
sprintf (finalName, "%s%s", BASE_DIR, fileName);
FILE* pfw = fopen(finalName, "w");
/*
...
*/
// free after usage
free (finalName);

Cannot open file with fopen(); function - C Programing [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I am trying to create a program that using the fopen(); function.
My problem is that fopen(); cannot find the file.
when i am using perror("Error"); the output is Error: No such file or directory.
I have read this articles and they did`not solved my problem:
fopen() returning a NULL pointer, but the file definitely exists
Unable to open a file with fopen()
It means i have tried to use fopen(); with the exec path to the file, and i have checked that the filename is the specific filename that i am looking for.
I have also used exec("pwd"); to see that i am the correct directory.
My OS is ubuntu mate 20.04.
Here is my Code:
/* File Name: firstTransaction.c
* File Mission: scan the input files and make the first transaction.
*/
#include "defines.h"
/*
* first transaction file:
* Allocating new memory for the assembly source file.
* Scanning the assembly source file.
* #param filename - the filename of the file that needs to be converted by the program.
* #return output and files -
* output the assembly source file in a machine code.
* return extern, entry and object files.
*/
/* function prototype */
extern char * readText(FILE * ptr, long ic, long dc); /* the function defined on assistanceFunctions.c file */
int firstTransaction(int * cf, char **av)
{
FILE * fp; /* a pointer for fopen function */
char * filteredFile = NULL;
long ic = 100, dc = 0; /* declaration and initialization of the instruction counter and current data counter */
int i = 0, j = 0; /* indexes */
int cfh = 0; /* compatible file holder */
int fileNameLength = (int)strlen(av[i]); /* computing the first filename length to allocate memory */
char * fileName = (char*) calloc(fileNameLength,sizeof (char)); /* allocating memory for the first filename */
system("pwd");
while(cf[i] != 0) /* while there is more compatible files to open */
{
cfh = cf[i]; /* cfh - compatible file holder, cf - compatible file array, set the next compatible file to cfh */
strcpy(fileName,av[cfh]); /* copy the file name from the argv array */
fp = fopen("fileName","r"); /* open the first compatible file for read */
if(fp == NULL) /* if file does not exists */
{
perror("Error"); /* print the error - why the file not opened */
i++; /* increment i by one and try to open the next filename */
}else /* if the file was opened successfully, start scanning the file */
{
/*filteredFile = */ readText(fp, ic, dc); /* calling readText function with pointer to the start of the file that was opend by fopen function */
/* while(filteredFile[j] != EOF)
{
putchar(filteredFile[j]);
j++;
}
/* DONT FORGET TO CLOSE WITH FCLOSE(); */
}
}
return 0;
}
Here is some screenshots with the tested solutions that failed from the other articles:
Edited after NeonFire answers:
My first code used fp = fopen(fileName,"r"); but my error message was made manually this way: printf("error, %s file does not exists\n", fileName); /* print error message to the user */
this cause that i did`not find my real error.
then i changed to fp = fopen("fileName","r"); and used perror("Error"); instead of the first and right way.
after i read NeonFire answers i got a new error Error: Too many open files.
i removed the backups file from the directory and i still have the same error.
Edited after Ted Lyngmo comment:
i did had to close the file to solve the - "to many file to open error".
your fp = fopen("fileName","r"); is incorrect. Remove the quotes from fileName so it refers to your variable char * fileName , not a string "fileName" :)

How to retrieve the file that is outside of current directory using format specifier?

char * read_file(char * filename) {
char * file_contents = malloc(4096 * sizeof(char));
FILE * file;
file = fopen(filename, "r");
fread(file_contents, 4096, sizeof(char), file);
fclose(file);
return file_contents;
}
char * read_flag() {
return read_file("/flag.txt"); // outside of current working directory ;)
}
int main(int argc, char* argv[]) {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
char * flag = read_flag();
char input_filename[40];
//Current directory is /home/problem
printf("Current working directory is: ");
system("pwd");
printf("Enter a filename to print the contents of the file => ");
scanf("%39s", input_filename);
while ((directory_entry = readdir(directory)) != NULL) {
if (strcmp(input_filename, directory_entry->d_name) == 0) {
printf("File contents:\n");
printf("%s\n", read_file(input_filename));
return 0;
}
}
}
I need to open a file that is outside of this directory ("/flag.txt"). I have tried something like "../" in the input to get out from this directory but it is not working. I am not sure how do i enter the filename such that it can retrieve the file that is outside of the /home/problem directory. I am currently using Ubuntu to do this. I think the idea should be using something like %s%d when i enter my input. Is this possible to use any specifier or exploit this program in order to read the entire contents?
You need to pass the full path to your file if it is outside the solution directory either with \\ or one /. On a windows based system this would be for example C:\\folder\\file.txt. I do not use linux currently, but it should be /home/folder/file.txt.
The fopen function can fail, and you should handle that. Read fopen(3), open(2), path_resolution(7), errno(3) to understand the possible failure reasons. Details could be file system and computer specific (and could include hardware failures).
I recommend using perror(3) and exit(3) on failure (don't forget to include both <stdio.h> for perror and <stdlib.h> for exit):
FILE* file = fopen(filename, "r");
if (!file) {
perror(filename);
exit(EXIT_FAILURE);
}
then you'll get a meaningful error message (into stderr) on failure
My guess: your root file system (and root directory / ...) don't have a flag.txt file and you might want to retrieve what your shell understands from ~/flag.txt. Perhaps you want to retrieve it in your home directory (then build its file path, using getenv("HOME") on Linux or Unix; see this).
Read also about globbing, and glob(7).
Read also some Linux programming book, perhaps the old ALP.

How to replace the text into a particular location of a file by passing the argument via command line argument

My intention is to read the second element in the 1st row and replace it with the value which we pass as an command line argument and replace it in the input.txt file
Input file:logic.txt
one=1234
two=3456
I want my file to be changed like this after compiling the code.
./a.out 1567
Currently i am getting output like this
./filelogic 1567
1567=1234
two=5678
Expected Output file should be modified like this after the compilation
logic.txt
one=1567
two=5678
char buf[MAXSIZE] = {};
int num = 0;
int i = 0;
num = atoi(argv[1]);
printf("%d",num);
FILE *fp1;
fp1 = fopen("logic.txt","r");//currently reading the file.
if(fp1 != NULL)
{
fseek(fp1,3,0);//Need to Move the pointer to the 3rd position where i need to replace the num(fseek(fp1,??,0))-->how we can achieve that.
//Using which method i can replace the num value into a file (means need to replace 1234 inplace of 1567)
//Once the changes are done need to replace in the same file.
fread(buf, 1, MAXSIZE, fp1);
printf("%s\n",buf);
fclose(fp1);
}else {
printf("Cannot open file"");
exit(1);
}
Could someone guide me to resolve this issue?Thanks in advance
You can make replacements to a file in-place, but you should not do this in practice. You will likely corrupt the file if you attempt to replace characters and do not make an exact one-to-one replacement of characters already in the file.
To safely change the contents of a file, read the entire file contents into memory, make the changes needed, and then truncate the current file and write the new contents to the truncated file. (if the file is too large for in-memory operations, then use a temporary file)
You do not want to use atoi to convert the string "1567" to an integer. You are replacing characters in a file, not integer values in a binary file, so work with characters instead.
Your project is complicated by only wanting to replace the text after the first '=' sign. This may or may not be on the first line of the file, so you will need some flag to indicate when the first '=' is found and the replacement is made. (once the replacement is made, you can simply break your read loop and close the file -- but below the example output all lines for convenience)
Any time you close a file after writing to it, you should validate the return of fclose to catch any stream errors, or errors that occurred on the last write that will not be apparent until the next file operation.
With those cautions and caveats in mind, you could do something similar to:
#include <stdio.h>
#include <string.h>
#define MAXSIZE 64 /* max line/buffer size */
#define FNAME "logic.txt" /* default file name */
#define REPLACE "1567" /* default replacement text */
int main (int argc, char **argv) {
char buf[MAXSIZE] = ""; /* line buffer */
const char *str = argc > 1 ? argv[1] : REPLACE; /* replacement string */
int replaced = 0; /* flag indicating replacement made */
FILE *fp = fopen (FNAME, "r+"); /* open file reading/writing */
if (!fp) { /* validate file open for reading/writing */
perror ("fopen-FNAME");
return 1;
}
while (fgets (buf, MAXSIZE, fp)) { /* read each line in file */
if (!replaced) { /* if replacement not yet made */
char *p = strchr (buf, '='); /* search for '=' in line */
if (p) { /* if found */
size_t plen = 0; /* var for length to end */
p++; /* advance past '=' sign */
plen = strlen (p); /* get length to end */
if (plen < strlen (str)) { /* check avail length */
fprintf (stderr, "error: not enough space in line.\n");
return 1;
}
strcpy (p, str); /* copy str to p */
if (fseek (fp, -plen, SEEK_CUR)) { /* backup plen chars */
perror ("fseek(fp)");
return 1;
}
fputs (p, fp); /* overwite contents with replacement */
replaced = 1; /* set flag indicating replacement */
} /* (you can break, and remove output */
} /* here if not writing to stdout) */
fputs (buf, stdout); /* output lines to stdout (optional) */
}
if (fclose (fp) == EOF) /* always validate close-after-write */
perror ("fclose-FNAME");
return 0;
}
Using your file logic.txt as an example input, and naming the executable filelogic as you have, the use and operation of the code above yields:
logic.txt File Before
$ cat logic.txt
one=1234
two=3456
Example Use/Output
$ ./filelogic
one=1567
two=3456
logic.txt File After
$ cat logic.txt
one=1567
two=3456
Again, this is fine for a learning endeavor, but in practice, avoid making changes to files in-place as the risk of inadvertent file corruption far outweighs writing a new file with the changes.

Can I pass a string into fopen()? in c

My goal is to gather input and open files based on that input.
FILE*
open_input_file (char* fileName) //opens source file to be read
{
return fopen(fileName, "r");
}
In an earlier function, I collect input from the user and save it to fileName. When I debug the program, it tells me fopen is returning NULL. That's not what I want, and I'm not sure where the problem is.
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName); // infileName is an output parameter for this
inFile = open_input_file(infileName);
}
I don't know what the problem is. Any thoughts?
If fopen returns NULL, the open failed. errno will hold the failure code and strerror(errno) will return a short description of why the open failed.
#include <errno.h>
#include <string.h>
...
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName); // infileName is an output parameter for this
if (!(inFile = open_input_file(infileName))) {
fprintf(stderr, "Error opening '%s': %s\n",
infileName, strerror(errno));
} else {
// open successful
...
}
}
Off-topic
gather_input better make sure infileName is null-terminated to prevent buffer overflows. The simplest way to do this is to define the size of the file name buffer as a macro and set the last character to 0.
#define FILENAMELEN 32
void gather_input(char infileName[]) {
...
infileName[FILENAMELEN-1]=0;
}
int main(void)
{ FILE* inFile = NULL;
char infileName[FILENAMELEN] = {'\0'};
This isn't very flexible. You could instead pass the size of the file name buffer into gather_input.
#define LENGTH(a) (sizeof(a) / sizeof(a[0]))
void gather_input(char infileName[], size_t len) {
...
infileName[len-1]=0;
}
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName, LENGTH(infileName)); // infileName is an output parameter for this
An alternative to setting the last character, if using standard string manipulation functions, is to use the strl* functions (strlcpy and strlcat) rather than their unbounded cousins. If you aren't using strl*, you should be using strncpy and strncat.
Have you checked that the file pointed to by inFilename exists on your HDD ?
Check the value of infileName in your debugger or put a printf statement to show the value on screen. printf("'%s'\n", infileName);
Did you call fclose() on your file inside the open_input_file() call. Maybe the file is still locked ?
Edit: I just checked the code. I have modified your english_to_morse() function. 1. The while statement is easier to follow than the for. 2. fgetc() returns an int and not a char.
At the top of the initialise I added this. This initialises every string in the array with and undefined string of ".??.". This will make it easier to find strange bugs as everything in your array is at least initialised.
I have modified different sections of the code but you should be able to follow.
initialize_morse_alphanum (char morseStrings[91][6])
{
for (int i=0;i<91;i++)
strcpy(morseStrings[i], ".??.");
....
....
void
english_to_morse(FILE* inputFile, FILE* outputFile, char morseStrings[91][6])
{ int convert;
convert = fgetc(inputFile);
while (convert != EOF)
{
fputs(morseStrings[convert], outputFile);
fputc(' ', outputFile);
printf ("%s ", morseStrings[convert]);
convert = fgetc(inputFile);
}
}
open_output_file (char* fileName) //opens destination file to be written
{ FILE* handle = NULL;
handle = fopen (fileName, "w"); <---- Remove the * from filename
return handle; }
Also, as mentioned in a different answer, it would be good to add some bounds checks to different areas of the code. At the moment it is quite prone to crashing. If my input file contains a lowercase 'a' (ascii 96) your program will be accessing memory that is out of bounds. So you should add a line like if (convert >= '0' && convert <= 'Z') in there somewhere. I will let you work that out.
Make sure that gather_input works properly. Could it be a problem because you're trying to read a file you're also writing on? In this case, try to close and open again the stream.

Resources