www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - std.file.getAttributes/file stats

reply bobef <bobef_member pathlink.com> writes:
"uint getAttributes(char[] name) 
Get file name[] attributes."

This is what documentation says about it. And thats it. I read phobos docs over
and over, even look at the source and I keep saying to myself "how to get the
damn stats of a file?!?!?!". There is no really a fstats function or something
like that. And only Walter knows what is the getAttributes' return value (I
presume he forgot it too :)... I need these for two reasons - get readonly flag
because File.this/open crashes when owerwriting new files with readonly flag (or
throws exception maybe but I don't like exceptions and I don't use them). So I
need to check this and I have to use the ugly win32 api and also I need to get
file modification date... Windows api for that is even uglier... creating
handles and other crap. Tree functions for this simple task!!! Any ideas how to
do these things in *D*?
Mar 30 2005
next sibling parent reply Chris Sauls <ibisbasenji gmail.com> writes:
To check for read-only in Windows:
#
# import std.file;
# import std.c.windows.windows;
#
# bit isReadOnlyFile (char[] path) {
#   uint attr = getAttributes(path);
#   return (attr & FILE_ATTRIBUTE_READONLY) != 0;
# }
#

The getAttributes() function returns the local operating system's 
bitmask for file attributes, so use the constants defined in the 
appropriate system module.

Unfortunately as far as I know the only way to get things like the 
modification date is to use the Win32 API calls.

-- Chris Sauls
Mar 30 2005
next sibling parent "Ben Hinkle" <bhinkle mathworks.com> writes:
"Chris Sauls" <ibisbasenji gmail.com> wrote in message 
news:d2f46h$22v3$1 digitaldaemon.com...
 To check for read-only in Windows:
 #
 # import std.file;
 # import std.c.windows.windows;
 #
 # bit isReadOnlyFile (char[] path) {
 #   uint attr = getAttributes(path);
 #   return (attr & FILE_ATTRIBUTE_READONLY) != 0;
 # }
 #

 The getAttributes() function returns the local operating system's bitmask 
 for file attributes, so use the constants defined in the appropriate 
 system module.

 Unfortunately as far as I know the only way to get things like the 
 modification date is to use the Win32 API calls.

 -- Chris Sauls

That would be good to add to std.file right next to isfile and isdir. To have a consistent naming convention something like isfile would be nice. Nothing comes to mind, though. The error message that the constructor for std.stream.File throws if you try to open a read-only file as writeable stinks, though. It just says "file blah not found". I'll put that on the list of future changes for std.stream. I don't want to send Walter a third copy in the last week or so :-)
Mar 30 2005
prev sibling parent reply Georg Wrede <georg.wrede nospam.org> writes:
Chris Sauls wrote:
 To check for read-only in Windows:
 #
 # import std.file;
 # import std.c.windows.windows;
 #
 # bit isReadOnlyFile (char[] path) {
 #   uint attr = getAttributes(path);
 #   return (attr & FILE_ATTRIBUTE_READONLY) != 0;
 # }
 #
 
 The getAttributes() function returns the local operating system's 
 bitmask for file attributes, so use the constants defined in the 
 appropriate system module.
 
 Unfortunately as far as I know the only way to get things like the 
 modification date is to use the Win32 API calls.

Ok, we have two distinctly separate issues. On windows, it is essentially _one_ user at the computer. Then, issues like, checking for a read-only file are "straight forward". On the other operating systems (linux, unix, etc) one usually tries to write programs as if there were several users. That results in things like "not trying to get a Unique Temporary File Name", and then using it, because, by definition, on the non-windows systems one has to expect that a million things may happen between the time you get the name and start using it. On a sorry one-user system, it is obvious that a program can ask the OS for a Unique Temporary file name, and then use it. On a Real operating system one has to prepare for the fact that _between_ the time you get a suggestion from the operating system for a Unique file name, and actually start writing to such a file, there may be 2 million other users who've been at the same situation. Back to the issue at hand: if you check for read-only in one function, and then write to the file, there is the risk of something happening between the check and the write. So, we need to "open the file" and then check whether it succeeded or not. If it succeeded, then go ahead and write to it. In other words, the opening and desicion whether to write to the file, have to be "atomic" -- on any other operating system than Windows. Of course, this may not be an issue, unless you want to write software that is portable between Windows and Operating Systems.
Mar 30 2005
parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Georg Wrede" <georg.wrede nospam.org> wrote in message 
news:424B3D5E.5000009 nospam.org...
 Chris Sauls wrote:
 To check for read-only in Windows:
 #
 # import std.file;
 # import std.c.windows.windows;
 #
 # bit isReadOnlyFile (char[] path) {
 #   uint attr = getAttributes(path);
 #   return (attr & FILE_ATTRIBUTE_READONLY) != 0;
 # }
 #

 The getAttributes() function returns the local operating system's bitmask 
 for file attributes, so use the constants defined in the appropriate 
 system module.

 Unfortunately as far as I know the only way to get things like the 
 modification date is to use the Win32 API calls.

