The access function checks to see whether the file can be accessed in the way specified by the how argument. The how argument either can be the bitwise OR of the flags R_OK, W_OK, X_OK, or the existence test F_OK.
The return value is 0 if the access is permitted, and -1 otherwise.
if the file does not exist, Does the access return -1 too?
I wan to develop a function in which I check the existence of a file. If the following access function did it, what kind of arguments I have to put according to the standard?
if (access("file_example", R_OK | W_OK | X_OK) != -1)
BTW: the file I want to check if exisits by access() function is created by the same application. so it's created by the same user
Those flags would check if the file is executable, writeable and readable by the process, lots of files won't be. The flag you're looking for is F_OK. F_OK tests for the existence of the file and nothing else.
I suggest reading the man page for access. It should be documented there.
You can use it.
if (access("file_example", F_OK) != -1)
int access(const char *path, int amode);
The value of amode is either the bitwise-inclusive OR of the access permissions to be checked (R_OK, W_OK, X_OK) or the existence test (F_OK).
Yes, with errno set to ENOENT.
According to the manual page, one of the errors returned is:
ENOENT A component of pathname does not exist or is a dangling symbolic link.
Also, in the second paragraph it clearly says:
F_OK tests for the existence of the file.
Related
I know that open(filepath, O_WRONLY|O_EXCL) will fail if filepath exists, but does it return anything?
Now say if I want to know if a file exists, and would like to print a message if it does, should I include the O_EXCL flag in the open() command above?
Edit: I guess I made a mistake, and I was supposed to use open(filepath, O_CREAT|O_EXCL)
open(filepath, O_WRONLY|O_EXCL) will not fail if filepath exists, it will fail if it does not exist or if you do not have write access.
O_EXCL should only be used with O_CREAT and an extra argument must then be passed to specify the mode bits for the file to create:
int hd = open(filepath, O_WRONLY | O_CREAT | O_EXCL, 0644);
hd will have a negative value in case of failure and errno will be set to indicate the error cause. Use perror() to report the failure with an explicit error message.
You can also test file existence and write access with access(), but it is not appropriate for your use case as the file could be created by a concurrent process between the test with access and the call to open (among other reasons).
An important note from the manual:
In general, the behavior of O_EXCL is undefined if it is used
without O_CREAT. There is one exception: on Linux 2.6 and
later, O_EXCL can be used without O_CREAT if pathname refers
to a block device.
So barring one use case, your command invokes undefined behavior.
If open fails for any reason, it will return -1 and set errno to indicate the cause. The details are in your open(2) manual page. Type man 2 open in any Unixy system.
from the MAN page for open():
O_EXCL Ensure that this call creates the file: if this flag is speci‐
fied in conjunction with O_CREAT, and pathname already exists,
then open() fails with the error EEXIST.
When these two flags are specified, symbolic links are not fol‐
lowed: if pathname is a symbolic link, then open() fails regard‐
less of where the symbolic link points.
In general, the behavior of O_EXCL is undefined if it is used
without O_CREAT. There is one exception: on Linux 2.6 and
later, O_EXCL can be used without O_CREAT if pathname refers to
a block device. If the block device is in use by the system
(e.g., mounted), open() fails with the error EBUSY.
Therefore, your premise that it fails if the file already exist is not quite correct.
However, when it fails: (per the MAN page)
open(), openat(), and creat() return the new file descriptor, or -1 if
an error occurred (in which case, errno is set appropriately).
I have a full path stored in char full_path[1000] and I'd like to know whether anything exists at that location.
(The next thing my code would do after this check is create something at that location, but I want it to count as an error if there is already something there instead of clearing the spot with the equivalent of rm -rf)
The spot might be occupied by a file or a directory or even a link to some no-longer-existing-target e.g.:
lrwxrwxrwx 1 user grp 4 Jun 16 20:02 a-link -> non-existent-thing
With an invalid link, access(full_path, F_OK) is going to tell me I can't access full_path and that could be because (1) nothing exists there or because (2) the link is invalid.
Given that, what's the best way to determine if anything exists at full_path?
You simply cannot do that in a cross-platform obvious way. stat() and fopen() would not work. You can, though, use the OS API, for example, on windows you could use WinAPI with the example code:
int doesFileExist(TCHAR* path)
{
WIN32_FIND_DATA FindFileData;
HANDLE handle = FindFirstFile(path, &FindFileData) ;
int found = (handle != INVALID_HANDLE_VALUE);
if(found)
{
FindClose(handle);
}
return found;
}
If you just want to check if anything exists, finding any file (again, using Windows API) would also work, you could just go directory by directory to check if it exists, if one doesn't - return an error. Keep going until you got to the directory then check for the certain file in the way mentioned above.
Say you have C:/Dir1/Dir2/Dir3/file.txt then you'd go to C: first, then check if Dir1 exists, if it does - go to it, if it doesn't return an error. Same for Dir2 and so on up until you get to the last directory and check for the file OR if you don't check for a certain file and for any item - just try using the functions mentioned in MSDN for finding first file or first directory.
Since the next thing we plan to do is create something at that location, and since we want to treat it as an error if something already exists there, then let's not bother checking. Just attempt the create and exit with an error if it fails. The create step uses symlink so if it fails we can use strerror(errno) for the explanation of any failure.
To create a file in general (vs just a symlink), EOF points out in comments that open(path, O_CREAT|O_EXCL, mode) will return failure (-1) if the file already exists, and create the file otherwise. This is atomic and safe (unlike trying to stat) and guaranteed to work atomically on POSIX (with the possible exception of NFS).
How can I find if a directory exists or not in a C program? I know that getcwd() gives you the current directory but I want to find ANY directory. Is there a function for that or how do I do it? I am using Ubuntu
opendir, readdir and closedir are POSIX functions, so they should be available in Linux, MacOS, Windows as well as any Unix type system.
you can use access() function , like for example:
access(path, F_OK);
It returns 0 if found. -1 if not found.
int mkdir (const char *filename, mode_t mode)
you need to include the header file sys/stat.h to use this function.
The mkdir function creates a new, empty directory with name filename. The argument mode specifies the file permissions for the new directory file.A return value of 0 indicates successful completion, and -1 indicates failure.
In case of failure and if your Directory already exists errno value will equal to EEXIST.
I have a situation where I need to get a file name so that I can call the readlink() function. All I have is an integer that was originally stored as a file descriptor via an open() command. Problem is, I don't have access to the function where the open() command executed (if I did, then I wouldn't be posting this). The return value from open() was stored in a struct that I do have access to.
char buf[PATH_MAX];
char tempFD[2]; //file descriptor number of the temporary file created
tempFD[0] = fi->fh + '0';
tempFD[1] = '\0';
char parentFD[2]; //file descriptor number of the original file
parentFD[0] = (fi->fh - 1) + '0';
parentFD[1] = '\0';
if (readlink(tempFD, buf, sizeof(buf)) < 0) {
log_msg("\treadlink() error\n");
perror("readlink() error");
} else
log_msg("readlink() returned '%s' for '%s'\n", buf, tempFD);
This is part of the FUSE file system. The struct is called fi, and the file descriptor is stored in fh, which is of type uint64_t. Because of the way this program executes, I know that the two linked files have file descriptor numbers that are always 1 apart. At least that's my working assumption, which I am trying to verify with this code.
This compiles, but when I run it, my log file shows a readlink error every time. My file descriptors have the correct integer values stored in them, but it's not working.
Does anyone know how I can get the file name from these integer values? Thanks!
If it's acceptable that your code becomes non portable and is tied to being run on a somewhat modern version of Linux, then you can use /proc/<pid>/fd/<fd>. However, I would recommend against adding '0' to the fd as a means to get the string representing the number, because it uses the assumption that fd < 10.
However it would be best if you were able to just pick up the filename instead of relying on /proc. At the very least, you can replace calls to the library's function with a wrapper function using a linker flag. Example of usage is gcc program.c -Wl,-wrap,theFunctionToBeOverriden -o program, all calls to the library function will be linked against __wrap_theFunctionToBeOverriden; the original function is accessible under the name __real_theFunctionToBeOverriden. See this answer https://stackoverflow.com/a/617606/111160 for details.
But, back to the answer not involving linkage rerouting: you can do it something like
char fd_path[100];
snprintf("/proc/%d/fd/%d", sizeof(fd_path), getpid(), fi->fh);
You should now use this /proc/... path (it is a softlink) rather than using the path it links to.
You can call readlink to find the actual path in the filesystem. However, doing so introduces a security vulnerability and I suggest against using the path readlink returns.
When the file the descriptor points at is deleted,unlinked, then you can still access it through the /proc/... path. However, when you readlink on it, you get the original pathname (appended with a ' (deleted)' text).
If your file was /tmp/a.txt and it gets deleted, readlink on the /proc/... path returns /tmp/a.txt (deleted). If this path exists, you will be able to access it!, while you wanted to access a different file (/tmp/a.txt). An attacker may be able to provide hostile contents in the /tmp/a.txt (deleted) file.
On the other hand, if you just access the file through the /proc/... path, you will access the correct (unlinked but still alive) file, even if the path claims to be a link to something else.
I am trying to make a simple program that handles files and directories, but I have two major problems:
how can I check whether a file or directory exists or not, and
how do I know if it is a file, directory, symbolic link, device, named pipe etc.? Mainly file and directories matter for now, but I'd like to know the others too.
EDIT: Too all of those who are suggesting to use stat() or a similar function, I have already looked into that, and while it might answer my first question, I can't figure out how it would answer the second...
Since you're inquiring about named pipes/symlinks etc, you're probably on *nix, so use the
lstat() function
struct stat info;
if(lstat(name,&info) != 0) {
if(errno == ENOENT) {
// doesn't exist
} else if(errno == EACCES) {
// we don't have permission to know if
// the path/file exists.. impossible to tell
} else {
//general error handling
}
return;
}
//so, it exists.
if(S_ISDIR(info.st_mode)) {
//it's a directory
} else if(S_ISFIFO(info.st_mode)) {
//it's a named pipe
} else if(....) {
}
Se docs here for the S_ISXXX macros you can use.
The stat() function should give you everything you are looking for (or more specifically lstat() since stat() will follow the link).
Use stat (or if you wish to get information about a symbolic link instead of following it and getting information about the destination, lstat)
NAME
stat - get file status
SYNOPSIS
#include <sys/stat.h>
int stat(const char *restrict path, struct stat *restrict buf);
DESCRIPTION
The stat() function shall obtain information about the named file and write it to the area pointed to by the buf argument. The path argument points to a pathname naming a file. Read, write, or execute permission of the named file is not required. An implementation that provides additional or alternate file access control mechanisms may, under implementation-defined conditions, cause stat() to fail. In particular, the system may deny the existence of the file specified by path.
If the named file is a symbolic link, the stat() function shall continue pathname resolution using the contents of the symbolic link, and shall return information pertaining to the resulting file if the file exists.
The buf argument is a pointer to a stat structure, as defined in the header, into which information is placed concerning the file.