Commit Graph

243 Commits

Author SHA1 Message Date
Tobias Stoeckmann
3d21160b85 docs: Fix typos in comments 2025-09-03 21:33:53 +02:00
Tobias Stoeckmann
23b70b0d36 gfileutils: Fix OOB read in g_build_path(name)_va
If an array with more than INT_MAX elements is passed to functions
internally calling g_build_path_va or g_build_pathname_va, then a
signed integer overflow and eventual out of boundary read access can
occur.

Use size_t instead of gint for lengths and array sizes.
2025-07-18 22:50:27 +02:00
Michael Catanzaro
61e9632848 gfileutils: fix computation of temporary file name
We need to ensure that the value we use to index into the letters array
is always positive.

Fixes #3716
2025-07-01 11:00:44 -05:00
Philip Withnall
f9a7ac11f5 gstdio: Add support for the e flag (O_CLOEXEC) to g_fopen()
This adds cross-platform support for it: on glibc, musl and BSD’s libc,
the flag is natively supported. On Windows, convert it to the `N` flag,
which similarly indicates that an open file shouldn’t be inherited by
child processes.

This allows us to unconditionally pass `e` to `g_fopen()` so `O_CLOEXEC`
can easily be set on its FDs.

Also do the same for `g_freopen()`, since it shares the same underlying
mode handling code.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2025-05-28 14:37:02 +01:00
Wesley Hershberger
45a36e52b5 gfileutils: Preserve mode during atomic updates
If g_file_set_contents{_full,} is replacing an existing file, require
that the tmpfile have the same mode as the existing file.

This prevents the umask from taking effect for consistent writes to
existing files.

Closes GNOME/dconf#76
2025-04-23 08:54:07 -05:00
Philip Withnall
447fa26205 gfileutils: Clarify that g_mkstemp() and friends act in the current directory
Otherwise it’s easy to assume that they create a file in the system
temporary directory, if they’re only called with a filename template
(without a path).

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2025-03-21 14:02:41 +00:00
Philip Withnall
1ab1cd6ba4 gfileutils: Add an assertion to help static analysis
This assertion basically mirrors the existing `buffer_size >= 2`
assertion (one implies the other), but scan-build doesn’t seem to be
able to work that out — so give it some help.

