could not stat file - c - c

I need to stat a file to get the size of it. I also need to provide the name of the file as a command line argument. This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
int main (int argc, char* argv[])
{
int N = 300;
int L = 1000;
char Nseq[N][L];
FILE *myfile;
char *token;
const char s[2] = ",";
char *line;
int lenline;
char filename[100];
strcpy(filename, "/path/");
char name[100];
strcpy(name, argv[1]);
strcat(filename, name);
strcat(filename, ".txt");
printf("%s\n", filename);
int err;
struct stat st;
int n = 0;
err = stat(filename,&st);
if (err < 0) {
printf("could not stat file %s", filename);
exit(1);
}
lenline = st.st_size + 1;
line = malloc(lenline);
myfile = fopen(filename, "r");
if (myfile == NULL) {
printf("could not open file %s", filename);
exit(1);
}
while (fgets(line, lenline, myfile) != NULL) {
token = strtok(line, s);
while (token != NULL && n<N) {
strcpy(Nseq[n], token);
printf("%s\t%u\n", token, n);
token = strtok(NULL, s);
n++;
}
}
fclose(myfile);
return 0;
}
The output I get is:
/path/file.txt
could not stat file /path/file.txt
Does anyone know why is this happening?
how can I fix it?
thank you!

The manual page of stat (2) says: On success, zero (0) is returned. On error, -1 is returned, and errno is set appropriately.
You don't actually use errno and basically are causing your own error message to be a rather unhelpful variant of "something went wrong".
Actually use errno, implicitly by calling
perror("stat");
or explicitly by calling
fprintf(stderr, "could not stat file %s: %s", filename, strerror(errno));

The underlying problem, most likely, is that you're prepending /path and appending .txt and there is no actual file at the path you're constructing before calling stat. If you focus only on successfully stating the file, try this:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
int main (int argc, char** argv) {
const char* filename = argv[1];
printf("Calling stat(%s)...", filename);
int err;
struct stat st;
err = stat(filename, &st);
if (err < 0) {
printf("failed with error %d (%s)\n", err, strerror(errno));
return err;
} else {
printf("succeeded\n");
return 0;
}
}
At the very least you'll see exactly why stat is failing and it will help show why you're code isn't working properly.

Related

Unable to read from file from argv

