1

So I'm doing some very basic work with opening and closing files in C.

I noticed that when I run the following code, I get strange output:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdlib.h>

main()
{
   // first get rid of existing input.txt, which is guaranteed to exist
   pid_t pid = fork();

   //child code
   if (pid == 0) {
       char* command[4] = {"rm", "-f", "input.txt", NULL};
       execvp(command[0], command);
   }


   // parent code
   else {
       int status;
       wait(&status);
   }

   // initialize file descriptor
   int fd;

   // open input.txt with given flags
   int flags = O_RDWR | O_CREAT;
   fd = open("input.txt", flags);

   // debug
   fprintf(stderr,"The openval is %d\n", fd);

   // now close it
   int closeval = close(fd);

   // debug
   fprintf(stderr,"The closeval is %d\n", closeval);

   // try to re-open-it with different flags
   flags = O_RDONLY;
   fd = open("input.txt", flags);

   // debug
   fprintf(stderr,"The new openval is %d\n", fd);
}

Output:

The openval is 3
The closeval is 0
The new openval is -1

The first and second lines of output make sense to me. My big question is, why can I not open the file a second time?

I figured at first that it might be because I was requesting to open it the second time using the following flags:

flags = O_RDWR;

My thought was that requesting write permissions would somehow be messed up by the previous open (even though that shouldn't be the case because I closed it, right?). So i tried the version from above that only asks to read the file, and still no luck.

Is opening, closing, and then re-opening files like that just not an option?

Edit: Here is the errno testing code and output

if(fd == -1) {
       char* error = strerror(errno);
       fprintf(stderr,"%s\n",error);
}

Output:

Permission denied
lane0335
  • 124
  • 12

2 Answers2

1

First, man page link.

When you do

int flags = O_RDWR | O_CREAT;
fd = open("input.txt", flags);

You are missing the 3rd parameter of open, file creation mode. It is required with O_CREAT. Without it, function will take whatever "random" value for the argument, and file may be created with some undefined mode (or actually any UB can happen, theoretically).

Fix that as first step, to have defined behavior for your program.


Additionally, though probably not very helpful with above bug, when a C library function returns error (usually -1 for integers, NULL for pointers), it also sets global errno. Use perror or strerror(errno) to get human error message. Always log the error when you detect it, it will help a lot in troubleshooting not just code bugs, but also external problems like file permissions which may happen even after program is "ready".

hyde
  • 60,639
  • 21
  • 115
  • 176
1

This is problem of file creation mode. The default permission of the file created is not allowing you to reopen it. Just add a third parameter inside open(). So, your solution will be:



        #include <stdio.h>
        #include <string.h>
        #include <stdlib.h>
        #include <fcntl.h>
        #include <stdlib.h>

        main()
        {
          // first get rid of existing input.txt, which is guaranteed to exist
          pid_t pid = fork();

          //child code
          if (pid == 0) {
           char* command[4] = {"rm", "-f", "input.txt", NULL};
           execvp(command[0], command);
          }


           // parent code
         else {
           int status;
           wait(&status);
         }

         // initialize file descriptor
         int fd;

         // open input.txt with given flags
         int flags = O_RDWR | O_CREAT;
         /*ADD FILE PERMISSION HERE AS A THIRD PARAMETER. */
         fd = open("input.txt", flags, 0777);

         // debug
         fprintf(stderr,"The openval is %d\n", fd);

         // now close it
         int closeval = close(fd);

         // debug
         fprintf(stderr,"The closeval is %d\n", closeval);

         // try to re-open-it with different flags
         flags = O_RDONLY;
         fd = open("input.txt", flags);

         // debug
        fprintf(stderr,"The new openval is %d\n", fd);
       }

OR you can read about umask and see this page as an additional tip.

Community
  • 1
  • 1
Aman
  • 1,627
  • 13
  • 19
  • Terminology note: There are no "default permissions" when creating files with `open`, it uses the *mode* from arguments even if that argument is not given. C has no default argument values. – hyde Aug 19 '14 at 17:02
  • Thank you for the comment. What I meant to say is when forking a process, the child copies its parents' address space. This makes the child process to have its parents' file permissions. That is what I mentioned as default permission. Thanks anyway. – Aman Aug 20 '14 at 06:46
  • you are welcome. If your problem is solved, mark it as solved. – Aman Aug 22 '14 at 16:46
  • sorry just saw that. I will do so. – lane0335 Sep 08 '14 at 13:59