Fixes:
```
../../../glib/gfileutils.c: In function ‘g_get_current_dir’:
../../../glib/gfileutils.c:2995:17: warning: potential null pointer dereference [-Wnull-dereference]
 2995 |       buffer[1] = 0;
      |       ~~~~~~~~~~^~~
../../../glib/gfileutils.c:2994:17: warning: potential null pointer dereference [-Wnull-dereference]
 2994 |       buffer[0] = G_DIR_SEPARATOR;
```

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-12-31 12:45:42 +00:00
Philip Withnall
362f92b693 glib: Fix various implicit conversions from size_t to smaller types
Basically various trivial instances of the following MSVC compiler
warning:
```
../gio/gio-tool-set.c(50): warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data
```

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-04-25 12:39:33 +01:00
Philip Withnall
704d0bb297 gfileutils: Use g_format_size() for another translatable string
As with commit a3c2691c23, another
instance of the same pattern was missed.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Fixes: #3271
2024-03-01 11:57:50 +00:00
Philip Withnall
a3c2691c23 gfileutils: Use g_format_size() for a translatable string
Partially because the use of `G_GSIZE_MODIFIER` breaks translatable
string extraction (issue #3271) and partially because `g_format_size()`
produces more human-readable results anyway.

Prior to commit cf5e371c67 the code was using `%lu`, so this is a fairly
new issue.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Fixes: #3271
2024-02-27 09:14:22 +00:00
Philip Withnall
158ec5be34 docs: Move the gfileutils SECTION
Move it to a separate page so more detail can be provided about all the
groups of API.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Helps: #3037
2023-11-28 13:52:05 +00:00
Joseph Nuzman
cf5e371c67 gfileutils: Fix g_file_get_contents() silent under-read of large files
On certain platforms where file size (off_t) can be truncated when assigning to
gsize, get_contents_regfile() may use the truncated size as the size to read. Add
an explicit check to raise an error in such cases.

G_FILE_ERROR_FAILED will be raised in this case, aligning with behavior for other
cases.

This generally affects 32-bit non-Win32 platforms.
2023-11-23 12:41:41 +00:00
Philip Withnall
3f705ffa12 gfileutils: Add a missing ftruncate() call when writing files
When calling `g_file_set_contents_full()` without
`G_FILE_SET_CONTENTS_CONSISTENT`, the file is written by opening it,
`write()`ing to it, then closing it.

This is fine as long as the file is not longer than the new content you
want to set its contents to. If it is, the last bit of the old content
remains, because `g_file_set_contents_full()` was missing an
`ftruncate()` call.

Fix that, and change the tests to catch truncation failures in future.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>

Fixes: #3144
2023-10-22 21:37:28 +01:00
Alexander Kanavin
285db475ec glib/gfileutils.c: use 64 bits for value in get_tmp_file()
On 32 bit systems 'long' value will overflow in 2038 and become negative.
As it is used to index into letters array, and % operation preserves signs,
data corruption will then occur.

Signed-off-by: Alexander Kanavin <alex@linutronix.de>
2023-08-23 14:50:41 +02:00
Philip Withnall
7a5d4c2bb7 gfileutils: Fix potential integer overflow in g_get_current_dir()
In practice, this will never happen.

If `getcwd()` returns `ERANGE` whenever the working directory is ≥
`PATH_MAX`, though, the previous implementation of the loop would run
until `max_len == G_MAXULONG`, and would then overflow when adding `1`
to it for a nul terminator in the allocation.

Avoid that problem by always keeping `buffer_len` as a power of two, and
relying on `getcwd()` to write a nul terminator within the buffer space
it’s given. It seems to do this on all platforms we care about, because
the previous version of the code never explicitly wrote a nul terminator
anywhere.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>

Fixes: #98
2023-04-14 19:23:20 +01:00
Maciej S. Szmigiero
8f8ebb1bd0 g_mkstemp: Use O_CLOEXEC for race-free setting of the close-on-exec flag
mkstemp-like family of functions also use g_open () under the hood so
they should pass the O_CLOEXEC flag there for race-free setting of the
close-on-exec flag.
2023-02-22 00:38:13 +01:00
Maciej S. Szmigiero
3f2e18b07c Use O_CLOEXEC in {g_,}open () calls for race-free setting of the close-on-exec flag
The remaining call sites are either Windows-only, between fork () and
exec () or in xdgmime copylib.

Hope I haven't missed any site.
2023-02-21 12:42:55 +00:00
Simon McVittie
f6e13753aa fileutils: Make some sample code detect symlinks as intended
The sample code here wasn't a race-free version of the race-susceptible
anti-pattern, because it would have dereferenced a symlink automatically.

Fixes: 293b4923 "Clarify g_file_test() docs about TOCTOU bugs"
Signed-off-by: Simon McVittie <smcv@collabora.com>
2023-02-10 13:06:04 +00:00
Emmanuele Bassi
280649fb82 docs: Clarify the path construction functions
Use the same wording for functions that belong in the same family, and
link to the newly introduced GPathBuf API.
2023-02-09 13:36:51 +00:00
Emmanuele Bassi
314d62f302 doc: Make file utils docblocks render nicely with gi-docgen
Do not use 4-spaces indentation for return and argument descriptions, to
avoid getting rendered as preformatted blocks.

Annotate code examples with their language, for syntax highlighting.

Isolate the first paragraph to give a short description.
2023-02-09 13:36:51 +00:00
Emmanuele Bassi
293b492334 Clarify g_file_test() docs about TOCTOU bugs
Do not show just what not to do: show what to do instead, otherwise
people won't know how to fix their code.

Make sure to link to an explanation of the TOCTOU class of bugs;
Wikipedia is as good a place as any.
2023-02-09 13:36:51 +00:00
CCode
e9e4d52de8 gfileutils: Use 'write' with 'count' <= max value of its return type
Limit `count` so that `write` can properly report the number of written bytes.

Limits:
 - POSIX: `SSIZE_MAX`
 - Windows: `INT_MAX`

Fixes: #2883
2023-01-16 13:08:42 +00:00
Marco Trevisan (Treviño)
126b822137 gfileutils: Use correct type comparison for length
length is defined as an unsigned size value, so can't compare it with a
signed one
2022-10-31 12:02:57 +01:00
Philip Withnall
5553a44b1b gfileutils: Mention possibility of relative paths in g_file_read_link()
It’s entirely possible that `g_file_read_link()` will return a relative
path. Mention that in the documentation, and include a short example of
how to make the path absolute for further computation.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
2022-10-24 12:38:15 +01:00
Philip Withnall
70ee43f1e9 glib: Add SPDX license headers automatically
Add SPDX license (but not copyright) headers to all files which follow a
certain pattern in their existing non-machine-readable header comment.

This commit was entirely generated using the command:
```
git ls-files glib/*.[ch] | xargs perl -0777 -pi -e 's/\n \*\n \* This library is free software; you can redistribute it and\/or\n \* modify it under the terms of the GNU Lesser General Public/\n \*\n \* SPDX-License-Identifier: LGPL-2.1-or-later\n \*\n \* This library is free software; you can redistribute it and\/or\n \* modify it under the terms of the GNU Lesser General Public/igs'
```

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>

Helps: #1415
2022-05-18 09:19:02 +01:00
Marc-André Lureau
56e87ae1b5 glib: fix buffer overflow in g_canonicalize_filename()
The output pointer must not go past the ending \0.

warning: HEAP[testglib.exe]:
warning: Heap block at 0000011EA35745A0 modified at 0000011EA35745BF past requested size of f

Fixes commit 9a30a495ec "gfileutils: Improve performance of g_canonicalize_filename()"

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2022-03-04 20:16:29 +00:00
Gabor Karsay
7e64004db0 docs: mark macros, flags, enums with percent sign 2022-03-04 16:21:55 +00:00
Sebastian Keller
d9e001e2cd gfileutils: Remove outdated BTRFS fsync optimization from set_contents
This code was skipping fsync on BTRFS because of an old guarantee about
the overwrite-by-rename behavior that no longer holds true. This has
been confirmed by the BTRFS developers to no longer be guaranteed since
Kernel 3.17 (August 2014), but it was guaranteed when this optimization
was first introduced in 2010.

This could result in empty files after crashes in applications using
g_file_set_contents(). Most prominently this might have been the cause
of dconf settings getting lost on BTRFS after crashes due to the
frequency with which such writes can happen in dconf.

See: https://gitlab.gnome.org/GNOME/dconf/-/issues/73
2022-01-11 19:07:01 +01:00
Phaedrus Leeds
93f5758cf4 gfileutils: Fix transfer annotation and whitespace issues 2021-12-02 12:37:26 -08:00
Philip Withnall
fc25f8d7ef gfileutils: Correctly reset start value when canonicalising paths
If a path starts with more than two slashes, the `start` value was
previously incorrect:
 1. As per the `g_path_skip_root()` call, `start` was set to point to
    after the final initial slash. For a path with three initial
    slashes, this is the character after the third slash.
 2. The canonicalisation loop to find the first dir separator sets
    `output` to point to the character after the first slash (and it
    overwrites the first slash to be `G_DIR_SEPARATOR`).
 3. At this point, with a string `///usr`, `output` points to the second
    `/`; and `start` points to the `u`. This is incorrect, as `start`
    should point to the starting character for output, as per the
    original call to `g_path_skip_root()`.
 4. For paths which subsequently include a `..`, this results in the
    `output > start` check in the `..` loop below not skipping all the
    characters of a preceding path component, which is then caught by
    the `G_IS_DIR_SEPARATOR (output[-1])` assertion.

Fix this by resetting `start` to `output` after finding the final slash
to keep in the output, but before starting the main parsing loop.

Relatedly, split `start` into two variables: `after_root` and
`output_start`, since the variable actually has two roles in the two
parts of the function.

Includes a test.

This commit is heavily based on suggestions by Sebastian Wilhemi and
Sebastian Dröge.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>

oss-fuzz#41563
2021-12-02 17:50:17 +00:00
Philip Withnall
3421a703ca gfileutils: Add a comment in g_canonicalize_filename()
Clarify the code a little. This introduces no functional changes.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
2021-12-02 11:32:25 +00:00
Sebastian Wilhelmi
9a30a495ec gfileutils: Improve performance of g_canonicalize_filename()
Improve the performance of canonicalising filenames with many `..` or
`.` components, by modifying the path inline rather than calling
`memmove()`.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>

Fixes: #2541
2021-11-26 14:07:10 +00:00
Emmanuel Fleury
78af147721 Fix signedness warning in glib/gfileutils.c
glib/gfileutils.c: In function 'g_file_test':
glib/gfileutils.c:375:18: warning: comparison of integer expressions of different signedness: 'int' and 'long unsigned int'
   if (attributes == INVALID_FILE_ATTRIBUTES)
                  ^~
glib/gfileutils.c: In function 'g_get_current_dir':
glib/gfileutils.c:2882:40: warning: comparison of integer expressions of different signedness: 'DWORD' {aka 'long unsigned int'} and 'int'
   if (GetCurrentDirectoryW (len, wdir) == len - 1)
                                        ^~
2021-10-14 18:42:07 +02:00
Emmanuele Bassi
bed2da6cc2 docs: Break gtk-doc stanzas into paragraphs
Keep the first paragraph short, to act as a summary.
2021-08-02 16:00:12 +01:00
Simon McVittie
6c5a227bcc gmain: Add g_steal_fd() to API
This is basically glnx_steal_fd() from libglnx. We already had two
private implementations of it in GLib.

Signed-off-by: Simon McVittie <smcv@collabora.com>
2021-03-22 11:48:10 +00:00
Timm Bäder
03ca87586f fileutils: Avoid calling set_file_error with NULL GError**
If no pointer to a GError* has been passed to public API, there's not
need to look at translations via gettext or format an error message that
g_set_error_literal will entirely ignore in the end.
2020-12-31 14:58:37 +01:00
Phaedrus Leeds
7ef936f4e3 gfileutils: Fix typo in docs 2020-12-10 21:06:00 -08:00
Sebastian Dröge
b7c75f78ab Merge branch '2077-pointer-arithmetic' into 'master'
gfileutils: Correct operator precedence to avoid undefined pointer maths

Closes #2077

See merge request GNOME/glib!1526
2020-09-10 11:22:44 +00:00
Sebastian Dröge
dae128e6bb Don't pass more than G_MAXSSIZE bytes at once to write() in glib/gfileutils.c
Behaviour in that case is implementation-defined and how many bytes were
actually written can't be expressed by the return value anymore.

Instead do a short write of G_MAXSSIZE bytes and let the existing loop
for handling short writes takes care of the remaining length.
2020-08-27 19:32:14 +03:00
Emmanuel Fleury
856265fe66 Fixing signedness warning in glib/gfileutils.c
glib/gfileutils.c: In function ‘write_to_file’:
glib/gfileutils.c:1176:19: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’} [-Werror=sign-compare]
 1176 |       g_assert (s <= length);
      |                   ^~
