After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 657085 - GFile mkstemp wrapper
GFile mkstemp wrapper
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: gio
unspecified
Other Linux
: Normal enhancement
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2011-08-22 15:50 UTC by Jasper St. Pierre (not reading bugmail)
Modified: 2011-12-09 14:01 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Add g_file_new_for_temp (3.09 KB, patch)
2011-11-29 01:42 UTC, Thomas Andersen
rejected Details | Review
(rejected) Updated patch used in tests (5.06 KB, patch)
2011-11-30 00:31 UTC, Thomas Andersen
rejected Details | Review
Add g_file_new_temp (5.67 KB, patch)
2011-12-05 00:47 UTC, Thomas Andersen
needs-work Details | Review
Add g_file_new_for_temp (6.02 KB, patch)
2011-12-08 22:33 UTC, Thomas Andersen
committed Details | Review

Description Jasper St. Pierre (not reading bugmail) 2011-08-22 15:50:38 UTC
A simple wrapper like:

  Gio.file_new_for_temp("thing.XXXXXX");

would be a nice thing to have for bindings, returning a GFile*
Comment 1 Thomas Andersen 2011-11-29 01:42:00 UTC
Created attachment 202339 [details] [review]
Add g_file_new_for_temp

I tried to create the function g_file_new_for_temp. I simply use g_file_open_tmp to create a file, close it, and then create GFile from its path. I guess it is not very safe but I don't see a way to make it so.

(documentation is heavily inspired from g_file_open_tmp and g_file_new_for_* functions)
Comment 2 Thomas Andersen 2011-11-29 11:01:59 UTC
Comment on attachment 202339 [details] [review]
Add g_file_new_for_temp

I just noticed a typo in the patch (g_unlink should take the path, not the fd)

I will create a new patch soon.
Comment 3 Dan Winship 2011-11-29 15:12:22 UTC
Comment on attachment 202339 [details] [review]
Add g_file_new_for_temp

Creating a file and then opening it is a wrapper for mktemp(), not mkstemp(), and creates security holes. g_file_make_temp() needs to actually create a GFile directly from the fd.
Comment 4 Thomas Andersen 2011-11-30 00:31:00 UTC
Created attachment 202413 [details] [review]
(rejected) Updated patch used in tests

Hi Dan, thanks for the review.

I understand that the approach was naive. I was simply writing it as a wrapper for a common way of accomplishing it that I see spread across a lot of gnome modules. Before I read your comment I had already updated the patch and altered gio/tests/file.c to use it. It replaces code that does pretty much the same thing there too. I'll attach the patch (and reject it as well) in case you want to have a look.

Do you have any hints how I might do this the right way? Should I create a GFileIOStream for the file and return that also? Like
GFile * g_file_new_for_temp (const gchar *, GFileIOStream **) ?