Ok, we have two distinctly separate issues. On windows, it is essentially _one_ user at the computer. Then, issues like, checking for a read-only file are "straight forward". On the other operating systems (linux, unix, etc) one usually tries to write programs as if there were several users. That results in things like "not trying to get a Unique Temporary File Name", and then using it, because, by definition, on the non-windows systems one has to expect that a million things may happen between the time you get the name and start using it. On a sorry one-user system, it is obvious that a program can ask the OS for a Unique Temporary file name, and then use it. On a Real operating system one has to prepare for the fact that _between_ the time you get a suggestion from the operating system for a Unique file name, and actually start writing to such a file, there may be 2 million other users who've been at the same situation. Back to the issue at hand: if you check for read-only in one function, and then write to the file, there is the risk of something happening between the check and the write. So, we need to "open the file" and then check whether it succeeded or not. If it succeeded, then go ahead and write to it. In other words, the opening and desicion whether to write to the file, have to be "atomic" -- on any other operating system than Windows. Of course, this may not be an issue, unless you want to write software that is portable between Windows and Operating Systems.

I don't know why you think Windows is special here. All modern OSes multitask so what you describe can happen whenever one has multiple processes running. If the file system is shared (which Windows can do, in case you haven't use it) all bets are off. Your general point is valid, though, ignoring the Windows part. To the OP: to be successful with D on moderate to large projects you will need to be comfortable with exception handling.
Mar 30 2005
parent reply Georg Wrede <georg.wrede nospam.org> writes:
Ben Hinkle wrote:
 "Georg Wrede" <georg.wrede nospam.org> wrote 
So, we need to "open the file" and then check whether it succeeded or not. 
If it succeeded, then go ahead and write to it. In other words, the 
opening and desicion whether to write to the file, have to be "atomic" --  
on any other operating system than Windows.

Of course, this may not be an issue, unless you want to write software 
that is portable between Windows and Operating Systems.

I don't know why you think Windows is special here. All modern OSes multitask so what you describe can happen whenever one has multiple processes running. If the file system is shared (which Windows can do, in case you haven't use it) all bets are off. Your general point is valid, though, ignoring the Windows part.

Well, Windows programming traditionally meant two things uncommon for unix programming: - You use the resources as if your program was the only one running (i.e. use memory as you please, use cpu cycles like you owned the computer, use other resources as if you were alone, etc.) - While theoretically it is possible that somebody else, or the same user in another process, is competing for some of the resources (devices, write access to a file, or even temporary file names), in practice it is unlikely that there are clashes. In normal circumstances Windows is used, at the most, as a file server, for a workgroup. The average use, however, is one person at the keyboard. Contrast that to unix (and Linux, by inheritance of philosophy). One has to always assume 100s of users. It is considered _very_ impolite to use memory casually, opening devices and not closing them right at the first possible moment, or in general using the machine/resources as if you were alone. I admit, that a lot of Linuxes are today used on single-user workstations or laptops. But the philosophy and practices stick. The programmer cannot know in advance that there'll be only one user. For example, Open Office text document writer seems to be a good candidate for a single-user program. But, Sun offices around the world, and even regular offices that have abandoned the Microsoft Office suite, do tend to run Writer for several people on the same machine. Back to the trivia: because of the above, it is not "dangerous" on a windows machine to first get a temporary file name (or first check whether a file is writable), and then use the file. Equally: on a unix machine it is "deplorable" to check and use a file in separate commands. On a windows machine you (as a programmer) are unlikely to get fired for doing it. Yes, we have shared Windows computers. But "max 3, average 1.0003" is different from "max 300, average 125" users. Oh, and yes, you are correct, Windows is not alone here, Mac OS X would fall in the Windows category too. Not for any other reason, (definitely not philosophical, since it is based on a Real Operating System) but because it (to my knowledge, Anders will correct if I'm wrong) is mainly used by a single person.
Mar 30 2005
parent "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 31 Mar 2005 06:22:18 +0300, Georg Wrede <georg.wrede nospam.org>  
wrote:
 Back to the trivia: because of the above, it is not "dangerous" on a  
 windows machine to first get a temporary file name (or first check  
 whether a file is writable), and then use the file.

It's dangerous in any situation where it matters regardless of OS.
 Equally: on a unix machine it is "deplorable" to check and use a file in  
 separate commands. On a windows machine you (as a programmer) are  
 unlikely to get fired for doing it.

You're assuming "Windows" means "single-user" which is incorrect. Sure, most desktop pcs are running windows. But that's irrelevant, what is relevant is what type of software you are writing, for example: I am involved with a piece of mail server software, it runs on windows, linux, freebsd, macosx, solaris x86 and sparc, ... when writing code for this I have to keep in mind the situation you describe, I can't simply ignore it on windows, I can't treat windows any differently than linux, or any other OS.
 Yes, we have shared Windows computers. But "max 3, average 1.0003" is  
 different from "max 300, average 125" users.