glib/gmacros.h:939:25: note: in definition of macro ‘G_LIKELY’
  939 | #define G_LIKELY(expr) (expr)
      |                         ^~~~
glib/gfileutils.c:1176:7: note: in expansion of macro ‘g_assert’
 1176 |       g_assert (s <= length);
      |       ^~~~~~~~

Related to issue #1735 (Get back to a -werror build)
2020-08-27 19:32:11 +03:00
Philip Withnall
b4aa9d7858 gfileutils: Fix O_NOFOLLOW handling on BSD systems
Various different BSD systems use a different errno from `E_LOOP` (as
defined by POSIX and used on Linux) to indicate that a file is a symlink
when you try to `open()` it with `O_NOFOLLOW`.

Fix the code which detects this. This is a follow-up to #1302.

Signed-off-by: Philip Withnall <withnall@endlessm.com>
2020-07-27 12:24:20 +01:00
Philip Withnall
84dd89242a gfileutils: Use g_fsync() for platform-independence
Signed-off-by: Philip Withnall <withnall@endlessm.com>
2020-07-26 21:38:17 +01:00
Philip Withnall
24ed91ce33 gfileutils: Add a mode argument to g_file_set_contents_full()
This is used when creating the temporary file, or new file from scratch.

I wondered about also allowing the file owner and group to be set, but
that’s not as generally applicable — if your process is operating across
multiple user IDs then it likely has some fairly OS-specific
requirements and will need tighter control of its syscalls anyway.