I am probably in above my head here though.
Comment 5 Jasper St. Pierre (not reading bugmail) 2011-11-30 00:46:12 UTC
(In reply to comment #3)
> (From update of attachment 202339 [details] [review])
> Creating a file and then opening it is a wrapper for mktemp(), not mkstemp(),
> and creates security holes. g_file_make_temp() needs to actually create a GFile
> directly from the fd.

I thought a GFile was basically a convenient wrapper around a path. How do you create a GFile for an fd?
Comment 6 Dan Winship 2011-11-30 09:12:28 UTC
(In reply to comment #5)
> I thought a GFile was basically a convenient wrapper around a path. How do you
> create a GFile for an fd?

er, yeah, right. I guess what I meant was that g_file_new_temp() would create a GFile such that the first time you called a G*Stream-returning method on it, it would return a stream that wrapped the mkstemp fd, but after that it would behave just like a regular GLocalFile.

But maybe it would be simpler/better to just do:

  GFile *g_file_new_temp (const char  *template,
                          GIOStream  **iostream);

where iostream is an out parameter that returns a GLocalFileIOStream as though you had called g_file_create_readwrite() (with G_FILE_CREATE_PRIVATE) on the GFile, except that it is created directly from the fd returned by mkstemp.

I feel like it should be "g_file_new_temp", not "g_file_new_for_temp", because the "new_for" methods all mean "create a GFile representing (ie, 'for') some specific argument", which this new method does not.
Comment 7 Thomas Andersen 2011-12-01 12:03:14 UTC
Would this be total crack?

Get an fd with g_get_tmp_name (to allow setting mode 0666)

Create a GFile from name_used that is also returned from g_get_tmp_name

Use the fd in a function like:
GLocalFileIOStream  *
_g_local_file_io_stream_for_fd (int fd)    
  GLocalFileInputStream *input_stream;
  GLocalFileOutputStream *output_stream;
  GLocalFileIOStream *stream;
  
  output_stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
  output_stream->priv->fd = fd;

  input_stream = g_object_new (G_TYPE_LOCAL_FILE_INPUT_STREAM, NULL);
  input_stream->priv->fd = fd;  
  
  stream = g_object_new (G_TYPE_LOCAL_FILE_IO_STREAM, NULL);
  stream->output_stream = g_object_ref (output_stream);
  stream->input_stream = g_object_ref (input_stream);
  _g_local_file_output_stream_set_do_close (output_stream, FALSE);
  _g_local_file_input_stream_set_do_close (input_stream, FALSE);

  return stream;
}

and then do that with an api like you suggested? I could have a patch ready with that later today.
Comment 8 Thomas Andersen 2011-12-01 12:24:03 UTC
wait, that is crack. We do want 0600. I misread. Disregard that comment.
Comment 9 Dan Winship 2011-12-01 12:36:01 UTC
(In reply to comment #7)
>   output_stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
>   output_stream->priv->fd = fd;

Even ignoring the style issue of modifying someone else's private data, that won't compile, because GLocalFileOutputStreamPrivate is only defined inside glocalfileoutputstream.c.

You ned to add a _g_local_file_output_stream_new() that takes an fd (just like g_local_input_stream_new()), call that to create the output stream, and then pass that to _g_local_file_io_stream_new().
Comment 10 Thomas Andersen 2011-12-05 00:47:49 UTC
Created attachment 202781 [details] [review]
Add g_file_new_temp

Thank you for the pointers Dan. Would something along this line do? I suppose I should also do something more useful with the GError I pass around.
Comment 11 Dan Winship 2011-12-06 16:02:18 UTC
Comment on attachment 202781 [details] [review]
Add g_file_new_temp

ok, getting close...

>+GFile *
>+g_file_new_temp (const char     *template,
>+                 GFileIOStream **iostream)

This will need a gtk-doc comment of course. (You should be able to crib most of the content from the related gfileutils.c and gfile.c methods.) Also, you need to add g_file_new_temp to gio/gio.symbols and docs/reference/gio/gio-sections.txt (just after the other g_file_new* methods).

>+  if (fd != -1) {

>+  }
>+  else {

code style. should be

  if (fd != -1)
    {
      ...
    }
  else
    {
      ...
    }

>+    iface = G_FILE_GET_IFACE (file);
>+    *iostream = iface->open_readwrite_for_fd (fd, &error);

we don't want a public open_readwrite_for_fd() method on the interface; it's inconsistent with the rest of the interface and fds can cause tricky portability issues with Windows anyway. Just move your code from g_local_file_open_readwrite_for_fd() into g_file_new_temp() itself.

>+    g_warning ("Could not create temporary file: %s", error->message);

Don't do that. Just have g_file_new_temp() take a GError** and return the error to the caller.
Comment 12 Thomas Andersen 2011-12-08 22:33:58 UTC
Created attachment 203122 [details] [review]
Add g_file_new_for_temp

Thanks Dan. I updated the patch with your comments. It will probably need some work on the introspection annotations.
Comment 13 Dan Winship 2011-12-09 14:01:21 UTC
committed with a few doc fixes, and I also ended up renaming the
function to g_file_new_tmp() (rather than "temp") for consistency with
g_file_open_tmp() and g_get_tmp_dir().

(though unfortunately I forgot to change the commit message. oops)

Thanks for the patch.