Getting the file name from a FILE *

B

Bartc

Ben Bacarisse said:
How would you deal with hard links? Soft links (aliases)? Streams
opened by functions other than fopen() or freopen()? Are you
returning simply the file name, or the full path name (if you're
talking about error messages, the full path name would be useful)? If
there is no name associated with the file, would you return an empty
string or NULL? How would you distinguish between streams that had no
name to begin with vs. streams where the name could not be stored due
to an error?

This is one of the odd argument where I find myself on both sides. I
think these problems miss the point -- it always up the programmer to
know if a file name makes any sense, and it seems all Jacob is
suggesting is that he store what use at the point of the open call and
offer to return it later[1]. (Personally I would not copy it. I'd
store the pointer used in the fopen/freopen and hand that back when
asked.)

Sounds very dangerous to just store a pointer. The original argument may
have pointed to a temporary value. Or to a local variable now out of scope.
Or to a buffer now with different contents.
[1] If he is proposing something stronger (like trying to find some
canonical representation of the opened file's name and storing that)
then I agree that these criticisms are valid, but I thought (at least
at first) he was simply suggesting that the pointer be stored.

Since lccwin is for Windows there is already an OS-specific call to obtain
the normalised (as I term it) form of the file.
 
L

Lew Pitcher

For tempfile() should return... the name of the temporary file of course
For stdin it will return an invalid file name (either NULL or
"....stdin...." or similar.
For stdout/stderr the same.

What if stdin, stdout, or stderr have been redirected to a file? As in

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\Documents and Settings\Guest>md temp
C:\Documents and Settings\Guest>cd temp
C:\Documents and Settings\Guest\temp>dir >thisfile.txt
C:\Documents and Settings\Guest\temp>type thisfile.txt
Volume in drive C has no label.
Volume Serial Number is 061E-1ADD

Directory of C:\Documents and Settings\Guest\temp

06/23/2008 11:15 AM <DIR> .
06/23/2008 11:15 AM <DIR> ..
06/23/2008 11:16 AM 0 thisfile.txt
1 File(s) 0 bytes
2 Dir(s) 4,884,660,224 bytes free

C:\Documents and Settings\Guest\temp>

It seems to me that, if you offer a function to return the filename of a
FILE *, and there /is/ a filename for the file, then you should return the
actual name, and not something concocted by the runtimelibrary as a
standin.

[snip]

--
Lew Pitcher

Master Codewright & JOAT-in-training | Registered Linux User #112576
http://pitcher.digitalfreehold.ca/ | GPG public key available by request
---------- Slackware - Because I know what I'm doing. ------
 
R

Richard Tobin

fname receives a FILE *. not a file descriptor

Does your operating system have no way to get a FILE * other than
fopen() and freopen()? E.g. functions like unix's popen() and
fdopen()? If so, presumably you will return NULL for these.
For stdin stdout and stderr "..stdin.." "..stdout.." and "..stderr.."
is returned.

In that case it might be better to consistently return a string and
never NULL. For example, "..unknown.." or "..closed..".

Are filenames starting ".." impossible? They aren't on other systems,
so if you have an idea that this might be adopted elsewhere you might
want to use something different, though I can't see a nice solution.

-- Richard
 
S

Serve Lau

Nick Keighley said:
is this documented in the standard? There's mention in this
thread of OSs that support 10,000 (or more) open files. Do they
create 10,000 file structures on startup? Sounds a bit wasteful...

It is somewhat:

Environmental limits
The value of FOPEN_MAX shall be at least eight, including the three standard
text streams.

And in most implementations I've seen FOPEN_MAX is the limit as far as C is
concerned.
They declare "FILE iob[FOPEN_MAX];" and start returning NULL if you want to
fopen more. When you do want more you will have to go system specific or
start different processes.
What better way is there to assure that the standard streams are opened and
ready. I guess one could do
iob = malloc(FOPEN_MAX * sizeof(*iob));
if (iob == NULL) exit(1);
but nothing is as deterministic on any platform using just FILE
iob[FOPEN_MAX]

Adding filenames to FILE will make things less deterministic, its
application programming moved into system libraries without the programmer
knowing about it. When no memory could be allocated for the filename it will
store NULL but return a valid pointer in lccwin32. That means that every
time you call fname() you have to check for NULL and I'm pretty sure people
will forget that at some point.
 
A

Antoninus Twink

In that case it might be better to consistently return a string and
never NULL. For example, "..unknown.." or "..closed..".

Are filenames starting ".." impossible? They aren't on other systems,
so if you have an idea that this might be adopted elsewhere you might
want to use something different, though I can't see a nice solution.

Jacob has said that he will return NULL rather than the empty string if
the filename isn't available, so he could adopt the convention that if
_fname(fp) isn't null, and if *_fname(fp) is '\0', then _fname(fp)+1
points to a "special string" like "..stdin.." or whatever. This will be
fine unless you want to port to a system where filenames can contain
'\0' or where filenames can be zero-length.
 
B

Ben Bacarisse

Richard Heathfield said:
Ben Bacarisse said:

[...] it seems all Jacob is
suggesting is that he store what use at the point of the open call and
offer to return it later[1]. (Personally I would not copy it. I'd
store the pointer used in the fopen/freopen and hand that back when
asked.)

Alas, that won't work. Consider:

size_t n = strlen(argv[1] + sizeof ".txt";
char *name = malloc(n);
if(name != NULL && sprintf(name, "%s.txt", argv[1]))
{
FILE *fp = fopen(name, "w");
free(name);
if(fp != NULL)
{
char *whatever = malloc(n);
if(whatever != NULL)
{
sprintf(whatever, "%s.foo", argv[1]);

Perfectly legal C, but now name no longer points anywhere legal. The second
call to malloc may well return the same address as the first call (because
there is an intervening free and the requested size is after all the same
as before). So a call to _fname or whatever, at this point, would return
the wrong name.

That's a rather convoluted example -- there are lots a cases where the
string used to open file is either no longer there or has been
replaced by something else. The simplest examples would a buffer that
gets re-used, or a "local" that goes out of scope.

I may have got the wrong end of the stick. It was my understanding
that the idea was simply for the convenience of the programmer. The
advantage of the simple pointer copy interface is that just that -- it
is simple to understand and therefore the programmer should know if
the returned result is usable or not. If they need to track the file
name and choose to use Jacob's extension (with this pointer copy
semantics) then they better make sure the file name sticks around and
remains unmodified.

Reviewing the thread, however, there is some evidence that Jacob wants
the *library* to be able to use the name. If that is the case then of
course a pointer is no use. If I'd picked on that hint I'd still have
suggested just copying the pointer, but I'd have added that the
library should not use it! The benefit to the library of taking a
copy of the name seems too small to be worth the kerfuffle.
 
R

Richard Tobin

Antoninus Twink said:
Jacob has said that he will return NULL rather than the empty string if
the filename isn't available, so he could adopt the convention that if
_fname(fp) isn't null, and if *_fname(fp) is '\0', then _fname(fp)+1
points to a "special string" like "..stdin.." or whatever.

Yes, I almost suggested that. But it's a bit ugly, isn't it.
This will be
fine unless you want to port to a system where filenames can contain
'\0' or where filenames can be zero-length.

Traditionally on unix systems the empty string refers to the current
directory, and you can, on some systems and some filesystems, fopen()
it. However, this is such a special case that simply setting the
"special string" to something like "(empty)" would handle it.

-- Richard
 
I

Ian Collins

CBFalconer said:
Exactly. So now you see the savings in not having fname.
Isn't that the C philosophy: you don't pay for what you don't want?

How often do people want to associate a file name with a FILE object? I
can't think of a time when I have and I certainly would want either the
time or space overhead on a embedded system.
 
J

jacob navia

Ian said:
Isn't that the C philosophy: you don't pay for what you don't want?

How often do people want to associate a file name with a FILE object?

Every time
fopen(filename,mode);

A FILE object *is* an association between a name and a disk region.
I
can't think of a time when I have and I certainly would want either the
time or space overhead on a embedded system.

There is no time or overhead involved here. The passed pointer is copied
and that is it. The overhead is minimal compared to all the fields,
buffers and other things fopen must do.

This is a first step in a more general set of functions to get
the properties of a file.
 
I

Ian Collins

jacob said:
Every time
fopen(filename,mode);

A FILE object *is* an association between a name and a disk region.
Quite, the disk region is distinct from one of its possible names. As
others have said, the name my change or the file may not have a name
after it is opened.

A FILE is a data source and or sink, the name is immaterial. In most
code I've seen or written, the only place where the name is important is
the place where the file is opened.
There is no time or overhead involved here. The passed pointer is copied
and that is it. The overhead is minimal compared to all the fields,
buffers and other things fopen must do.
A buffer has to be allocated and and the name copied. True this may
take a trivial time compared with opening a disk file, but not compared
to opening a (FLASH) memory based file. The extra buffer (be it static
or dynamic) would be an issue on small systems that use files.

I still think the you don't pay for what you don't want manta should
apply here, if you want to pass the name around, encapsulate the FILE
pointer and name in a struct and pass that.
This is a first step in a more general set of functions to get
the properties of a file.
Which would be incredibly hard to do given the large number of file
system types with their unique set of properties and characteristics.
You might be interesting in seeing where the C++ world is going with
this, if so check out boost.filesystem.
 
N

Nick Keighley

sorry, no. What is the saving? (I'm not, incidently, in favour
of Jacob's proposal- but I think the criticism should
be rational and clear).

Isn't that the C philosophy: you don't pay for what you don't want?

How often do people want to associate a file name with a FILE object?  

every time there's an error reading a file.

Error: inifile_read.c line 230: parse error reading "BLOB_COUNT"
I
can't think of a time when I have and I certainly would want either the
time or space overhead on a embedded system.

fair point


--
Nick Keighley

"XML is isomorphic to the subset of Lisp data
where the first item in a list is required to be atomic."
John McCarthy
 
N

Nick Keighley

Every time
        fopen(filename,mode);

A FILE object *is* an association between a name and a disk region.

no it isn't This is you fundamental misconception.
Read up on how unix works.


There is no time or overhead involved here. The passed pointer is copied
and that is it.

time and space overhead.

The overhead is minimal compared to all the fields,
buffers and other things fopen must do.

This is a first step in a more general set of functions to get
the properties of a file.

such as? Can you make them platform independant?
 
I

Ian Collins

Nick said:
sorry, no. What is the saving? (I'm not, incidently, in favour
of Jacob's proposal- but I think the criticism should
be rational and clear).



every time there's an error reading a file.
The name is know at the point where the file is opened, otherwise it
would be a little difficult opening it...
 
N

Nick Keighley

Nick Keighleywrote:



The name is know at the point where the file is opened, otherwise it
would be a little difficult opening it...

I said *reading* not opening. And you snipped the example
 
R

Richard

Nick Keighley said:
I said *reading* not opening. And you snipped the example

It's called "memory Nick". Try "remembering" the name in a "variable" or
similar. It's complicated but good.
 
N

Nick Keighley

It's called "memory Nick". Try "remembering" the name in a "variable" or
similar. It's complicated but good

que?

I was argueing there *was* reason for sometimes requiring the filename
after the fopen(). So, yes, I store it in a variable. Your point?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,229
Latest member
GloryAngul

Latest Threads

Top