(Eventually, support for setting the file owner and group atomically
could be added by writing out a file using `O_TMPFILE` so it’s not
addressable, and then linking it into the file system in place of the
old file using something like `renameat2(AT_EMPTY_PATH)` or `linkat()`.
That’s currently not possible without patching the kernel with
https://marc.info/?l=linux-fsdevel&m=152472898003523&w=2, as far as I
know at the moment.)

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Fixes: #1203
2020-07-26 21:37:46 +01:00
Philip Withnall
f3cea1c464 gfileutils: Implement GFileSetContentsFlags
This moves `write_to_temp_file()` into `g_file_set_contents_full()` and
coalesces its handling of `do_fsync` with the `rename_file()` call. It
adds support for `G_FILE_SET_CONTENTS_DURABLE` and
`G_FILE_SET_CONTENTS_NONE` — previously only
`G_FILE_SET_CONTENTS_CONSISTENT | G_FILE_SET_CONTENTS_ONLY_EXISTING` was
supported.

In the case that `G_FILE_SET_CONTENTS_CONSISTENT |
G_FILE_SET_CONTENTS_DURABLE` is set, an additional `fsync()` is now done
on the directory after renaming the temporary file.

In the case that `G_FILE_SET_CONTENTS_ONLY_EXISTING` isn’t set, the
`fsync()` after writing the temporary file will always be done (unless
the file system guarantees it never needs to be done).