I am trying to read from a file, and here is my code, but as I run my code nothing shows up. Have I used the getline() function incorrectly? I can not understand my problem.
const char *READ = "r";
/**
* main - Entry point of my program
*
* Return: On success, it returns 0. On
* error it returns -1
*/
int main(int ac, char **av)
{
FILE *fpointer;
char *lineptr = NULL;
size_t *n = 0;
int line_number = 1;
if (ac != 2)
{
fprintf(stderr, "USAGE: monty file\n");
exit(EXIT_FAILURE);
}
fpointer = fopen(av[1], READ);
if (fpointer == NULL)
{
fprintf(stderr, "Error: Can't open file %s\n", av[1]);
exit(EXIT_FAILURE);
}
while (getline(&lineptr, n, fpointer) != -1)
{
printf("Line %d: %s\n", line_number, lineptr);
line_number++;
}
return (0);
}
getline(&lineptr, n, fpointer) returns -1. You did not explicitly check this and print an error message.
Checking errno it's because of EINVAL: invalid argument. Also good to check errno.
Reason is that n is NULL, while a pointer to an existing size_t is required.
BTW, indenting with 8 spaces is rather uncommon; I'd stay with 4 space. (Also, never use TAB characters.)
It's advisable to stick with extremely common argc and argv.
Nice you put {s on a further empty line; I like that style.
You'd get this:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
const char *READ = "r";
int main(int argc, char **argv)
{
FILE *fpointer;
char *lineptr = NULL;
size_t n;
int line_number = 1;
if (argc != 2)
{
fprintf(stderr, "USAGE: monty file\n");
exit(EXIT_FAILURE);
}
fpointer = fopen(argv[1], READ);
if (fpointer == NULL)
{
fprintf(stderr, "Error: Can't open file '%s'.\n", argv[1]);
exit(EXIT_FAILURE);
}
if (getline(&lineptr, &n, fpointer) == -1)
{
printf("Failed to read file '%s': %s.\n", argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
do
{
printf("Line %4d: %s\n", line_number, lineptr);
line_number++;
}
while (getline(&lineptr, &n, fpointer) != -1);
return (0);
}
Declaration of getline:
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
As an output parameter, the type of n is size_t *. It points to a space for writing by getline.
But in your code, n points to 0, which is NOT a vaild addr to write in.

Unable to save a char array using fprintf()

I am unable to save a char array using fprint() and i cannot figure out why. The below codes compliles correctly but saves nothing to file. Please advise.
static char bitSpecial[100];
int main(int argc, char *argv[]) {
FILE *fp
fp = fopen(thefilename, "w+");
if (fp == NULL) {
printf("I couldn't open file for writing.\n");
exit(0);
}
/* populate bitSpecial one character at the time and verify array is full */
fprintf(fp,"%s", bitSpecial);
if (fclose(fp) != 0) puts("Unable to close the file");
return
}
It'll be easier to identify the problem with the full code. I tried the following snippet and it worked:
#include <stdio.h>
#include <string.h> // for strerror
#include <errno.h> // for errno
static char bitSpecial[100];
int main(int argc, char *argv[])
{
char * thefilename = "test";
FILE *fp;
fp = fopen(thefilename, "w+");
if (fp == NULL) {
printf("I couldn't open file for writing.\n");
return 1;
}
/* populate bitSpecial one character at the time and verify array is full */
bitSpecial[0] = 'a';
bitSpecial[1] = '\n';
bitSpecial[2] = '\0'; // terminator
if (fprintf(fp,"%s", bitSpecial) < 0)
printf("[+] fprintf failed with '%s'\n", strerror(errno));
if (fclose(fp) != 0)
puts("Unable to close the file");
return 0;
}
Verify that you put a null terminator (\0) at the end of bitSpecial, and check the return value of fprintf.

Opening a file using relative path

The following code is supposed to work as follows: print the list of the files in a directory, and print the content of each .c file.
it works fine when executed in UNIX for the same directory: ./a.out ./
However, I was not able to make it work for ./a.out ../differentDir execution.
I know that if the absolute path is provided as an argument, I could use argv[1] for that. However, when it is provided in a form of a relative path I am lost.
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFFSIZE 32768
int main(int argc, char **argv) {
char buf[BUFFSIZE];
DIR *dp;
struct dirent *dirp;
char filename[80];
int name_length;
FILE *fp;
if (argc != 2) {
fprintf(stderr, "usage: %s dir_name\n", argv[0]);
exit(1);
}
if ((dp = opendir(argv[1])) == NULL ) {
fprintf(stderr, "can't open '%s'\n", argv[1]);
exit(1);
}
while ((dirp = readdir(dp)) != NULL ){
printf("%s\n", dirp->d_name);
memset(filename, '\0', sizeof(filename));
strcpy(filename, dirp->d_name);
printf(" ** %s ", filename);
name_length = strlen(filename);
printf(" name_length=%d \n", name_length);
if (findC(filename)) // checking if the file has a .c extension
{
fp=fopen(filename, "r");
if (fp == NULL)
fprintf(stderr, "Can't open .C file!\n");
else
{// if the file was opened successfuly:
do
{
fgets(buf,BUFFSIZE,fp); // reading each line until buffer is full or until reaching whitespace
buf[strlen(buf)-1]='\0'; // removing the trailing whitespace from the buffer
puts(buf);
}
while (!feof(fp));
printf("\n\n");
fclose(fp);
}
}
}
closedir(dp);
return(0);
}
/*FindC method gets a c-string that represents a file name; returns 1 if the file ends with .C extension, else returns 0*/
int findC(char * name)
{
int len = strlen(name);
if (len>=2 && name[len-2]=='.' && tolower(name[len-1])=='c')
return 1;
return 0;
}
Upon opening the file to read, the file pathname needs to also be relative.
// Form prefix for complete relative file name
char filename[MAXPATH];
strcpy(filename, argv[1]);
// append '/' if directory path does not end in '/'
if (TBD_code(filename)) {
strcat(filename, "/");
}
char *end = filename[strlen(filename)];
while ((dirp = readdir(dp)) != NULL ){
printf("%s\n", dirp->d_name);
if (findC(dirp->d_name)) {
// append filename to prefix
strcpy(end, dirp->d_name);
fp=fopen(filename, "r");
...
You can use realpath(argv1...) like in this example. realpath will return the absolute path for a relative path.
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
int main(int argc, char **argv) {
char *path = "../..";
char buff[PATH_MAX + 1]; /* not sure about the "+ 1" */
char *res = realpath(path, buff);
if (res) {
printf("This source is at %s.\n", buff);
} else {
perror("realpath");
exit(EXIT_FAILURE);
}
return 0;
}
To include the desired behavior in your program, you can use realpathin your code:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <dirent.h>
#include <string.h>
#define BUFFSIZE 32768
int main(int argc, char **argv) {
char buf[BUFFSIZE];
DIR *dp;
struct dirent *dirp;
char filename[80];
int name_length;
FILE *fp;
char buff[PATH_MAX + 1]; /* not sure about the "+ 1" */
if (argc != 2) {
fprintf(stderr, "usage: %s dir_name\n", argv[0]);
exit(1);
}
char *res = realpath(argv[1], buff);
if ((dp = opendir(res)) == NULL ) {
fprintf(stderr, "can't open '%s'\n", argv[1]);
exit(1);
}
while ((dirp = readdir(dp)) != NULL ){
printf("%s\n", dirp->d_name);
memset(filename, '\0', sizeof(filename));
strcpy(filename, dirp->d_name);
printf(" ** %s ", filename);
name_length = strlen(filename);
printf(" name_length=%d \n", name_length);
if (findC(filename)) // checking if the file has a .c extension
{
fp=fopen(filename, "r");
if (fp == NULL)
fprintf(stderr, "Can't open .C file!\n");
else
{// if the file was opened successfuly:
do
{
fgets(buf,BUFFSIZE,fp); // reading each line until buffer is full or until reaching whitespace
buf[strlen(buf)-1]='\0'; // removing the trailing whitespace from the buffer
puts(buf);
}
while (!feof(fp));
printf("\n\n");
fclose(fp);
}
}
}
closedir(dp);
return(0);
}
/*FindC method gets a c-string that represents a file name; returns 1 if the file ends with .C extension, else returns 0*/
int findC(char * name)
{
int len = strlen(name);
if (len>=2 && name[len-2]=='.' && tolower(name[len-1])=='c')
return 1;
return 0;
}
You could first change to the directory chdir either with relative or absolute path and the get the absolute path via the getcwd
#include <sys/types.h>
#include <string.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFFSIZE 32768
#define PATH_SIZE 512
int main(int argc, char **argv) {
char buf[BUFFSIZE];
char path[PATH_SIZE];
DIR *dp;
struct dirent *dirp;
char filename[80];
int name_length, r;
FILE *fp;
if (argc != 2) {
fprintf(stderr, "usage: %s dir_name\n", argv[0]);
exit(1);
}
strcpy(path, argv[1]);
r = chdir(path);
if( r != 0 )
{
printf("Invalid path '%s'\n",path);
exit(1);
}
getcwd(path,PATH_SIZE);
if ((dp = opendir(path)) == NULL ) {
fprintf(stderr, "can't open '%s'\n", argv[1]);
exit(1);
}
while ((dirp = readdir(dp)) != NULL ){
printf("%s\n", dirp->d_name);
memset(filename, '\0', sizeof(filename));
strcpy(filename, dirp->d_name);
printf(" ** %s ", filename);
name_length = strlen(filename);
printf(" name_length=%d \n", name_length);
if (findC(filename)) // checking if the file has a .c extension
{
fp=fopen(filename, "r");
if (fp == NULL)
fprintf(stderr, "Can't open .C file!\n");
else
{// if the file was opened successfuly:
do
{
fgets(buf,BUFFSIZE,fp); // reading each line until buffer is full or until reaching whitespace
buf[strlen(buf)-1]='\0'; // removing the trailing whitespace from the buffer
puts(buf);
}
while (!feof(fp));
printf("\n\n");
fclose(fp);
}
}
}
closedir(dp);
return(0);
}
/*FindC method gets a c-string that represents a file name; returns 1 if the file ends with .C extension, else returns 0*/
int findC(char * name)
{
int len = strlen(name);
if (len>=2 && name[len-2]=='.' && tolower(name[len-1])=='c')
return 1;
return 0;
}

Finding the size of a file from stdin gives incorrect number

I am reading a file name off the standard input and the function returns something that is completely wrong. The code below returns 4294967296 rather than what should be 7. I am running the file like this on linux:
echo "p3test.txt" | ./totalsize
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
//find the file size
off_t filesize(const char* fileName){
printf("%s", fileName);
struct stat st;
if(stat(fileName, &st) == 0)
printf("%zd", st.st_size);
return st.st_size;
fprintf(stderr, "Cannot determine size of %s: %s\n",
fileName, strerror(errno));
return -1;
}
int main (int argc, char *argv[])
{
char tmpstring[1024];
const char* fileName;
off_t size;
while (fgets(tmpstring, 1024, stdin))
{
fileName = tmpstring;
size = filesize(fileName);
}
}
When you use:
while (fgets(tmpstring, 1024, stdin))
you get the '\n' in tmpstring. Trim that character from the name before calling filesize.
Also, the lines
if(stat(fileName, &st) == 0)
printf("%zd", st.st_size);
return st.st_size;
should be:
if(stat(fileName, &st) == 0)
{
printf("%zd", st.st_size);
return st.st_size;
}
Otherwise, the if statement terminates at the printf line and you end up returning st.st_size regardless of the return value of stat.
Update
Thanks to #chux for the suggestion. The format "%zd" might not be appropriate for the type used for stat.st_size. You should use:
printf("%jd", (intmax_t)st.st_size);

C assign string from argv[] to char array

I have the following code which reads an file name from the command line and opens this file:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv){
FILE *datei;
char filename[255];
//filename = argv[1];
//datei=fopen(filename, "r");
datei=fopen(argv[1], "r");
if(datei != NULL)
printf("File opened");
else{
printf("Fehler beim öffnen von %s\n", filename);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
This example works, but I want to write the string from the command line to the char array and pass that char array to to fopen(), but i get the compiler error
Error: assignment to expression with array type filename = argv[1];
What does this error mean and what can I do to fix it?
You must copy the string into the char array, this cannot be done with a simple assignment.
The simplistic answer is strcpy(filename, argv[1]);.
There is a big problem with this method: the command line parameter might be longer than the filename array, leading to a buffer overflow.
The correct answer therefore:
if (argc < 2) {
printf("missing filename\n");
exit(1);
}
if (strlen(argv[1]) >= sizeof(filename)) {
printf("filename too long: %s\n", argv[1]);
exit(1);
}
strcpy(filename, argv[1]);
...
You might want to output the error messages to stderr.
As a side note, you probably want to choose English or German, but not use both at the same time ;-)
An even simpler solution is to just keep a copy of the pointer argv[1] in a char *filename. Unless you modify it yourself, a very bad idea, its contents will not change for the duration of the program execution.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
FILE *datei;
char *filename;
if (argc < 2) {
fprintf(stderr, "Fehlendes Dateiname-Befehlszeilenargument\n");
return EXIT_FAILURE;
}
filename = argv[1];
datei = fopen(filename, "r");
if (datei != NULL) {
printf("Datei erfolgreich geöffnet\n");
} else {
fprintf(stderr, "Fehler beim öffnen von %s: %s\n",
filename, strerror(errno));
return EXIT_FAILURE;
}
// ...
fclose(datei);
return EXIT_SUCCESS;
}

Resources