Thread overview
std.file.getAttributes/file stats
Mar 30, 2005
bobef
Mar 30, 2005
Chris Sauls
Mar 30, 2005
Ben Hinkle
Mar 31, 2005
Georg Wrede
Mar 31, 2005
Ben Hinkle
Mar 31, 2005
Georg Wrede
Mar 31, 2005
Regan Heath
Mar 31, 2005
Regan Heath
March 30, 2005
"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*?


March 30, 2005
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
March 30, 2005
"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 :-)


March 31, 2005
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.
March 31, 2005
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);
	*/
}
March 31, 2005
"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.


March 31, 2005
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.
March 31, 2005
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