Distinguishing a pipe from a file in Unix - c

Given a FILE*, is it possible to determine the underlying type? That is, is there a function that will tell me if the FILE* is a pipe or a socket or a regular on-disk file?

There's a fstat(2) function.
NAME
stat, fstat, lstat - get file status
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int fstat(int fd, struct stat *buf);
You can get the fd by calling fileno(3).
Then you can call S_ISFIFO(buf) to figure it out.

Use the fstat() function. However, you'll need to use the fileno() macro to get the file descriptor from file FILE struct.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
FILE *fp = fopen(path, "r");
int fd = fileno(fp);
struct stat statbuf;
fstat(fd, &statbuf);
/* a decoding case statement would be good here */
printf("%s is file type %08o\n", path, (statbuf.st_mode & 0777000);

Related

Call to fdopendir() corrupts file descriptor

I stumbled upon a problem in a program I was working on. The following reproduces my issue:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
int fd, ret_fd;
DIR *dirp;
fd = open("./", O_RDONLY);
#if 1
if ((dirp = fdopendir(fd)) == NULL) {
perror("dirp");
return 1;
}
closedir(dirp);
#endif
ret_fd = openat(fd, "Makefile", O_RDONLY);
if (ret_fd == -1) {
perror("ret_fd");
return 1;
}
return 0;
}
Basically, the call to openat(), which has been preceeded by fdopendir(), fails with: Bad file descriptor. However, this does not happen if fdopendir() is omitted.
I know that fdopendir() makes internal use of the file descriptor, but shouldn't it revert any changes to it after calling closedir()?
What can I do to prevent openat() from failing in this case?
The POSIX description of fdopendir() says:
Upon calling closedir() the file descriptor shall be closed.
So the descriptor is likely to be closed by the time you call openat().
And this is from a typical Linux man page for fdopendir():
After a successful call to fdopendir(), fd is used internally by the
implementation, and should not otherwise be used by the application.

How to read a file permission and store it in a variable in C

In Linux platform(Ubuntu system).
As describe in title.
I try to get a number like '0644' and store it in a variable for later use.
the stat, fstat, lstat system calls can be used to retrieve the permission of a file.
The field st_mode of the stat structure contains the permission of the file specified as argument of the system call. Then a variable of type mode_t can be used as local storage in your application.
This is an example :
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#define FILE_NAME "test.c"
int main(int argc, char *argv[])
{
struct stat sb;
mode_t file_permision;
if (stat(FILE_NAME, &sb) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
file_permision = sb.st_mode;
printf(" File permission : %o (octal)\n",
(unsigned int) file_permision);
return 0;
}

Can't open 2 FILE *

I was working on a program in C for Raspberry PI development, and I've been getting this weird bug.
I honestly have no clue regarding its origins. The program is very simple so far.
#include <bcm2835.h>
#include <time.h>
#include <sys/time.h>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
int main(int argc, char *argv[])
{
FILE *file;
FILE *file2;
FILE *peak1;
FILE *peak2;
file = fopen("input0.txt", "a+");
file2 = fopen("input1.txt", "a+");
peak1=fopen("peak1.txt", "a+");
peak2=fopen("peak2.txt", "a+");
fprintf(file, "%s\n", "HELLO!");
fprintf(peak1, "%s\n", "HELLO!");
}
Bug:-
When I run the program and check the outputs to the files, Only 'input0.txt' has "HELLO!" written where as 'peak1.txt' has nothing.
I can write to the first two files file and file2, but cannot write to the second two files peak1 and peak2.
I have tried writing multiple things but to no avail. What could be the problem?
Thanks!
You forgot to call fclose(FILE *) at the end. Calling int fclose(FILE *fp); will ensure the file descriptor is properly disposed of and output buffers flushed so the data written to the file will be present in the file on disk.
From: IEEE Std 1003.1, 2004 Edition:
int fclose(FILE *stream);
The fclose() function shall cause the stream pointed to by stream to
be flushed and the associated file to be closed. Any unwritten
buffered data for the stream shall be written to the file; any unread
buffered data shall be discarded. Whether or not the call succeeds,
the stream shall be disassociated from the file and any buffer set by
the setbuf() or setvbuf() function shall be disassociated from the
stream. If the associated buffer was automatically allocated, it shall
be deallocated.
You need to call fclose(FILE *) at the end of your code.
The C library function int fclose(FILE *stream) closes the stream. All buffers are flushed.

open() function error when flags are a char string pointer instead of an int

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
int fd;
int i=1;
for(i=1;i<argc;++i)
{
char temp;
fd=open(argv[i],"O_RDWR");
if (fd==-1)
perror("file:");
while (read(fd,&temp,1)!=EOF)
{
putchar(temp);
}
}
}
I execute ./a.out a b. a and b are files in my directory. I get an error saying File exists.
The line open(argv[i],"O_RDWR") is not opening the file.
It is returning -1 since the file exists . How then should i open the file using the open system call?
fd=open(argv[i],"O_RDWR");
^ ^
You're passing a char * instead of an integer constant. Drop the ", it should be just:
fd = open(argv[i], O_RDWR);
Interestingly but likely off-topic, open must have thought you passed O_CREAT | O_EXCL, that's why it complained about the file already existing.
So what i have wriiten is right then???But the code is going into an
infinite look printing nothin
The function read(2) doesn't return EOF at and of input but rather 0.

Existence of a file given its path

Given the path, is there a way to find out whether the file exists without opening the file?
Thanks
The most efficient way is access with the F_OK flag.
stat also works but it's much heavier weight since it has to read the inode contents, not just the directory.
You can use the stat system call. Make sure though that you check errno for the correct error because stat may return -1 for a number of other reasons/Failures.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
main()
{
struct stat BUF;
if(stat("/Filepath/FileName",&BUF)==0)
{
printf("File exists\n");
}
}
Another way is by using the access function.
#include <unistd.h>
main()
{
if(access("/Filepath/FileName", F_OK) != -1 )
{
printf("File exists\n");
}
else
{
printf("File does not exist\n");
}
}
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
int rc;
struct stat mystat;
rc = stat(path, &mystat);
Now check rc and (maybe) errno.
EDIT 2011-09-18 addendum:
Both access() and stat() return 0 if the path points to a non-file (directory, fifo,symlink, whatever)
In the stat() case, this can be tested with "((st_mode & S_IFREG) == S_IFREG)".
Best way still is to just try to open the file with open() or fopen().
Try to remove it (unlink()). If successful, it doesn't exist anymore. If unsuccessful,
interpret errno to see if it exists :)

Resources