So you're using *your* windows machines as single-user/desktop machines and not as servers. Arguably it's what they we're designed to do best. Regan
Mar 30 2005
prev sibling parent "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 30 Mar 2005 20:30:43 +0000 (UTC), bobef  
<bobef_member pathlink.com> wrote:
 "uint getAttributes(char[] name)
 Get file name[] attributes."

 This is what documentation says about it. And thats it. I read phobos  
 docs over
 and over, even look at the source and I keep saying to myself "how to  
 get the
 damn stats of a file?!?!?!". There is no really a fstats function or  
 something
 like that. And only Walter knows what is the getAttributes' return value  
 (I
 presume he forgot it too :)... I need these for two reasons - get  
 readonly flag
 because File.this/open crashes when owerwriting new files with readonly  
 flag (or
 throws exception maybe but I don't like exceptions and I don't use  
 them). So I
 need to check this and I have to use the ugly win32 api and also I need  
 to get
 file modification date... Windows api for that is even uglier... creating
 handles and other crap. Tree functions for this simple task!!! Any ideas  
 how to
 do these things in *D*?

This might be useful: import std.stream; import std.stdio; extern (C) { struct _stat { uint st_dev; ushort st_ino; ushort st_mode; short st_nlink; short st_uid; short st_gid; // uint st_rdev; uint st_size; uint st_atime; uint st_mtime; uint st_ctime; } int stat(char *path, _stat *buffer); } void main() { _stat buf; File f; f = new File("test36.txt",FileMode.Out); f.writeLine("Line 1"); f.writeLine("Line 2"); f.close(); if (stat("test36.txt",&buf) == -1) writefln("FAIL"); else { writefln("st_dev: ",buf.st_dev); writefln("st_ino: ",buf.st_ino); writefln("st_mode: ",buf.st_mode); writefln("st_nlink: ",buf.st_nlink); writefln("st_uid: ",buf.st_uid); writefln("st_gid: ",buf.st_gid); writefln("st_size: ",buf.st_size); writefln("st_atime: ",buf.st_atime); writefln("st_mtime: ",buf.st_mtime); writefln("st_ctime: ",buf.st_ctime); } /* printf("st_dev (%d)(%x)(%x)(%d): %d\n",buf.st_dev.sizeof, cast(void *)&buf,cast(void *)&buf.st_dev, cast(void *)&buf.st_dev - cast(void *)&buf, buf.st_dev); printf("st_ino (%d)(%x)(%x)(%d): %d\n",buf.st_ino.sizeof, cast(void *)&buf,cast(void *)&buf.st_ino, cast(void *)&buf.st_ino - cast(void *)&buf, buf.st_ino); printf("st_mode (%d)(%x)(%x)(%d): %d\n",buf.st_mode.sizeof, cast(void *)&buf,cast(void *)&buf.st_mode, cast(void *)&buf.st_mode - cast(void *)&buf, buf.st_mode); printf("st_nlink(%d)(%x)(%x)(%d): %d\n",buf.st_nlink.sizeof,cast(void *)&buf,cast(void *)&buf.st_nlink,cast(void *)&buf.st_nlink - cast(void *)&buf,buf.st_nlink); printf("st_uid (%d)(%x)(%x)(%d): %d\n",buf.st_uid.sizeof, cast(void *)&buf,cast(void *)&buf.st_uid, cast(void *)&buf.st_uid - cast(void *)&buf, buf.st_uid); printf("st_gid (%d)(%x)(%x)(%d): %d\n",buf.st_gid.sizeof, cast(void *)&buf,cast(void *)&buf.st_gid, cast(void *)&buf.st_gid - cast(void *)&buf, buf.st_gid); //printf("st_rdev (%d)(%x)(%x)(%d): %d\n",buf.st_rdev.sizeof, cast(void *)&buf,cast(void *)&buf.st_rdev, cast(void *)&buf.st_rdev - cast(void *)&buf, buf.st_rdev); printf("st_size (%d)(%x)(%x)(%d): %d\n",buf.st_size.sizeof, cast(void *)&buf,cast(void *)&buf.st_size, cast(void *)&buf.st_size - cast(void *)&buf, buf.st_size); printf("st_atime(%d)(%x)(%x)(%d): %d\n",buf.st_atime.sizeof,cast(void *)&buf,cast(void *)&buf.st_atime,cast(void *)&buf.st_atime - cast(void *)&buf,buf.st_atime); printf("st_mtime(%d)(%x)(%x)(%d): %d\n",buf.st_mtime.sizeof,cast(void *)&buf,cast(void *)&buf.st_mtime,cast(void *)&buf.st_mtime - cast(void *)&buf,buf.st_mtime); printf("st_ctime(%d)(%x)(%x)(%d): %d\n",buf.st_ctime.sizeof,cast(void *)&buf,cast(void *)&buf.st_ctime,cast(void *)&buf.st_ctime - cast(void *)&buf,buf.st_ctime); */ }
Mar 30 2005