In the case that only `G_FILE_SET_CONTENTS_DURABLE` is set, the
destination file will be written to directly (using this mode is not
really advised).

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Fixes: #1302
2020-07-26 21:37:46 +01:00
Philip Withnall
387c159862 gfileutils: Tidy up types of length arguments in helper functions
We can guarantee that they’re non-negative.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Helps: #1302
2020-07-26 21:37:46 +01:00
Philip Withnall
e4e618c604 gfileutils: Factor out fsync calculation
This introduces no functional changes, just makes the code a bit more
modular and reusable.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Helps: #1302
2020-07-26 21:37:46 +01:00
Philip Withnall
00c17de72e gfileutils: Split out write_to_file() helper function
This introduces no functional changes.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Helps: #1302
2020-07-26 21:37:46 +01:00
Philip Withnall
554107c23c gfileutils: Add g_file_set_contents_full() and GFileSetContentsFlags
This is a new version of the g_file_set_contents() API which will allow
its safety to be controlled by some flags, allowing the user to choose
their preferred tradeoff between safety (`fsync()` calls) and speed.

Currently, the flags do nothing and the new API behaves like the old
API. This will change in the following commits.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Helps: #1302
2020-07-26 21:37:46 +01:00
Philip Withnall
e86dd77655 gfileutils: Correct operator precedence to avoid undefined pointer maths
`base` can be `-1` in some situations, which would lead to pointing
outside an allocation area if the sums were evaluated as `(file_name +
base) + 1` rather than `file_name + (base + 1)`.

I don’t see how this can practically cause an issue, as the arithmetic
is all finished before anything’s dereferenced, but let’s keep to the
letter of the C standard to avoid this coming up in code audits in
future.

Fix suggested by fablhx.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Closes: #2077
2020-06-10 13:26:14 +01:00
Carlos Garnacho
3a4a665083 gfileutils: Fix error propagation for other than ENOENT
Commit 6f55306e04 unintendedly broke error handling for other
error conditions than ENOENT along the path, like EPERM. It wanted
to ignore ENOENT on all elements except the last in the path, but
in doing that it ignored any other error that might happen on the
last element.

https://gitlab.gnome.org/GNOME/glib/issues/1852
2019-08-08 02:32:46 +02:00