简体   繁体   中英

fopen() returns NULL but open() syscall returns proper file descriptor?

I've been trying to run this very simple C code on Ubuntu 20.04LTS

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

int main()
{
   
    FILE *f;
   
    f=fopen("tree.txt","r");
    if(f==NULL){
        perror("fopen");
        exit(1);
    }
    //readTree();
    return 0;
}

But no matter what I've tried so far fopen still returns this eror:

fopen: No such file or directory
[1] + Done     

First thing I assumed was that the program didn't have permission to open the file, but the permissions are set correctly:

ls -la tree.txt
-rw-rw-rw- 1 mor mor 7 mar 26 20:43 tree.txt

Next I tried to change the location of the file to /home or to specify a full path instead of the file name; still the same result

Now comes the part I can't wrap my head around, when running the script under Strace, it appears to work fine , at least for now

execve("./B1", ["./B1"], 0x7ffe586e59b0 /* 26 vars */) = 0
brk(NULL)                               = 0x55cd150ea000
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff084d4590) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=156877, ...}) = 0
mmap(NULL, 156877, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fcadcd70000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360q\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\t\233\222%\274\260\320\31\331\326\10\204\276X>\263"..., 68, 880) = 68
fstat(3, {st_mode=S_IFREG|0755, st_size=2029224, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcadcd6e000
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\t\233\222%\274\260\320\31\331\326\10\204\276X>\263"..., 68, 880) = 68
mmap(NULL, 2036952, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fcadcb7c000
mprotect(0x7fcadcba1000, 1847296, PROT_NONE) = 0
mmap(0x7fcadcba1000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7fcadcba1000
mmap(0x7fcadcd19000, 303104, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19d000) = 0x7fcadcd19000
mmap(0x7fcadcd64000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7fcadcd64000
mmap(0x7fcadcd6a000, 13528, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fcadcd6a000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7fcadcd6f540) = 0
mprotect(0x7fcadcd64000, 12288, PROT_READ) = 0
mprotect(0x55cd14c84000, 4096, PROT_READ) = 0
mprotect(0x7fcadcdc4000, 4096, PROT_READ) = 0
munmap(0x7fcadcd70000, 156877)          = 0
brk(NULL)                               = 0x55cd150ea000
brk(0x55cd1510b000)                     = 0x55cd1510b000
openat(AT_FDCWD, "tree.txt", O_RDONLY)  = 3
exit_group(0)                           = ?
+++ exited with 0 +++

The openat() call returns a small positive integer, which is normal behavior from what I read so far

Lastly, what really grinds my gears is that the output of Strace above differs from the output I received just a couple minutes before . For some reason I can't seem to recreate that output but the gist of it is this:

-openat() returns 3

- lseek(fd, -9, SEEK_CUR) is called and returns -1 ESPIPE Illegal seek please excuse my syntax here, I'm writing it from memory. Also why is the offset a negative integer? Is that normal?

And why was lseek() called the first couple of times, but not now?

Reading man on lseek here it says that

On Linux, using lseek() on a terminal device fails with the error ESPIPE.

also the error descriptor

ESPIPE fd is associated with a pipe, socket, or FIFO.

I believe the first quote to be unrelated, plenty of threads online with people managing to use fopen() on linux. When it comes to the error descriptor, it is beyond my level of understanding.

错误案例截图

renderer1.log:

[2021-03-27 23:08:46.895] [renderer1] [error] Unexpected: The specified task is missing an execution: Error: Unexpected: The specified task is missing an execution
    at S.getTaskExecution (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:48749)
    at S.$onDidStartTaskProcess (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:46905)
    at c._doInvokeHandler (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:10509)
    at c._invokeHandler (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:10201)
    at c._receiveRequest (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:8871)
    at c._receiveOneMessage (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:7673)
    at /snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:90:5782
    at g.fire (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:57:1836)
    at p.fire (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:65:15443)
    at /snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:106:29119
    at g.fire (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:57:1836)
    at p.fire (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:65:15443)
    at t._receiveMessage (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:65:20693)
    at /snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:65:17587
    at g.fire (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:57:1836)
    at l.acceptChunk (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:65:12808)
    at /snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:65:12156
    at Socket.E (/snap/code/59/usr/share/code/resources/app/out/vs/workbench/services/extensions/node/extensionHostProcess.js:106:12375)
    at Socket.emit (events.js:315:20)
    at addChunk (_stream_readable.js:295:12)
    at readableAddChunk (_stream_readable.js:271:9)
    at Socket.Readable.push (_stream_readable.js:212:10)
    at Pipe.onStreamRead (internal/stream_base_commons.js:186:23)

This is all I could come up with, apparently it's not good enough.

Any and all help is appreciated.

To sum it up, my issue was that the working directory of the.c program and the directory in which i had saved the.txt file were different. There are many ways to get around this issue.

Try using an absolute path in the fopen directory. For example:

    FILE*f; f=fopen("/home/user/Desktop/file.txt","r");
 

this only works as a test, as it makes the code too rigid(answer provided by @kaylum)

Changing the working directory using chdir()

simple code that changes directory to the one specified by the user, opens file with name and mode specified by user; printing cwd using getcwd() (part of the answer provided by @ilkkachu)

//puts cwd in *str and prints cwd if successful, otherwise prints error 
void getdir(char *str, unsigned int str_size)
{
    
     if(getcwd(str,str_size)==NULL){
        perror("getcwd()");
        exit(1);
    }else
        printf("Current working dir: %s\n",str);
}

//reads directory path and sets it as new working dir
int changeDir()
{
    char cwd[256];
    printf("New woking dir path= ");
    scanf("%s",cwd);
    if(chdir(cwd)!=0){
        perror("chdir()");
        return -1;
        }
    getdir(cwd,sizeof(cwd));
    return 0;
}

int main()
{
   
    FILE *f;
    char cwd[256],fmod[5];
    
    getdir(cwd,sizeof(cwd));
    //reads new path until an existing one is inputted
    while(changeDir()!=0);

    printf("File name: ");
    scanf("%s",cwd);
    printf("File mode: ");
    scanf("%s",fmod);
    
    f=fopen(cwd,fmod);
    if(f==NULL){
        perror("fopen");
        exit(1);
    }


    //reads first line of file and prints it to console
    fscanf(f,"%[^\n]",cwd);
    printf("%s",cwd);
    
    return 0;
}

Code terminal output:

Current working dir: /home/moro/Documents/TP-Lab
New woking dir path= /home/moro/doesNotExist
chdir(): No such file or directory
New woking dir path= /home/moro/Desktop
Current working dir: /home/moro/Desktop
File name: input.txt
File mode: r
THIS IS A TEST FILE[1] + Done

        

Changing the current working directory in Visual Studio Code settings

Go to

Settings>Terminal>Integrated: Cwd

You can specify a start path there

Terminal › Integrated: Cwd An explicit start path where the terminal will be launched, this is used as the current working directory (cwd) for the shell process. This may be particularly useful in workspace settings if the root directory is not a convenient cwd.

There probably are smoother ways to go about this, but for my use case these options are more than good enough. If i find the time i will add more solutions to this answer

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM