Confused with the st_ino? - c

#include "stdio.h"
#include <sys/stat.h>
int
main(int argc, char *argv[]) {
struct stat buf;
//int fd = open("./fstatat.c", "r");
//int fd2 = fstatat(fd, "a.txt", &buf, 0);
//printf("%d\n", buf.st_ino);
stat("./fstatat.c", &buf);
printf("%d\n", buf.st_ino);
return 0;
}
if i use the function stat to get a struct stat, the st_ino is the same as the i-node number with the ls -i.
1305609
[inmove#localhost chapter-four]$ ls -i
1305607 a.txt 1305606 fstatat.bin 1305609 fstatat.c 1305605 tmp.txt
buf if i use the function fstat, the st_ino is always the 4195126.
anyone can tell me why this happen?

The problem is that you are not using open correctly and don't check the return values for errors. So you are then calling fstat on the invalid file descriptor value -1 returned by open on error, which will also fail and not touch buf at all, so the uninitialized garbage in the struct is still there (4195126, hex 0x400336 smells a lot like a return address of a previous function call still being on the stack or something like this.)
As davmac already pointed out, the second parameter to open must be a list of flags, which are numeric. Check the docs.
So, the correct code would be:
#include "stdio.h"
#include <sys/stat.h>
#include <sys/fcntl.h> // for the O_RDONLY constant
#include <errno.h> // for error output
int main(int argc, char *argv[]) {
struct stat buf;
int fd = open("./fstatat.c", O_RDONLY);
if(fd == -1) {
printf("Error calling open: %s\n", strerror(errno));
} else {
if(fstat(fd, &buf) == -1) {
printf("Error calling fstat: %s\n", strerror(errno));
} else {
printf("%d\n", buf.st_ino);
if(close(fd) == -1) {
printf("Error calling close: %s\n", strerror(errno));
}
}
}
return 0;
}

Related

S_ISREG returns 0

So I want to test if a file given is regular or not.
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv)
{
// Input check.
if (argc != 2) {
fprintf(stdout,"Format: %s <filename.txt>\n", argv[0]);
return -1;
}
// Make sure the file is a regular file.
int fd;
if ((fd = open(argv[1], O_RDONLY) == -1)) {
fprintf(stdout, "%s", strerror(errno));
return -1;
}
struct stat st;
if ((fstat(fd, &st) == -1)) {
fprintf(stdout, "%s\n", strerror(errno));
return -1;
}
if (!(S_ISREG(st.st_mode))) {
fprintf(stdout, "Error, invalid file\n");
return -1;
}
close(fd);
return 0;
}
I run: .\a in.txt
I don't know what exactly is going on, but when I'm trying to test if the file is regular (last if statement), it fails. I tested to see if fstat fails, but it doesn't.
Here's the problem:
if ((fd = open(argv[1], O_RDONLY) == -1)) {
The equality operator == has higher precedence than the assignment operator =. So the above parses as:
if (fd = (open(argv[1], O_RDONLY) == -1)) {
Which assigns to fd the result of the comparison which will be either 0 or 1. These values both happen to be valid open file descriptors for stdin and stdout so the fstat call is successful and gets you the status of one of these streams.
You'll need to adjust the parenthesis to do the assignment first:
if ((fd = open(argv[1], O_RDONLY)) == -1) {
Also, it looks like you have other if statements that have a redundant set of parenthesis that you can remove. You want to avoid this because those extra parenthesis can silence warnings about exactly what you did.

open()'s "mode" argument won't set the correct permissions for the file

My intention was to open two files, where the second one would be brand new, with the same permissions as the first file. So to test my code I changed the first file permissions to "777". Then I proceeded to run my program. And to my surprise, the permission of the newborn file2 were wrong! They where set to 755. Even weirder is when I set the first file to "111" and tried again, the result now was "1204".
Can someone explain to me this weird behavior?
Here's my code
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char *args[]) {
struct stat stats;
int fd1, fd2;
fd1 = open("testfile.txt", O_RDONLY);
/* Error check*/
if (fd1 == -1) {
/* Error handling */
perror("Opening");
printf("Unable to open file: %s\n", "testfile.txt");
printf("ERROR: %s\n", strerror(errno));
return 1;
}
if(fstat(fd1, &stats) == -1)
{
printf("Error while getting stats: %s\n", strerror(errno));
exit(-1);
}
//Receives the output file as a main argument . . .
if (argc > 1)
{
//(stats.st_mode = Gets the mask of the first file)
fd2 = open(args[1], O_WRONLY|O_CREAT, stats.st_mode);
/* Error check*/
if (fd2 == -1) {
/* Error handling */
perror("Opening");
printf("Unable to open file: %s\n",args[1]);
printf("ERROR: %s\n", strerror(errno));
return 1;
}
}
//. . . if it doesn't it creates a standard one warning you about it
else
{
fd2 = open("Nope.txt", O_WRONLY|O_CREAT, stats.st_mode);
/* Error check*/
if (fd2 == -1) {
/* Error handling */
perror("Opening");
printf("Unable to open file: %s\n",args[1]);
printf("ERROR: %s\n", strerror(errno));
return 1;
}
printf("Standard file created\n");
}
close(fd1);
close(fd2);
return 0;
}
I tried to make it as tidy as I could :)
From open(2) man page on the part about O_CREATE:
The effective mode is modified by the process's umask in the usual way: in the absence of a default ACL, the mode of the created file is (mode & ~umask).
If you type umask in bash you can see what value is used and which bits get cleared from the mode you provide.

How can I duplicate time atrributes in C on Linux?

I tried to make a copy program. I made it, but it's hard to implement copying time-atrributes(access time, modify time, change time).
I thought that I can make it using st_atime, st_mtime, st_ctime of struct stat.
But I don't know where should I use them.
Can you help me?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#define MAX_BUF 64
int main(int argc, char *argv[]) {
char buf[MAX_BUF];
int fd, fd1, read_size, write_size;
struct stat stat; // struct stat variable
// if the number of arguments are not 3, return 0
if(argc != 3) {
printf("\nUSAGE: %s [old_file_name] [new_file_name]\n\n", argv[0]);
return 0;
}
fd = open(argv[1], O_RDONLY); // execute an original file descriptor(read only)
fstat(fd, &stat); // store stats of the original file
// execute a file descripoter to be copied
if(0 < (fd1 = open(argv[2], O_RDWR | O_CREAT | O_EXCL, stat.st_mode))) {
// write data of original in copied
while(1) {
read_size = read(fd, buf, MAX_BUF);
if(read_size == 0) break;
write_size = write(fd1, buf, read_size);
}
} else
printf("\nfile name of [%s] is already exist\n\n", argv[2]);
close(fd);
close(fd1); // close file descriptors
}
The function you're after is called utime().

C Program that makes a copy of a file using standard I/O and system calls

I am trying to write a C program which uses standard I/O and System calls to perform copying of contents of one file to another file.
So far, I have done this :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd1, fd2;
char buffer[1024];
long int n1;
if(((fd1 = open(argv[1], O_RDONLY)) == -1) || ((fd2=open(argv[2],O_CREAT|O_WRONLY|O_TRUNC, 0700)) == -1)){
perror("file problem");
exit(1);
}
while((n1=read(fd1, buffer, 1024) > 0)){
if(write(fd2, buffer, n1) != n1){
perror("writing problem ");
exit(3);
}
}
close(fd1);
close(fd2);
}
When I run the program like this :
cc copyContents.c
./a.out one.txt two.txt
Assuming that one.txt is well defined, what I want is to create a new file called two.txt and copy over all the contents of one.txt
When I look into the contents of two.txt after running the program, it has literally nothing in it. Just a blank file.
Where am I going wrong?
You wrote
while((n1=read(fd1, buffer, 1024) > 0)){
instead of
while ( (n1 = read(fd1, buffer, 1024)) > 0)
In your code the code int the while condition boils down to:
n1 = (read(fd1, buffer, 1024) > 0)
So the read is done correctly, it's return value is compared to 0, the result of the comparision (0 or 1) is assigned to n1.
This shows once more how important it is to format your code in a way that makes it readable.
You could have debugged this easily yourself with a debugger or by inserting one or two printfs in your code.
Input:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
void typefile (char *filename)
{
int fd, nread;
char buf[1024];
fd = open (filename, O_RDONLY);
if (fd == -1) {
perror (filename);
return;
}
while ((nread = read (fd, buf, sizeof (buf))) > 0)
write (1, buf, nread);
close (fd);
}
int main (int argc, char **argv)
{
int argno;
for (argno = 1; argno < argc; argno )
typefile (argv[argno]);
exit (0);
}
Output:
student#ubuntu:~$gcc –o prg10.out prg10.c
student#ubuntu:~$cat > ff
hello`enter code here`
hai
student#ubuntu:~$./prg10.out ff
hello
hai
This is the best solution and easily executable.
input:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int f1, f2;
char buff[50];
long int n;
if(((f1 = open(argv[1], O_RDONLY)) == -1 || ((f2=open(argv[2], O_CREAT |
O_WRONLY | O_TRUNC, 0700))== 1)))
{
perror("problem in file");
exit(1);
}
while((n=read(f1, buff, 50))>0)
if(write(f2, buff, n)!=n)
{
perror("problem in writing");
exit(3);
}
if(n==-1)
{
perror("problem in reading");
exit(2);
}
close(f2);
exit(0);
}
Output:
cc sys.c
./a.out a.txt b.txt
cat b.txt
So, a.txt should have some content and this content is copied to b.txt
by "cat b.txt" you can cross-check the content(which is in "a.txt").
Narenda checks if n==-1 inside the loop, but, the loop test is n>0, so, that'll never happen.
Also, the test for a bad read should precede the attempt to write.

