3

QUESTION: Is there a means to obtain a file's size as off_t with an absolute file path when the file path relative to the current working directory is not known

This may well be marked as a duplicate but I believe it sufficiently varys from questions such as this or this as I do not wish to use a relative path.

Like many folk -it appears- I fell into the trap of assuming that when looking to obtain file information stat() used absolute rather than relative (to the current working directory) pathnames. I have an absolute path to a file that I need to identify the size of as off_t. The second issue I discovered was that absolute pathnames -aside from pointing in the wrong place- may also exceed PATH_MAX from limits.h?.

The function below which was found here offers a means to obtain an off_t with a relative path. BUT this will obviously return No such file or directory via errno with an absolute path because it uses stat().

#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

off_t fsize(const char *filename) {
    struct stat st;

    if (stat(filename, &st) == 0)
        return st.st_size;

    fprintf(stderr, "Cannot determine size of %s: %s\n",
            filename, strerror(errno));

    return -1;
}

Because I know someone will ask; I was advised that chdir() is neither thread safe nor good practice; that I should avoid changing the current working directory. I was also advised to steer clear of fseek() but there was no rationale given as to why..

Community
  • 1
  • 1
Chortle
  • 171
  • 2
  • 11
  • 7
    And... What are you asking? `stat()` does work with absolute paths! – 3442 Aug 30 '15 at 21:39
  • The current directory you set with `chdir()` is like a global variable, shared between threads and affect the system calls for all threads that work with pathnames. For this reason I agree that you should only initialize it once at program startup before spawning threads. `fseek()`: I agree that you shouldn't use it when isn't necessary (and it is rarely reasonable to use it). Not all kind of streams support seeking! By not using seek operation your stream-user code becomes more generalized and can be used with a lot more kinds of streams. For example a socket is a non-seekable stream. – pasztorpisti Aug 30 '15 at 21:58
  • 1
    Ahh...I am most definately confused. – Chortle Aug 30 '15 at 22:00
  • the above function provides me with the errno error `No such file or directory` when accessing `/home/chortle/Documents/C/foo/src` despite the file existing. – Chortle Aug 30 '15 at 22:01
  • I clearly misinterpreted what was written elsewhere regarding absolute path's – Chortle Aug 30 '15 at 22:02
  • 1
    The *path* is completely irrelevant. There could be two or more directory entries pointing to the same inode. (or even zero links: fstat() could give the size of a file descriptor that does not even have a directory entry) – wildplasser Aug 30 '15 at 22:04
  • Are you sure that's the path you're passing to stat? E.g. have you checked you don't have a newline at the end of the path or anything? – user253751 Aug 30 '15 at 22:05
  • 3
    I'd recommend looking at `fstatat()`, which does absolute and relative paths, as well as removing the necessity for `chdir()`. – EOF Aug 30 '15 at 22:05
  • @immibis I hard coded as `const char*` as part of debugging `"fsize("/home/chortle/Documents/C/foo/src");` – Chortle Aug 30 '15 at 22:51
  • @EOF thanks I'll take a look; I did try fstat but the `int fd` I obtained from the file stream came back `bad file descriptor`. – Chortle Aug 30 '15 at 23:00
  • And the file path definitely exists? (`ls /home/chortle/Documents/C/foo/src` doesn't print an error, for example). And your program isn't running in a chroot jail or anything weird like that? – user253751 Aug 31 '15 at 00:26
  • @immibis; `ls` returns it so I'm guessing it does exist, and no not chrooting or jailing – Chortle Aug 31 '15 at 08:46
  • 1
    Most probably cause: a trailing space or CR in the pathname. (or for even more fun: a *backspace* ) – joop Aug 31 '15 at 10:06
  • @KemyLand thanks for correcting my understanding regarding absolute path's and to all for the quick responses. I think I'm going to have to re-look and see if it's something else messing up the call to `stat()`. – Chortle Aug 31 '15 at 12:10
  • @Chortle: Say us if you have any other question :). – 3442 Aug 31 '15 at 19:29

1 Answers1

2

stat(2) allows you to specify a file using it's full path name from the root directory (if the path starts with a /) or a relative one (otherwise, see path_resolution(7)), from your current directory. Even if you don't know any of the names (in case yo have only an open file descriptor, and you don't know the name of this file) you have the possibility of making a fstat(2) system call.

Be careful with the fact that the file size can change between the stat(2) call you make to know the file size and whatever you could do after. Think on opening with O_APPEND flag if you want to assure your write will not be interspesed with others'.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • Good edit Basile, a reference to path_resolution was the best complement to complete this answer. Thanks for the edit. – Luis Colorado Aug 31 '15 at 20:53
  • Whilst my question was poor this was the most helpful with respect to understanding `stat()` and `fstat()` was what I ended up using in the end. – Chortle Sep 02 '15 at 20:48
  • @Chortle, there's another way to get the file size using `lseek(2)`, but it has the drawback that needs an open file descriptor (not a pathname as you requested in your question) so I didn't mention it. – Luis Colorado Sep 03 '15 at 05:45