digitalmars.D.learn - No tempFile() in std.file
- =?UTF-8?B?Tm9yZGzDtnc=?= (5/5) May 15 2017 Why isn't there a function, say `tempFile()`, in
- Jonathan M Davis via Digitalmars-d-learn (30/34) May 15 2017 We have std.stdio.File.tmpfile, which is kind of terrible, because you c...
- Era Scarecrow (6/11) May 15 2017 I'm reminded of doing the same thing with C++ using streams and
- Anonymouse (3/15) May 16 2017 Linker --gc-sections, though in my experience it doesn't cull
- Jacob Carlborg (5/6) May 16 2017 IIRC that only works with LDC. With DMD it's possible that it removes
- bachmeier (6/13) May 16 2017 That seems perfectly reasonable to me. Couldn't the function
- Jonathan M Davis via Digitalmars-d-learn (11/24) May 16 2017 std.file doesn't have anything to do with File. It only operates on enti...
- bachmeier (3/14) May 16 2017 Okay, now I see your point. Your proposal is still a lot better
- Patrick Schluter (6/27) May 16 2017 As your solution doesn't inherently solve the race condition
- Patrick Schluter (4/11) May 16 2017 But as Jonathan said above, this is not a good solution in any
- Jonathan M Davis via Digitalmars-d-learn (40/52) May 17 2017 As I recall, the main problem with mks*temp() is that some platforms onl...
- H. S. Teoh via Digitalmars-d-learn (29/37) May 16 2017 [...]
- H. S. Teoh via Digitalmars-d-learn (10/22) May 16 2017 [...]
- Jonathan M Davis via Digitalmars-d-learn (13/30) May 16 2017 wrote:
Why isn't there a function, say `tempFile()`, in https://dlang.org/phobos/std_file.html that creates a temporary _file_ when we already have https://dlang.org/phobos/std_file.html#tempDir ?
May 15 2017
On Monday, May 15, 2017 21:52:27 Nordlöw via Digitalmars-d-learn wrote:Why isn't there a function, say `tempFile()`, in https://dlang.org/phobos/std_file.html that creates a temporary _file_ when we already have https://dlang.org/phobos/std_file.html#tempDirWe have std.stdio.File.tmpfile, which is kind of terrible, because you can't get at its name, and it gets deleted as soon as the File is destroyed. And we briefly had std.stdio.File.scratchFile (IIRC someone didn't like tempFile for one reason or another, which is what I had named it originally), but it pulled in enough dependencies (IIRC, beacuse it used tempDir, which is in std.file, std.datetime got pulled in, because other stuff in std.file uses SysTime, and std.datetime pulled in yet more...) that hello world grew considerably in size (since it uses std.stdio and File for writeln), and there was enough screaming about that that the function was removed. I don't remember what the proposal was for what we needed to do to fix having a bunch of Phobos pulled in to make scratchFile work, but until that's been sorted out, we're kind of stuck, as stupid as that is: https://issues.dlang.org/show_bug.cgi?id=14599 Personally, I think that it would be very much worth making hello world larger, since hello world really doesn't matter, but because there are plenty of folks checking out D who write hello world and then look at the executable size, it was considered unacceptable for it to get much larger. Now, we _could_ add a tempFile to std.file which returned a supposedly unique filename in tempDir, but simply using it would result in a race condition, because (as unlikely as it may be) someone else could create the file between the time that you get the file name from tempFile and the time when you try to open it to write to it - that's why using a solution that involves opening the file is needed. I suppose that we could add a tempFile that did what std.stdio.File.scratchFile did but create an empty file and return its path rather than returning a File, though that would be a bit annoying, since you'd then have to open it to operate on it instead of just writing to it. Maybe it would be worth doing though given the stupidity blocking std.stdio.File.scratchFile. - Jonathan M Davis
May 15 2017
On Monday, 15 May 2017 at 22:38:15 UTC, Jonathan M Davis wrote:Personally, I think that it would be very much worth making hello world larger, since hello world really doesn't matter, but because there are plenty of folks checking out D who write hello world and then look at the executable size, it was considered unacceptable for it to get much larger.I'm reminded of doing the same thing with C++ using streams and saw the size explode from 60k or so to something like 400k, for seemingly no good reason at all. Hmmm while we're on the subject of size, is there a tool to strip out functions that are never used from the final executable?
May 15 2017
On Tuesday, 16 May 2017 at 05:09:12 UTC, Era Scarecrow wrote:On Monday, 15 May 2017 at 22:38:15 UTC, Jonathan M Davis wrote:Linker --gc-sections, though in my experience it doesn't cull much. Add --print-gc-sections to see what it does remove.Personally, I think that it would be very much worth making hello world larger, since hello world really doesn't matter, but because there are plenty of folks checking out D who write hello world and then look at the executable size, it was considered unacceptable for it to get much larger.I'm reminded of doing the same thing with C++ using streams and saw the size explode from 60k or so to something like 400k, for seemingly no good reason at all. Hmmm while we're on the subject of size, is there a tool to strip out functions that are never used from the final executable?
May 16 2017
On 2017-05-16 09:39, Anonymouse wrote:Linker --gc-sectionsIIRC that only works with LDC. With DMD it's possible that it removes sections that are used but not directly referenced. -- /Jacob Carlborg
May 16 2017
On Monday, 15 May 2017 at 22:38:15 UTC, Jonathan M Davis wrote:I suppose that we could add a tempFile that did what std.stdio.File.scratchFile did but create an empty file and return its path rather than returning a File, though that would be a bit annoying, since you'd then have to open it to operate on it instead of just writing to it. Maybe it would be worth doing though given the stupidity blocking std.stdio.File.scratchFile.That seems perfectly reasonable to me. Couldn't the function return both the path and the file in a struct? This is something that really should be in Phobos. It's one of those little things that makes D a lot less pleasurable to work with, at least for anyone needing that functionality.
May 16 2017
On Tuesday, May 16, 2017 11:19:14 bachmeier via Digitalmars-d-learn wrote:On Monday, 15 May 2017 at 22:38:15 UTC, Jonathan M Davis wrote:std.file doesn't have anything to do with File. It only operates on entire files at a time, so it wouldn't make sense for a function in std.file to return a std.stdio.File. At most what would make sense to me would be to have a function in std.file which created the file as empty and closed it and then returned the file name for the program to then open or do whatever else it wants with - which would actually be perfectly fine if you then wanted to use std.file.write or similar to the file. It's just more annoying if you want a File, because then you end up effectively opening the file twice. - Jonathan M DavisI suppose that we could add a tempFile that did what std.stdio.File.scratchFile did but create an empty file and return its path rather than returning a File, though that would be a bit annoying, since you'd then have to open it to operate on it instead of just writing to it. Maybe it would be worth doing though given the stupidity blocking std.stdio.File.scratchFile.That seems perfectly reasonable to me. Couldn't the function return both the path and the file in a struct? This is something that really should be in Phobos. It's one of those little things that makes D a lot less pleasurable to work with, at least for anyone needing that functionality.
May 16 2017
On Tuesday, 16 May 2017 at 13:56:57 UTC, Jonathan M Davis wrote:std.file doesn't have anything to do with File. It only operates on entire files at a time, so it wouldn't make sense for a function in std.file to return a std.stdio.File. At most what would make sense to me would be to have a function in std.file which created the file as empty and closed it and then returned the file name for the program to then open or do whatever else it wants with - which would actually be perfectly fine if you then wanted to use std.file.write or similar to the file. It's just more annoying if you want a File, because then you end up effectively opening the file twice. - Jonathan M DavisOkay, now I see your point. Your proposal is still a lot better than doing nothing.
May 16 2017
On Tuesday, 16 May 2017 at 13:56:57 UTC, Jonathan M Davis wrote:On Tuesday, May 16, 2017 11:19:14 bachmeier via Digitalmars-d-learn wrote:As your solution doesn't inherently solve the race condition associated with temporary files, you could still generate the name with a wrapper around tempnam() or tmpnam() (Posix for Windows I don't know). This would avoid the double open() of the scenario above.On Monday, 15 May 2017 at 22:38:15 UTC, Jonathan M Davis wrote:std.file doesn't have anything to do with File. It only operates on entire files at a time, so it wouldn't make sense for a function in std.file to return a std.stdio.File. At most what would make sense to me would be to have a function in std.file which created the file as empty and closed it and then returned the file name for the program to then open or do whatever else it wants with - which would actually be perfectly fine if you then wanted to use std.file.write or similar to the file. It's just more annoying if you want a File, because then you end up effectively opening the file twice. - Jonathan M Davis[...]That seems perfectly reasonable to me. Couldn't the function return both the path and the file in a struct? This is something that really should be in Phobos. It's one of those little things that makes D a lot less pleasurable to work with, at least for anyone needing that functionality.
May 16 2017
On Wednesday, 17 May 2017 at 05:30:40 UTC, Patrick Schluter wrote:On Tuesday, 16 May 2017 at 13:56:57 UTC, Jonathan M Davis wrote:But as Jonathan said above, this is not a good solution in any case. In Posix the use the mks*temp() family of functions is standard now.[...]As your solution doesn't inherently solve the race condition associated with temporary files, you could still generate the name with a wrapper around tempnam() or tmpnam() (Posix for Windows I don't know). This would avoid the double open() of the scenario above.
May 16 2017
On Wednesday, May 17, 2017 05:34:50 Patrick Schluter via Digitalmars-d-learn wrote:On Wednesday, 17 May 2017 at 05:30:40 UTC, Patrick Schluter wrote:As I recall, the main problem with mks*temp() is that some platforms only support a stupidly short list af random values (something like 26 IIRC). Regardless, it's trivial to write that functionality yourself. The key is that you open the file with the flag that indicates that the file must not exist when you open it. Worst case, you have to try a few times with different file names, but if you generate something like a UUID, then the odds of a collision are so low that that's not realistically an issue. And AFAIK, for mks*temp() to guarantee that the file was created by the call, it has to do basically the same thing internally. But in any case, even if we wanted to use mks*temp() in a D program, we'd want to wrap it in a portable D function using D's strings and not char*. So, whether mks*temp() is used is an implementation detail. For the use case where you actually want a file name rather than just a file handle to play around with, you're almost certainly going to be closing and reopening the file or closing it and handing its path off to another program, in which case, the only real downside to having a function that securely creates an empty temporary file and returns its path is that you then have to open it a second time to put actual data in it, whereas a function like scratchFile lets you start writing to it without opening it again. Regardless, as long as a program can get the path to the file, and has the appropriate permissions, as I understand it, there's a risk of them screwing with it even if you have it open (at least on POSIX systems which don't normally use file locks and where - as I understand it - obeying the file locks is completely optional, unlike Windows which likes to lock everything). So, while having scratchFile would definitely be nice, maybe a good solution would be to add function to std.file such as writeToTempFile which acted like std.file.write except that it created a temporary file which was guaranteed to not exist prior to the call and returned its path after it wrote to it. If you want to use std.stdio.File with it, you're still forced to write an empty file and then open it again with File, but for the case where you simply want to write the data to a file and then pass the path to something else to use it (be it something in your program or another program), it should work well. Certainly, it would be far better than what we have now (which would be nothing). So, I should probably dig up my scratchFile implementation and adapt it for std.file as something like writeToTempFile or createTempFile. - Jonathan M DavisOn Tuesday, 16 May 2017 at 13:56:57 UTC, Jonathan M Davis wrote:But as Jonathan said above, this is not a good solution in any case. In Posix the use the mks*temp() family of functions is standard now.[...]As your solution doesn't inherently solve the race condition associated with temporary files, you could still generate the name with a wrapper around tempnam() or tmpnam() (Posix for Windows I don't know). This would avoid the double open() of the scenario above.
May 17 2017
On Tue, May 16, 2017 at 06:56:57AM -0700, Jonathan M Davis via Digitalmars-d-learn wrote:On Tuesday, May 16, 2017 11:19:14 bachmeier via Digitalmars-d-learn wrote:[...] Don't forget that there are security concerns related to this. Most modern OS APIs tend to prefer a temp file creation call that atomically (1) generates a unique filename and (2) creates a file with said filename with permissions set such that it can only be exclusively used by the calling process. The reason for this is that there is a race condition between the generation of the filename and the creation of the file. On Posix, for example, an attacker could guess the generated filename and preemptively create the temp file with unexpected content that may cause the program to malfunction (usually to trigger another security flaw and thereby cause arbitrary code execution or privilege escalation, etc.), or to substitute a symlink that points to a file the program shouldn't be writing to / reading from (e.g., /etc/passwd). Actual exploits have been carried out using this route, hence it's something application programmers need to be aware of. (Note that even if your program doesn't do anything directly security related, it may still be an issue; e.g., it could be a music player but an attacker could potentially leverage it to read sensitive files by redirecting file operations or cause a malfunction that gives the attacker escalation of privileges, e.g., a remote attacker gaining shell access on a local user account, from which further attacks can be launched. In this day and age of advanced exploits being widely disseminated over the 'net, these scenarios are far more likely than we'd like to think.) T -- Без труда не выловишь и рыбку из пруда.On Monday, 15 May 2017 at 22:38:15 UTC, Jonathan M Davis wrote:I suppose that we could add a tempFile that did what std.stdio.File.scratchFile did but create an empty file and return its path rather than returning a File, though that would be a bit annoying, since you'd then have to open it to operate on it instead of just writing to it. Maybe it would be worth doing though given the stupidity blocking std.stdio.File.scratchFile.
May 16 2017
On Tue, May 16, 2017 at 08:06:13AM -0700, H. S. Teoh via Digitalmars-d-learn wrote:On Tue, May 16, 2017 at 06:56:57AM -0700, Jonathan M Davis via Digitalmars-d-learn wrote:[...] Cf.: https://cwe.mitre.org/data/definitions/377.html https://cwe.mitre.org/data/definitions/378.html https://security.stackexchange.com/questions/34397/how-can-an-attacker-use-a-fake-temp-file-to-compromise-a-program https://security.openstack.org/guidelines/dg_using-temporary-files-securely.html T -- A bend in the road is not the end of the road unless you fail to make the turn. -- Brian WhiteOn Tuesday, May 16, 2017 11:19:14 bachmeier via Digitalmars-d-learn wrote:[...] Don't forget that there are security concerns related to this.On Monday, 15 May 2017 at 22:38:15 UTC, Jonathan M Davis wrote:I suppose that we could add a tempFile that did what std.stdio.File.scratchFile did but create an empty file and return its path rather than returning a File, though that would be a bit annoying, since you'd then have to open it to operate on it instead of just writing to it. Maybe it would be worth doing though given the stupidity blocking std.stdio.File.scratchFile.
May 16 2017
On Tuesday, May 16, 2017 08:06:13 H. S. Teoh via Digitalmars-d-learn wrote:On Tue, May 16, 2017 at 06:56:57AM -0700, Jonathan M Davis viaDigitalmars-d-learn wrote:wrote:On Tuesday, May 16, 2017 11:19:14 bachmeier via Digitalmars-d-learn[...] Yes, which is why you use the system call that fails if the file already exists when you open it. std.stdio.File.scratchFile dealt with all of that (and AFAIK, did so correctly, though I could have missed something). And we'd have it in Phobos still if it weren't for the complaints about hello world's excecutable size. But all of the subtleties around that mess is why we don't have a std.file.tempFile which simply returns a suggested file name. You'd _think_ that it would be a simple issue, but unfortunately, it's not. - Jonathan M Davis[...] Don't forget that there are security concerns related to this. Most modern OS APIs tend to prefer a temp file creation call that atomically (1) generates a unique filename and (2) creates a file with said filename with permissions set such that it can only be exclusively used by the calling process. The reason for this is that there is a race condition between the generation of the filename and the creation of the file.On Monday, 15 May 2017 at 22:38:15 UTC, Jonathan M Davis wrote:I suppose that we could add a tempFile that did what std.stdio.File.scratchFile did but create an empty file and return its path rather than returning a File, though that would be a bit annoying, since you'd then have to open it to operate on it instead of just writing to it. Maybe it would be worth doing though given the stupidity blocking std.stdio.File.scratchFile.
May 16 2017