How to distinguish a file pointer points to a file or a directory?

When I do:
FILE * fp = fopen("filename", "r");`
How can I know the file pointer fp points to a file or a directory? Because I think both cases the fp won't be null. What can I do?
The environment is UNIX.
i've found this near by:
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
int main (int argc, char *argv[]) {
int status;
struct stat st_buf;
status = stat ("your path", &st_buf);
if (status != 0) {
printf ("Error, errno = %d\n", errno);
return 1;
}
// Tell us what it is then exit.
if (S_ISREG (st_buf.st_mode)) {
printf ("%s is a regular file.\n", argv[1]);
}
if (S_ISDIR (st_buf.st_mode)) {
printf ("%s is a directory.\n", argv[1]);
}
}
You could use fileno() to get the file discriptor for the already opened file, and then use fstat() on the file descriptor to have a struct stat returned.
It's member st_mode carries info on the file.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main()
{
FILE * pf = fopen("filename", "r");
if (NULL == pf)
{
perror("fopen() failed");
exit(1);
}
{
int fd = fileno(pf);
struct stat ss = {0};
if (-1 == fstat(fd, &ss))
{
perror("fstat() failed");
exit(1);
}
if (S_ISREG (ss.st_mode))
{
printf ("Is's a file.\n");
}
else if (S_ISDIR (ss.st_mode))
{
printf ("It's a directory.\n");
}
}
return 0;
}
On Windows, Call GetFileAttributes, and check for the FILE_ATTRIBUTE_DIRECTORY attribute.
Check this and this.

Resources