X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgfileutils.c;h=0db07c541e973d470c9ef03f9c1771fe5b2e6aca;hb=0a4ee12c7a9dfc82443133dfb2b18fb411d79f48;hp=83105312d521290b11675f3a02dcd44b8e4051d6;hpb=749fa587bc081e0f5b9c4af1ed8bdf90bd0856d2;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gfileutils.c b/glib/gfileutils.c index 8310531..0db07c5 100644 --- a/glib/gfileutils.c +++ b/glib/gfileutils.c @@ -14,17 +14,13 @@ * * You should have received a copy of the GNU Lesser General Public * License along with GLib; see the file COPYING.LIB. If not, - * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * see . */ #include "config.h" #include "glibconfig.h" #include -#ifdef HAVE_UNISTD_H -#include -#endif #include #include #include @@ -35,6 +31,9 @@ #include #include +#ifdef G_OS_UNIX +#include +#endif #ifdef G_OS_WIN32 #include #include @@ -58,6 +57,141 @@ #include #endif + +/** + * SECTION:fileutils + * @title: File Utilities + * @short_description: various file-related functions + * + * There is a group of functions which wrap the common POSIX functions + * dealing with filenames (g_open(), g_rename(), g_mkdir(), g_stat(), + * g_unlink(), g_remove(), g_fopen(), g_freopen()). The point of these + * wrappers is to make it possible to handle file names with any Unicode + * characters in them on Windows without having to use ifdefs and the + * wide character API in the application code. + * + * The pathname argument should be in the GLib file name encoding. + * On POSIX this is the actual on-disk encoding which might correspond + * to the locale settings of the process (or the `G_FILENAME_ENCODING` + * environment variable), or not. + * + * On Windows the GLib file name encoding is UTF-8. Note that the + * Microsoft C library does not use UTF-8, but has separate APIs for + * current system code page and wide characters (UTF-16). The GLib + * wrappers call the wide character API if present (on modern Windows + * systems), otherwise convert to/from the system code page. + * + * Another group of functions allows to open and read directories + * in the GLib file name encoding. These are g_dir_open(), + * g_dir_read_name(), g_dir_rewind(), g_dir_close(). + */ + +/** + * GFileError: + * @G_FILE_ERROR_EXIST: Operation not permitted; only the owner of + * the file (or other resource) or processes with special privileges + * can perform the operation. + * @G_FILE_ERROR_ISDIR: File is a directory; you cannot open a directory + * for writing, or create or remove hard links to it. + * @G_FILE_ERROR_ACCES: Permission denied; the file permissions do not + * allow the attempted operation. + * @G_FILE_ERROR_NAMETOOLONG: Filename too long. + * @G_FILE_ERROR_NOENT: No such file or directory. This is a "file + * doesn't exist" error for ordinary files that are referenced in + * contexts where they are expected to already exist. + * @G_FILE_ERROR_NOTDIR: A file that isn't a directory was specified when + * a directory is required. + * @G_FILE_ERROR_NXIO: No such device or address. The system tried to + * use the device represented by a file you specified, and it + * couldn't find the device. This can mean that the device file was + * installed incorrectly, or that the physical device is missing or + * not correctly attached to the computer. + * @G_FILE_ERROR_NODEV: The underlying file system of the specified file + * does not support memory mapping. + * @G_FILE_ERROR_ROFS: The directory containing the new link can't be + * modified because it's on a read-only file system. + * @G_FILE_ERROR_TXTBSY: Text file busy. + * @G_FILE_ERROR_FAULT: You passed in a pointer to bad memory. + * (GLib won't reliably return this, don't pass in pointers to bad + * memory.) + * @G_FILE_ERROR_LOOP: Too many levels of symbolic links were encountered + * in looking up a file name. This often indicates a cycle of symbolic + * links. + * @G_FILE_ERROR_NOSPC: No space left on device; write operation on a + * file failed because the disk is full. + * @G_FILE_ERROR_NOMEM: No memory available. The system cannot allocate + * more virtual memory because its capacity is full. + * @G_FILE_ERROR_MFILE: The current process has too many files open and + * can't open any more. Duplicate descriptors do count toward this + * limit. + * @G_FILE_ERROR_NFILE: There are too many distinct file openings in the + * entire system. + * @G_FILE_ERROR_BADF: Bad file descriptor; for example, I/O on a + * descriptor that has been closed or reading from a descriptor open + * only for writing (or vice versa). + * @G_FILE_ERROR_INVAL: Invalid argument. This is used to indicate + * various kinds of problems with passing the wrong argument to a + * library function. + * @G_FILE_ERROR_PIPE: Broken pipe; there is no process reading from the + * other end of a pipe. Every library function that returns this + * error code also generates a 'SIGPIPE' signal; this signal + * terminates the program if not handled or blocked. Thus, your + * program will never actually see this code unless it has handled + * or blocked 'SIGPIPE'. + * @G_FILE_ERROR_AGAIN: Resource temporarily unavailable; the call might + * work if you try again later. + * @G_FILE_ERROR_INTR: Interrupted function call; an asynchronous signal + * occurred and prevented completion of the call. When this + * happens, you should try the call again. + * @G_FILE_ERROR_IO: Input/output error; usually used for physical read + * or write errors. i.e. the disk or other physical device hardware + * is returning errors. + * @G_FILE_ERROR_PERM: Operation not permitted; only the owner of the + * file (or other resource) or processes with special privileges can + * perform the operation. + * @G_FILE_ERROR_NOSYS: Function not implemented; this indicates that + * the system is missing some functionality. + * @G_FILE_ERROR_FAILED: Does not correspond to a UNIX error code; this + * is the standard "failed for unspecified reason" error code present + * in all #GError error code enumerations. Returned if no specific + * code applies. + * + * Values corresponding to @errno codes returned from file operations + * on UNIX. Unlike @errno codes, GFileError values are available on + * all systems, even Windows. The exact meaning of each code depends + * on what sort of file operation you were performing; the UNIX + * documentation gives more details. The following error code descriptions + * come from the GNU C Library manual, and are under the copyright + * of that manual. + * + * It's not very portable to make detailed assumptions about exactly + * which errors will be returned from a given operation. Some errors + * don't occur on some systems, etc., sometimes there are subtle + * differences in when a system will report a given error, etc. + */ + +/** + * G_FILE_ERROR: + * + * Error domain for file operations. Errors in this domain will + * be from the #GFileError enumeration. See #GError for information + * on error domains. + */ + +/** + * GFileTest: + * @G_FILE_TEST_IS_REGULAR: %TRUE if the file is a regular file + * (not a directory). Note that this test will also return %TRUE + * if the tested file is a symlink to a regular file. + * @G_FILE_TEST_IS_SYMLINK: %TRUE if the file is a symlink. + * @G_FILE_TEST_IS_DIR: %TRUE if the file is a directory. + * @G_FILE_TEST_IS_EXECUTABLE: %TRUE if the file is executable. + * @G_FILE_TEST_EXISTS: %TRUE if the file exists. It may or may not + * be a regular file. + * + * A test to perform on a file using g_file_test(). + */ + /** * g_mkdir_with_parents: * @pathname: a pathname in the GLib file name encoding @@ -136,11 +270,11 @@ g_mkdir_with_parents (const gchar *pathname, * @test: bitfield of #GFileTest flags * * Returns %TRUE if any of the tests in the bitfield @test are - * %TRUE. For example, (G_FILE_TEST_EXISTS | - * G_FILE_TEST_IS_DIR) will return %TRUE if the file exists; - * the check whether it's a directory doesn't matter since the existence - * test is %TRUE. With the current set of available tests, there's no point - * passing in more than one test at a time. + * %TRUE. For example, `(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)` + * will return %TRUE if the file exists; the check whether it's a + * directory doesn't matter since the existence test is %TRUE. With + * the current set of available tests, there's no point passing in + * more than one test at a time. * * Apart from %G_FILE_TEST_IS_SYMLINK all tests follow symbolic links, * so for a symbolic link to a regular file g_file_test() will return @@ -155,12 +289,12 @@ g_mkdir_with_parents (const gchar *pathname, * For example, you might think you could use %G_FILE_TEST_IS_SYMLINK * to know whether it is safe to write to a file without being * tricked into writing into a different location. It doesn't work! - * |[ - * /* DON'T DO THIS */ + * |[ + * // DON'T DO THIS * if (!g_file_test (filename, G_FILE_TEST_IS_SYMLINK)) * { * fd = g_open (filename, O_WRONLY); - * /* write to fd */ + * // write to fd * } * ]| * @@ -175,9 +309,9 @@ g_mkdir_with_parents (const gchar *pathname, * %G_FILE_TEST_IS_SYMLINK will always return %FALSE. Testing for * %G_FILE_TEST_IS_EXECUTABLE will just check that the file exists and * its name indicates that it is executable, checking for well-known - * extensions and those listed in the %PATHEXT environment variable. + * extensions and those listed in the `PATHEXT` environment variable. * - * Return value: whether a test was %TRUE + * Returns: whether a test was %TRUE **/ gboolean g_file_test (const gchar *filename, @@ -324,26 +458,22 @@ g_file_test (const gchar *filename, #endif } -GQuark -g_file_error_quark (void) -{ - return g_quark_from_static_string ("g-file-error-quark"); -} +G_DEFINE_QUARK (g-file-error-quark, g_file_error) /** * g_file_error_from_errno: * @err_no: an "errno" value * - * Gets a #GFileError constant based on the passed-in @errno. - * For example, if you pass in %EEXIST this function returns - * #G_FILE_ERROR_EXIST. Unlike @errno values, you can portably + * Gets a #GFileError constant based on the passed-in @err_no. + * For example, if you pass in `EEXIST` this function returns + * #G_FILE_ERROR_EXIST. Unlike `errno` values, you can portably * assume that all #GFileError values will exist. * * Normally a #GFileError value goes into a #GError returned * from a function that manipulates files. So you would use * g_file_error_from_errno() when constructing a #GError. * - * Return value: #GFileError corresponding to the given @errno + * Returns: #GFileError corresponding to the given @errno **/ GFileError g_file_error_from_errno (gint err_no) @@ -353,166 +483,185 @@ g_file_error_from_errno (gint err_no) #ifdef EEXIST case EEXIST: return G_FILE_ERROR_EXIST; - break; #endif #ifdef EISDIR case EISDIR: return G_FILE_ERROR_ISDIR; - break; #endif #ifdef EACCES case EACCES: return G_FILE_ERROR_ACCES; - break; #endif #ifdef ENAMETOOLONG case ENAMETOOLONG: return G_FILE_ERROR_NAMETOOLONG; - break; #endif #ifdef ENOENT case ENOENT: return G_FILE_ERROR_NOENT; - break; #endif #ifdef ENOTDIR case ENOTDIR: return G_FILE_ERROR_NOTDIR; - break; #endif #ifdef ENXIO case ENXIO: return G_FILE_ERROR_NXIO; - break; #endif #ifdef ENODEV case ENODEV: return G_FILE_ERROR_NODEV; - break; #endif #ifdef EROFS case EROFS: return G_FILE_ERROR_ROFS; - break; #endif #ifdef ETXTBSY case ETXTBSY: return G_FILE_ERROR_TXTBSY; - break; #endif #ifdef EFAULT case EFAULT: return G_FILE_ERROR_FAULT; - break; #endif #ifdef ELOOP case ELOOP: return G_FILE_ERROR_LOOP; - break; #endif #ifdef ENOSPC case ENOSPC: return G_FILE_ERROR_NOSPC; - break; #endif #ifdef ENOMEM case ENOMEM: return G_FILE_ERROR_NOMEM; - break; #endif #ifdef EMFILE case EMFILE: return G_FILE_ERROR_MFILE; - break; #endif #ifdef ENFILE case ENFILE: return G_FILE_ERROR_NFILE; - break; #endif #ifdef EBADF case EBADF: return G_FILE_ERROR_BADF; - break; #endif #ifdef EINVAL case EINVAL: return G_FILE_ERROR_INVAL; - break; #endif #ifdef EPIPE case EPIPE: return G_FILE_ERROR_PIPE; - break; #endif #ifdef EAGAIN case EAGAIN: return G_FILE_ERROR_AGAIN; - break; #endif #ifdef EINTR case EINTR: return G_FILE_ERROR_INTR; - break; #endif #ifdef EIO case EIO: return G_FILE_ERROR_IO; - break; #endif #ifdef EPERM case EPERM: return G_FILE_ERROR_PERM; - break; #endif #ifdef ENOSYS case ENOSYS: return G_FILE_ERROR_NOSYS; - break; #endif default: return G_FILE_ERROR_FAILED; - break; } } +static char * +format_error_message (const gchar *filename, + const gchar *format_string, + int saved_errno) G_GNUC_FORMAT(2); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +static char * +format_error_message (const gchar *filename, + const gchar *format_string, + int saved_errno) +{ + gchar *display_name; + gchar *msg; + + display_name = g_filename_display_name (filename); + msg = g_strdup_printf (format_string, display_name, g_strerror (saved_errno)); + g_free (display_name); + + return msg; +} + +#pragma GCC diagnostic pop + +/* format string must have two '%s': + * + * - the place for the filename + * - the place for the strerror + */ +static void +set_file_error (GError **error, + const gchar *filename, + const gchar *format_string, + int saved_errno) +{ + char *msg = format_error_message (filename, format_string, saved_errno); + + g_set_error_literal (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno), + msg); + g_free (msg); +} + static gboolean -get_contents_stdio (const gchar *display_filename, +get_contents_stdio (const gchar *filename, FILE *f, gchar **contents, gsize *length, GError **error) { gchar buf[4096]; - gsize bytes; + gsize bytes; /* always <= sizeof(buf) */ gchar *str = NULL; gsize total_bytes = 0; gsize total_allocated = 0; gchar *tmp; + gchar *display_filename; g_assert (f != NULL); @@ -523,23 +672,35 @@ get_contents_stdio (const gchar *display_filename, bytes = fread (buf, 1, sizeof (buf), f); save_errno = errno; - while ((total_bytes + bytes + 1) > total_allocated) + if (total_bytes > G_MAXSIZE - bytes) + goto file_too_large; + + /* Possibility of overflow eliminated above. */ + while (total_bytes + bytes >= total_allocated) { if (str) - total_allocated *= 2; + { + if (total_allocated > G_MAXSIZE / 2) + goto file_too_large; + total_allocated *= 2; + } else - total_allocated = MIN (bytes + 1, sizeof (buf)); + { + total_allocated = MIN (bytes + 1, sizeof (buf)); + } tmp = g_try_realloc (str, total_allocated); if (tmp == NULL) { + display_filename = g_filename_display_name (filename); g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOMEM, - _("Could not allocate %lu bytes to read file \"%s\""), + g_dngettext (GETTEXT_PACKAGE, "Could not allocate %lu byte to read file \"%s\"", "Could not allocate %lu bytes to read file \"%s\"", (gulong)total_allocated), (gulong) total_allocated, display_filename); + g_free (display_filename); goto error; } @@ -549,29 +710,21 @@ get_contents_stdio (const gchar *display_filename, if (ferror (f)) { + display_filename = g_filename_display_name (filename); g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (save_errno), _("Error reading file '%s': %s"), display_filename, g_strerror (save_errno)); + g_free (display_filename); goto error; } + g_assert (str != NULL); memcpy (str + total_bytes, buf, bytes); - if (total_bytes + bytes < total_bytes) - { - g_set_error (error, - G_FILE_ERROR, - G_FILE_ERROR_FAILED, - _("File \"%s\" is too large"), - display_filename); - - goto error; - } - total_bytes += bytes; } @@ -592,6 +745,15 @@ get_contents_stdio (const gchar *display_filename, return TRUE; + file_too_large: + display_filename = g_filename_display_name (filename); + g_set_error (error, + G_FILE_ERROR, + G_FILE_ERROR_FAILED, + _("File \"%s\" is too large"), + display_filename); + g_free (display_filename); + error: g_free (str); @@ -603,7 +765,7 @@ get_contents_stdio (const gchar *display_filename, #ifndef G_OS_WIN32 static gboolean -get_contents_regfile (const gchar *display_filename, +get_contents_regfile (const gchar *filename, struct stat *stat_buf, gint fd, gchar **contents, @@ -614,6 +776,7 @@ get_contents_regfile (const gchar *display_filename, gsize bytes_read; gsize size; gsize alloc_size; + gchar *display_filename; size = stat_buf->st_size; @@ -622,13 +785,14 @@ get_contents_regfile (const gchar *display_filename, if (buf == NULL) { + display_filename = g_filename_display_name (filename); g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOMEM, - _("Could not allocate %lu bytes to read file \"%s\""), + g_dngettext (GETTEXT_PACKAGE, "Could not allocate %lu byte to read file \"%s\"", "Could not allocate %lu bytes to read file \"%s\"", (gulong)alloc_size), (gulong) alloc_size, display_filename); - + g_free (display_filename); goto error; } @@ -646,13 +810,14 @@ get_contents_regfile (const gchar *display_filename, int save_errno = errno; g_free (buf); + display_filename = g_filename_display_name (filename); g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (save_errno), _("Failed to read from file '%s': %s"), display_filename, g_strerror (save_errno)); - + g_free (display_filename); goto error; } } @@ -688,22 +853,17 @@ get_contents_posix (const gchar *filename, { struct stat stat_buf; gint fd; - gchar *display_filename = g_filename_display_name (filename); /* O_BINARY useful on Cygwin */ fd = open (filename, O_RDONLY|O_BINARY); if (fd < 0) { - int save_errno = errno; - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to open file '%s': %s"), - display_filename, - g_strerror (save_errno)); - g_free (display_filename); + int saved_errno = errno; + set_file_error (error, + filename, + _("Failed to open file '%s': %s"), + saved_errno); return FALSE; } @@ -711,29 +871,24 @@ get_contents_posix (const gchar *filename, /* I don't think this will ever fail, aside from ENOMEM, but. */ if (fstat (fd, &stat_buf) < 0) { - int save_errno = errno; - + int saved_errno = errno; + set_file_error (error, + filename, + _("Failed to get attributes of file '%s': fstat() failed: %s"), + saved_errno); close (fd); - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to get attributes of file '%s': fstat() failed: %s"), - display_filename, - g_strerror (save_errno)); - g_free (display_filename); return FALSE; } if (stat_buf.st_size > 0 && S_ISREG (stat_buf.st_mode)) { - gboolean retval = get_contents_regfile (display_filename, + gboolean retval = get_contents_regfile (filename, &stat_buf, fd, contents, length, error); - g_free (display_filename); return retval; } @@ -746,21 +901,16 @@ get_contents_posix (const gchar *filename, if (f == NULL) { - int save_errno = errno; - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to open file '%s': fdopen() failed: %s"), - display_filename, - g_strerror (save_errno)); - g_free (display_filename); + int saved_errno = errno; + set_file_error (error, + filename, + _("Failed to open file '%s': fdopen() failed: %s"), + saved_errno); return FALSE; } - retval = get_contents_stdio (display_filename, f, contents, length, error); - g_free (display_filename); + retval = get_contents_stdio (filename, f, contents, length, error); return retval; } @@ -776,27 +926,21 @@ get_contents_win32 (const gchar *filename, { FILE *f; gboolean retval; - gchar *display_filename = g_filename_display_name (filename); - int save_errno; f = g_fopen (filename, "rb"); - save_errno = errno; if (f == NULL) { - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to open file '%s': %s"), - display_filename, - g_strerror (save_errno)); - g_free (display_filename); + int saved_errno = errno; + set_file_error (error, + filename, + _("Failed to open file '%s': %s"), + saved_errno); return FALSE; } - retval = get_contents_stdio (display_filename, f, contents, length, error); - g_free (display_filename); + retval = get_contents_stdio (filename, f, contents, length, error); return retval; } @@ -822,7 +966,7 @@ get_contents_win32 (const gchar *filename, * codes are those in the #GFileError enumeration. In the error case, * @contents is set to %NULL and @length is set to zero. * - * Return value: %TRUE on success, %FALSE if an error occurred + * Returns: %TRUE on success, %FALSE if an error occurred **/ gboolean g_file_get_contents (const gchar *filename, @@ -880,93 +1024,59 @@ write_to_temp_file (const gchar *contents, GError **err) { gchar *tmp_name; - gchar *display_name; gchar *retval; - FILE *file; gint fd; - int save_errno; retval = NULL; - + tmp_name = g_strdup_printf ("%s.XXXXXX", dest_file); errno = 0; fd = g_mkstemp_full (tmp_name, O_RDWR | O_BINARY, 0666); - save_errno = errno; - display_name = g_filename_display_name (tmp_name); - if (fd == -1) { - g_set_error (err, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to create file '%s': %s"), - display_name, g_strerror (save_errno)); - + int saved_errno = errno; + set_file_error (err, + tmp_name, _("Failed to create file '%s': %s"), + saved_errno); goto out; } - errno = 0; - file = fdopen (fd, "wb"); - if (!file) +#ifdef HAVE_FALLOCATE + if (length > 0) { - save_errno = errno; - g_set_error (err, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to open file '%s' for writing: fdopen() failed: %s"), - display_name, - g_strerror (save_errno)); - - close (fd); - g_unlink (tmp_name); - - goto out; + /* We do this on a 'best effort' basis... It may not be supported + * on the underlying filesystem. + */ + (void) fallocate (fd, 0, 0, length); } - - if (length > 0) +#endif + while (length > 0) { - gsize n_written; - - errno = 0; + gssize s; - n_written = fwrite (contents, 1, length, file); + s = write (fd, contents, length); - if (n_written < length) - { - save_errno = errno; - - g_set_error (err, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to write file '%s': fwrite() failed: %s"), - display_name, - g_strerror (save_errno)); + if (s < 0) + { + int saved_errno = errno; + if (saved_errno == EINTR) + continue; - fclose (file); - g_unlink (tmp_name); - - goto out; - } - } + set_file_error (err, + tmp_name, _("Failed to write file '%s': write() failed: %s"), + saved_errno); + close (fd); + g_unlink (tmp_name); - errno = 0; - if (fflush (file) != 0) - { - save_errno = errno; - - g_set_error (err, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to write file '%s': fflush() failed: %s"), - display_name, - g_strerror (save_errno)); + goto out; + } - fclose (file); - g_unlink (tmp_name); - - goto out; + g_assert (s <= length); + + contents += s; + length -= s; } #ifdef BTRFS_SUPER_MAGIC @@ -982,7 +1092,7 @@ write_to_temp_file (const gchar *contents, goto no_fsync; } #endif - + #ifdef HAVE_FSYNC { struct stat statbuf; @@ -994,23 +1104,16 @@ write_to_temp_file (const gchar *contents, * the new and the old file on some filesystems. (I.E. those that don't * guarantee the data is written to the disk before the metadata.) */ - if (g_lstat (dest_file, &statbuf) == 0 && - statbuf.st_size > 0 && - fsync (fileno (file)) != 0) + if (g_lstat (dest_file, &statbuf) == 0 && statbuf.st_size > 0 && fsync (fd) != 0) { - save_errno = errno; - - g_set_error (err, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to write file '%s': fsync() failed: %s"), - display_name, - g_strerror (save_errno)); - - fclose (file); - g_unlink (tmp_name); - - goto out; + int saved_errno = errno; + set_file_error (err, + tmp_name, _("Failed to write file '%s': fsync() failed: %s"), + saved_errno); + close (fd); + g_unlink (tmp_name); + + goto out; } } #endif @@ -1018,31 +1121,20 @@ write_to_temp_file (const gchar *contents, #ifdef BTRFS_SUPER_MAGIC no_fsync: #endif - - errno = 0; - if (fclose (file) == EOF) - { - save_errno = errno; - - g_set_error (err, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to close file '%s': fclose() failed: %s"), - display_name, - g_strerror (save_errno)); - fclose (file); + errno = 0; + if (!g_close (fd, err)) + { g_unlink (tmp_name); - + goto out; } retval = g_strdup (tmp_name); - + out: g_free (tmp_name); - g_free (display_name); - + return retval; } @@ -1059,24 +1151,19 @@ write_to_temp_file (const gchar *contents, * * This write is atomic in the sense that it is first written to a temporary * file which is then renamed to the final name. Notes: - * - * - * On Unix, if @filename already exists hard links to @filename will break. - * Also since the file is recreated, existing permissions, access control - * lists, metadata etc. may be lost. If @filename is a symbolic link, - * the link itself will be replaced, not the linked file. - * - * - * On Windows renaming a file will not remove an existing file with the + * + * - On UNIX, if @filename already exists hard links to @filename will break. + * Also since the file is recreated, existing permissions, access control + * lists, metadata etc. may be lost. If @filename is a symbolic link, + * the link itself will be replaced, not the linked file. + * + * - On Windows renaming a file will not remove an existing file with the * new name, so on Windows there is a race condition between the existing * file being removed and the temporary file being renamed. - * - * - * On Windows there is no way to remove a file that is open to some + * + * - On Windows there is no way to remove a file that is open to some * process, or mapped into memory. Thus, this function will fail if * @filename already exists and is open. - * - * * * If the call was successful, it returns %TRUE. If the call was not successful, * it returns %FALSE and sets @error. The error domain is #G_FILE_ERROR. @@ -1085,10 +1172,10 @@ write_to_temp_file (const gchar *contents, * Note that the name for the temporary file is constructed by appending up * to 7 characters to @filename. * - * Return value: %TRUE on success, %FALSE if an error occurred + * Returns: %TRUE on success, %FALSE if an error occurred * * Since: 2.8 - **/ + */ gboolean g_file_set_contents (const gchar *filename, const gchar *contents, @@ -1142,18 +1229,11 @@ g_file_set_contents (const gchar *filename, if (g_unlink (filename) == -1) { - gchar *display_filename = g_filename_display_name (filename); - - int save_errno = errno; - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Existing file '%s' could not be removed: g_unlink() failed: %s"), - display_filename, - g_strerror (save_errno)); - - g_free (display_filename); + int saved_errno = errno; + set_file_error (error, + filename, + _("Existing file '%s' could not be removed: g_unlink() failed: %s"), + saved_errno); g_unlink (tmp_filename); retval = FALSE; goto out; @@ -1180,7 +1260,7 @@ g_file_set_contents (const gchar *filename, * get_tmp_file based on the mkstemp implementation from the GNU C library. * Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc. */ -typedef gint (*GTmpFileCallback) (gchar *, gint, gint); +typedef gint (*GTmpFileCallback) (const gchar *, gint, gint); static gint get_tmp_file (gchar *tmpl, @@ -1245,13 +1325,27 @@ get_tmp_file (gchar *tmpl, return -1; } -gint -wrap_mkdir (gchar *tmpl, - int flags G_GNUC_UNUSED, - int mode) +/* Some GTmpFileCallback implementations. + * + * Note: we cannot use open() or g_open() directly because even though + * they appear compatible, they may be vararg functions and calling + * varargs functions through a non-varargs type is undefined. + */ +static gint +wrap_g_mkdir (const gchar *filename, + int flags G_GNUC_UNUSED, + int mode) { /* tmpl is in UTF-8 on Windows, thus use g_mkdir() */ - return g_mkdir (tmpl, mode); + return g_mkdir (filename, mode); +} + +static gint +wrap_g_open (const gchar *filename, + int flags, + int mode) +{ + return g_open (filename, flags, mode); } /** @@ -1271,17 +1365,17 @@ wrap_mkdir (gchar *tmpl, * in the GLib file name encoding. Most importantly, on Windows it * should be in UTF-8. * - * Return value: A pointer to @tmpl, which has been modified + * Returns: A pointer to @tmpl, which has been modified * to hold the directory name. In case of errors, %NULL is * returned, and %errno will be set. * - * Since: 2.26 + * Since: 2.30 */ gchar * g_mkdtemp_full (gchar *tmpl, gint mode) { - if (get_tmp_file (tmpl, wrap_mkdir, 0, mode) == -1) + if (get_tmp_file (tmpl, wrap_g_mkdir, 0, mode) == -1) return NULL; else return tmpl; @@ -1303,11 +1397,11 @@ g_mkdtemp_full (gchar *tmpl, * The string should be in the GLib file name encoding. Most importantly, * on Windows it should be in UTF-8. * - * Return value: A pointer to @tmpl, which has been modified + * Returns: A pointer to @tmpl, which has been modified * to hold the directory name. In case of errors, %NULL is * returned and %errno will be set. * - * Since: 2.26 + * Since: 2.30 */ gchar * g_mkdtemp (gchar *tmpl) @@ -1334,7 +1428,7 @@ g_mkdtemp (gchar *tmpl) * The string should be in the GLib file name encoding. Most importantly, * on Windows it should be in UTF-8. * - * Return value: A file handle (as from open()) to the file + * Returns: A file handle (as from open()) to the file * opened for reading and writing. The file handle should be * closed with close(). In case of errors, -1 is returned * and %errno will be set. @@ -1347,7 +1441,7 @@ g_mkstemp_full (gchar *tmpl, gint mode) { /* tmpl is in UTF-8 on Windows, thus use g_open() */ - return get_tmp_file (tmpl, (GTmpFileCallback) g_open, + return get_tmp_file (tmpl, wrap_g_open, flags | O_CREAT | O_EXCL, mode); } @@ -1366,7 +1460,7 @@ g_mkstemp_full (gchar *tmpl, * didn't exist. The string should be in the GLib file name encoding. * Most importantly, on Windows it should be in UTF-8. * - * Return value: A file handle (as from open()) to the file + * Returns: A file handle (as from open()) to the file * opened for reading and writing. The file is opened in binary * mode on platforms where there is a difference. The file handle * should be closed with close(). In case of errors, -1 is @@ -1440,15 +1534,11 @@ g_get_tmp_name (const gchar *tmpl, retval = get_tmp_file (fulltemplate, f, flags, mode); if (retval == -1) { - int save_errno = errno; - gchar *display_fulltemplate = g_filename_display_name (fulltemplate); - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to create file '%s': %s"), - display_fulltemplate, g_strerror (save_errno)); - g_free (display_fulltemplate); + int saved_errno = errno; + set_file_error (error, + fulltemplate, + _("Failed to create file '%s': %s"), + saved_errno); g_free (fulltemplate); return -1; } @@ -1483,7 +1573,7 @@ g_get_tmp_name (const gchar *tmpl, * when not needed any longer. The returned name is in the GLib file * name encoding. * - * Return value: A file handle (as from open()) to the file opened for + * Returns: A file handle (as from open()) to the file opened for * reading and writing. The file is opened in binary mode on platforms * where there is a difference. The file handle should be closed with * close(). In case of errors, -1 is returned and @error will be set. @@ -1497,7 +1587,7 @@ g_file_open_tmp (const gchar *tmpl, gint result; result = g_get_tmp_name (tmpl, &fulltemplate, - (GTmpFileCallback) g_open, + wrap_g_open, O_CREAT | O_EXCL | O_RDWR | O_BINARY, 0600, error); @@ -1530,7 +1620,7 @@ g_file_open_tmp (const gchar *tmpl, * Note that in contrast to g_mkdtemp() (and mkdtemp()) @tmpl is not * modified, and might thus be a read-only literal string. * - * Return value: (type filename): The actual name used. This string + * Returns: (type filename): The actual name used. This string * should be freed with g_free() when not needed any longer and is * is in the GLib file name encoding. In case of errors, %NULL is * returned and @error will be set. @@ -1543,7 +1633,7 @@ g_dir_make_tmp (const gchar *tmpl, { gchar *fulltemplate; - if (g_get_tmp_name (tmpl, &fulltemplate, wrap_mkdir, 0, 0700, error) == -1) + if (g_get_tmp_name (tmpl, &fulltemplate, wrap_g_mkdir, 0, 0700, error) == -1) return NULL; else return fulltemplate; @@ -1661,7 +1751,7 @@ g_build_path_va (const gchar *separator, * as a string array, instead of varargs. This function is mainly * meant for language bindings. * - * Return value: a newly-allocated string that must be freed with g_free(). + * Returns: a newly-allocated string that must be freed with g_free(). * * Since: 2.8 */ @@ -1698,8 +1788,7 @@ g_build_pathv (const gchar *separator, * the same as the number of trailing copies of the separator on * the last non-empty element. (Determination of the number of * trailing copies is done without stripping leading copies, so - * if the separator is ABA, ABABA - * has 1 trailing copy.) + * if the separator is `ABA`, then `ABABA` has 1 trailing copy.) * * However, if there is only a single non-empty element, and there * are no characters in that element not part of the leading or @@ -1710,7 +1799,7 @@ g_build_pathv (const gchar *separator, * copies of the separator, elements consisting only of copies * of the separator are ignored. * - * Return value: a newly-allocated string that must be freed with g_free(). + * Returns: a newly-allocated string that must be freed with g_free(). **/ gchar * g_build_path (const gchar *separator, @@ -1853,7 +1942,7 @@ g_build_pathname_va (const gchar *first_element, * as a string array, instead of varargs. This function is mainly * meant for language bindings. * - * Return value: a newly-allocated string that must be freed with g_free(). + * Returns: a newly-allocated string that must be freed with g_free(). * * Since: 2.8 */ @@ -1879,21 +1968,20 @@ g_build_filenamev (gchar **args) * Creates a filename from a series of elements using the correct * separator for filenames. * - * On Unix, this function behaves identically to g_build_path - * (G_DIR_SEPARATOR_S, first_element, ....). + * On Unix, this function behaves identically to `g_build_path + * (G_DIR_SEPARATOR_S, first_element, ....)`. * * On Windows, it takes into account that either the backslash - * (\ or slash (/) can be used - * as separator in filenames, but otherwise behaves as on Unix. When - * file pathname separators need to be inserted, the one that last - * previously occurred in the parameters (reading from left to right) - * is used. + * (`\` or slash (`/`) can be used as separator in filenames, but + * otherwise behaves as on UNIX. When file pathname separators need + * to be inserted, the one that last previously occurred in the + * parameters (reading from left to right) is used. * * No attempt is made to force the resulting filename to be an absolute * path. If the first element is a relative path, the result will * be a relative path. * - * Return value: a newly-allocated string that must be freed with g_free(). + * Returns: a newly-allocated string that must be freed with g_free(). **/ gchar * g_build_filename (const gchar *first_element, @@ -1913,328 +2001,507 @@ g_build_filename (const gchar *first_element, return str; } -#define KILOBYTE_FACTOR (G_GOFFSET_CONSTANT (1000)) -#define MEGABYTE_FACTOR (KILOBYTE_FACTOR * KILOBYTE_FACTOR) -#define GIGABYTE_FACTOR (MEGABYTE_FACTOR * KILOBYTE_FACTOR) -#define TERABYTE_FACTOR (GIGABYTE_FACTOR * KILOBYTE_FACTOR) -#define PETABYTE_FACTOR (TERABYTE_FACTOR * KILOBYTE_FACTOR) -#define EXABYTE_FACTOR (PETABYTE_FACTOR * KILOBYTE_FACTOR) - -#define KIBIBYTE_FACTOR (G_GOFFSET_CONSTANT (1024)) -#define MEBIBYTE_FACTOR (KIBIBYTE_FACTOR * KIBIBYTE_FACTOR) -#define GIBIBYTE_FACTOR (MEBIBYTE_FACTOR * KIBIBYTE_FACTOR) -#define TEBIBYTE_FACTOR (GIBIBYTE_FACTOR * KIBIBYTE_FACTOR) -#define PEBIBYTE_FACTOR (TEBIBYTE_FACTOR * KIBIBYTE_FACTOR) -#define EXBIBYTE_FACTOR (PEBIBYTE_FACTOR * KIBIBYTE_FACTOR) - /** - * g_format_size: - * @size: a size in bytes - * - * Formats a size (for example the size of a file) into a human readable - * string. Sizes are rounded to the nearest size prefix (kB, MB, GB) - * and are displayed rounded to the nearest tenth. E.g. the file size - * 3292528 bytes will be converted into the string "3.2 MB". - * - * The prefix units base is 1000 (i.e. 1 kB is 1000 bytes). - * - * This string should be freed with g_free() when not needed any longer. + * g_file_read_link: + * @filename: the symbolic link + * @error: return location for a #GError * - * See g_format_size_full() for more options about how the size might be - * formatted. + * Reads the contents of the symbolic link @filename like the POSIX + * readlink() function. The returned string is in the encoding used + * for filenames. Use g_filename_to_utf8() to convert it to UTF-8. * - * Returns: a newly-allocated formatted string containing a human readable - * file size. + * Returns: A newly-allocated string with the contents of the symbolic link, + * or %NULL if an error occurred. * - * Since: 2.30 - **/ + * Since: 2.4 + */ gchar * -g_format_size (guint64 size) +g_file_read_link (const gchar *filename, + GError **error) +{ +#ifdef HAVE_READLINK + gchar *buffer; + guint size; + gint read_size; + + size = 256; + buffer = g_malloc (size); + + while (TRUE) + { + read_size = readlink (filename, buffer, size); + if (read_size < 0) + { + int saved_errno = errno; + set_file_error (error, + filename, + _("Failed to read the symbolic link '%s': %s"), + saved_errno); + g_free (buffer); + return NULL; + } + + if (read_size < size) + { + buffer[read_size] = 0; + return buffer; + } + + size *= 2; + buffer = g_realloc (buffer, size); + } +#else + g_set_error_literal (error, + G_FILE_ERROR, + G_FILE_ERROR_INVAL, + _("Symbolic links not supported")); + + return NULL; +#endif +} + +/** + * g_path_is_absolute: + * @file_name: a file name + * + * Returns %TRUE if the given @file_name is an absolute file name. + * Note that this is a somewhat vague concept on Windows. + * + * On POSIX systems, an absolute file name is well-defined. It always + * starts from the single root directory. For example "/usr/local". + * + * On Windows, the concepts of current drive and drive-specific + * current directory introduce vagueness. This function interprets as + * an absolute file name one that either begins with a directory + * separator such as "\Users\tml" or begins with the root on a drive, + * for example "C:\Windows". The first case also includes UNC paths + * such as "\\myserver\docs\foo". In all cases, either slashes or + * backslashes are accepted. + * + * Note that a file name relative to the current drive root does not + * truly specify a file uniquely over time and across processes, as + * the current drive is a per-process value and can be changed. + * + * File names relative the current directory on some specific drive, + * such as "D:foo/bar", are not interpreted as absolute by this + * function, but they obviously are not relative to the normal current + * directory as returned by getcwd() or g_get_current_dir() + * either. Such paths should be avoided, or need to be handled using + * Windows-specific code. + * + * Returns: %TRUE if @file_name is absolute + */ +gboolean +g_path_is_absolute (const gchar *file_name) { - return g_format_size_full (size, G_FORMAT_SIZE_DEFAULT); + g_return_val_if_fail (file_name != NULL, FALSE); + + if (G_IS_DIR_SEPARATOR (file_name[0])) + return TRUE; + +#ifdef G_OS_WIN32 + /* Recognize drive letter on native Windows */ + if (g_ascii_isalpha (file_name[0]) && + file_name[1] == ':' && G_IS_DIR_SEPARATOR (file_name[2])) + return TRUE; +#endif + + return FALSE; } /** - * g_format_size_full: - * @size: a size in bytes - * @flags: #GFormatSizeFlags to modify the output - * - * Formats a size. - * - * This function is similar to g_format_size() but allows for flags that - * modify the output. See #GFormatSizeFlags. + * g_path_skip_root: + * @file_name: a file name * - * Returns: a newly-allocated formatted string containing a human - * readable file size. + * Returns a pointer into @file_name after the root component, + * i.e. after the "/" in UNIX or "C:\" under Windows. If @file_name + * is not an absolute path it returns %NULL. * - * Since: 2.30 - **/ -/** - * GFormatSizeFlags: - * @G_FORMAT_SIZE_DEFAULT: behave the same as g_format_size() - * @G_FORMAT_SIZE_LONG_FORMAT: include the exact number of bytes as part - * of the returned string. For example, - * "45.6 kB (45,612 bytes)". - * @G_FORMAT_SIZE_IEC_UNITS: use IEC (base 1024) units with "KiB"-style - * suffixes. IEC units should only be used - * for reporting things with a strong "power - * of 2" basis, like RAM sizes or RAID stripe - * sizes. Network and storage sizes should - * be reported in the normal SI units. - * - * Flags to modify the format of the string returned by - * g_format_size_full(). - **/ -gchar * -g_format_size_full (guint64 size, - GFormatSizeFlags flags) + * Returns: a pointer into @file_name after the root component + */ +const gchar * +g_path_skip_root (const gchar *file_name) { - GString *string; + g_return_val_if_fail (file_name != NULL, NULL); + +#ifdef G_PLATFORM_WIN32 + /* Skip \\server\share or //server/share */ + if (G_IS_DIR_SEPARATOR (file_name[0]) && + G_IS_DIR_SEPARATOR (file_name[1]) && + file_name[2] && + !G_IS_DIR_SEPARATOR (file_name[2])) + { + gchar *p; + p = strchr (file_name + 2, G_DIR_SEPARATOR); - string = g_string_new (NULL); +#ifdef G_OS_WIN32 + { + gchar *q; - if (flags & G_FORMAT_SIZE_IEC_UNITS) - { - if (size < KIBIBYTE_FACTOR) + q = strchr (file_name + 2, '/'); + if (p == NULL || (q != NULL && q < p)) + p = q; + } +#endif + + if (p && p > file_name + 2 && p[1]) { - g_string_printf (string, - g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes", (guint) size), - (guint) size); - flags &= ~G_FORMAT_SIZE_LONG_FORMAT; + file_name = p + 1; + + while (file_name[0] && !G_IS_DIR_SEPARATOR (file_name[0])) + file_name++; + + /* Possibly skip a backslash after the share name */ + if (G_IS_DIR_SEPARATOR (file_name[0])) + file_name++; + + return (gchar *)file_name; } + } +#endif + + /* Skip initial slashes */ + if (G_IS_DIR_SEPARATOR (file_name[0])) + { + while (G_IS_DIR_SEPARATOR (file_name[0])) + file_name++; + return (gchar *)file_name; + } - else if (size < MEBIBYTE_FACTOR) - g_string_printf (string, _("%.1f KiB"), (gdouble) size / (gdouble) KIBIBYTE_FACTOR); +#ifdef G_OS_WIN32 + /* Skip X:\ */ + if (g_ascii_isalpha (file_name[0]) && + file_name[1] == ':' && + G_IS_DIR_SEPARATOR (file_name[2])) + return (gchar *)file_name + 3; +#endif - else if (size < GIBIBYTE_FACTOR) - g_string_printf (string, _("%.1f MiB"), (gdouble) size / (gdouble) MEBIBYTE_FACTOR); + return NULL; +} - else if (size < TEBIBYTE_FACTOR) - g_string_printf (string, _("%.1f GiB"), (gdouble) size / (gdouble) GIBIBYTE_FACTOR); +/** + * g_basename: + * @file_name: the name of the file + * + * Gets the name of the file without any leading directory + * components. It returns a pointer into the given file name + * string. + * + * Returns: the name of the file without any leading + * directory components + * + * Deprecated:2.2: Use g_path_get_basename() instead, but notice + * that g_path_get_basename() allocates new memory for the + * returned string, unlike this function which returns a pointer + * into the argument. + */ +const gchar * +g_basename (const gchar *file_name) +{ + gchar *base; - else if (size < PEBIBYTE_FACTOR) - g_string_printf (string, _("%.1f TiB"), (gdouble) size / (gdouble) TEBIBYTE_FACTOR); + g_return_val_if_fail (file_name != NULL, NULL); - else if (size < EXBIBYTE_FACTOR) - g_string_printf (string, _("%.1f PiB"), (gdouble) size / (gdouble) PEBIBYTE_FACTOR); + base = strrchr (file_name, G_DIR_SEPARATOR); - else - g_string_printf (string, _("%.1f EiB"), (gdouble) size / (gdouble) EXBIBYTE_FACTOR); - } - else - { - if (size < KILOBYTE_FACTOR) - { - g_string_printf (string, - g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes", (guint) size), - (guint) size); - flags &= ~G_FORMAT_SIZE_LONG_FORMAT; - } +#ifdef G_OS_WIN32 + { + gchar *q; + q = strrchr (file_name, '/'); + if (base == NULL || (q != NULL && q > base)) + base = q; + } +#endif + + if (base) + return base + 1; - else if (size < MEGABYTE_FACTOR) - g_string_printf (string, _("%.1f kB"), (gdouble) size / (gdouble) KILOBYTE_FACTOR); +#ifdef G_OS_WIN32 + if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':') + return (gchar*) file_name + 2; +#endif - else if (size < GIGABYTE_FACTOR) - g_string_printf (string, _("%.1f MB"), (gdouble) size / (gdouble) MEGABYTE_FACTOR); + return (gchar*) file_name; +} - else if (size < TERABYTE_FACTOR) - g_string_printf (string, _("%.1f GB"), (gdouble) size / (gdouble) GIGABYTE_FACTOR); +/** + * g_path_get_basename: + * @file_name: the name of the file + * + * Gets the last component of the filename. + * + * If @file_name ends with a directory separator it gets the component + * before the last slash. If @file_name consists only of directory + * separators (and on Windows, possibly a drive letter), a single + * separator is returned. If @file_name is empty, it gets ".". + * + * Returns: a newly allocated string containing the last + * component of the filename + */ +gchar * +g_path_get_basename (const gchar *file_name) +{ + gssize base; + gssize last_nonslash; + gsize len; + gchar *retval; - else if (size < PETABYTE_FACTOR) - g_string_printf (string, _("%.1f TB"), (gdouble) size / (gdouble) TERABYTE_FACTOR); + g_return_val_if_fail (file_name != NULL, NULL); - else if (size < EXABYTE_FACTOR) - g_string_printf (string, _("%.1f PB"), (gdouble) size / (gdouble) PETABYTE_FACTOR); + if (file_name[0] == '\0') + return g_strdup ("."); - else - g_string_printf (string, _("%.1f EB"), (gdouble) size / (gdouble) EXABYTE_FACTOR); - } + last_nonslash = strlen (file_name) - 1; - if (flags & G_FORMAT_SIZE_LONG_FORMAT) - { - /* First problem: we need to use the number of bytes to decide on - * the plural form that is used for display, but the number of - * bytes potentially exceeds the size of a guint (which is what - * ngettext() takes). - * - * From a pragmatic standpoint, it seems that all known languages - * base plural forms on one or both of the following: - * - * - the lowest digits of the number - * - * - if the number if greater than some small value - * - * Here's how we fake it: Draw an arbitrary line at one thousand. - * If the number is below that, then fine. If it is above it, - * then we take the modulus of the number by one thousand (in - * order to keep the lowest digits) and add one thousand to that - * (in order to ensure that 1001 is not treated the same as 1). - */ - guint plural_form = size < 1000 ? size : size % 1000 + 1000; - - /* Second problem: we need to translate the string "%u byte" and - * "%u bytes" for pluralisation, but the correct number format to - * use for a gsize is different depending on which architecture - * we're on. - * - * Solution: format the number separately and use "%s bytes" on - * all platforms. - */ - const gchar *translated_format; - gchar *formatted_number; + while (last_nonslash >= 0 && G_IS_DIR_SEPARATOR (file_name [last_nonslash])) + last_nonslash--; - /* Translators: the %s in "%s bytes" will always be replaced by a number. */ - translated_format = g_dngettext(GETTEXT_PACKAGE, "%s byte", "%s bytes", plural_form); + if (last_nonslash == -1) + /* string only containing slashes */ + return g_strdup (G_DIR_SEPARATOR_S); - /* XXX: Windows doesn't support the "'" format modifier, so we - * must not use it there. Instead, just display the number - * without separation. Bug #655336 is open until a solution is - * found. - */ -#ifndef G_OS_WIN32 - formatted_number = g_strdup_printf ("%'"G_GUINT64_FORMAT, size); -#else - formatted_number = g_strdup_printf ("%"G_GUINT64_FORMAT, size); +#ifdef G_OS_WIN32 + if (last_nonslash == 1 && + g_ascii_isalpha (file_name[0]) && + file_name[1] == ':') + /* string only containing slashes and a drive */ + return g_strdup (G_DIR_SEPARATOR_S); #endif + base = last_nonslash; - g_string_append (string, " ("); - g_string_append_printf (string, translated_format, formatted_number); - g_free (formatted_number); - g_string_append (string, ")"); - } + while (base >=0 && !G_IS_DIR_SEPARATOR (file_name [base])) + base--; - return g_string_free (string, FALSE); +#ifdef G_OS_WIN32 + if (base == -1 && + g_ascii_isalpha (file_name[0]) && + file_name[1] == ':') + base = 1; +#endif /* G_OS_WIN32 */ + + len = last_nonslash - base; + retval = g_malloc (len + 1); + memcpy (retval, file_name + base + 1, len); + retval [len] = '\0'; + + return retval; } /** - * g_format_size_for_display: - * @size: a size in bytes. - * - * Formats a size (for example the size of a file) into a human readable string. - * Sizes are rounded to the nearest size prefix (KB, MB, GB) and are displayed - * rounded to the nearest tenth. E.g. the file size 3292528 bytes will be - * converted into the string "3.1 MB". + * g_dirname: + * @file_name: the name of the file * - * The prefix units base is 1024 (i.e. 1 KB is 1024 bytes). + * Gets the directory components of a file name. * - * This string should be freed with g_free() when not needed any longer. + * If the file name has no directory components "." is returned. + * The returned string should be freed when no longer needed. * - * Returns: a newly-allocated formatted string containing a human readable - * file size. + * Returns: the directory components of the file * - * Deprecated:2.30: This function is broken due to its use of SI - * suffixes to denote IEC units. Use g_format_size() - * instead. - * Since: 2.16 - **/ -char * -g_format_size_for_display (goffset size) + * Deprecated: use g_path_get_dirname() instead + */ + +/** + * g_path_get_dirname: + * @file_name: the name of the file + * + * Gets the directory components of a file name. + * + * If the file name has no directory components "." is returned. + * The returned string should be freed when no longer needed. + * + * Returns: the directory components of the file + */ +gchar * +g_path_get_dirname (const gchar *file_name) { - if (size < (goffset) KIBIBYTE_FACTOR) - return g_strdup_printf (g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes",(guint) size), (guint) size); - else + gchar *base; + gsize len; + + g_return_val_if_fail (file_name != NULL, NULL); + + base = strrchr (file_name, G_DIR_SEPARATOR); + +#ifdef G_OS_WIN32 + { + gchar *q; + q = strrchr (file_name, '/'); + if (base == NULL || (q != NULL && q > base)) + base = q; + } +#endif + + if (!base) { - gdouble displayed_size; - - if (size < (goffset) MEBIBYTE_FACTOR) - { - displayed_size = (gdouble) size / (gdouble) KIBIBYTE_FACTOR; - return g_strdup_printf (_("%.1f KB"), displayed_size); - } - else if (size < (goffset) GIBIBYTE_FACTOR) - { - displayed_size = (gdouble) size / (gdouble) MEBIBYTE_FACTOR; - return g_strdup_printf (_("%.1f MB"), displayed_size); - } - else if (size < (goffset) TEBIBYTE_FACTOR) - { - displayed_size = (gdouble) size / (gdouble) GIBIBYTE_FACTOR; - return g_strdup_printf (_("%.1f GB"), displayed_size); - } - else if (size < (goffset) PEBIBYTE_FACTOR) - { - displayed_size = (gdouble) size / (gdouble) TEBIBYTE_FACTOR; - return g_strdup_printf (_("%.1f TB"), displayed_size); - } - else if (size < (goffset) EXBIBYTE_FACTOR) - { - displayed_size = (gdouble) size / (gdouble) PEBIBYTE_FACTOR; - return g_strdup_printf (_("%.1f PB"), displayed_size); - } - else +#ifdef G_OS_WIN32 + if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':') + { + gchar drive_colon_dot[4]; + + drive_colon_dot[0] = file_name[0]; + drive_colon_dot[1] = ':'; + drive_colon_dot[2] = '.'; + drive_colon_dot[3] = '\0'; + + return g_strdup (drive_colon_dot); + } +#endif + return g_strdup ("."); + } + + while (base > file_name && G_IS_DIR_SEPARATOR (*base)) + base--; + +#ifdef G_OS_WIN32 + /* base points to the char before the last slash. + * + * In case file_name is the root of a drive (X:\) or a child of the + * root of a drive (X:\foo), include the slash. + * + * In case file_name is the root share of an UNC path + * (\\server\share), add a slash, returning \\server\share\ . + * + * In case file_name is a direct child of a share in an UNC path + * (\\server\share\foo), include the slash after the share name, + * returning \\server\share\ . + */ + if (base == file_name + 1 && + g_ascii_isalpha (file_name[0]) && + file_name[1] == ':') + base++; + else if (G_IS_DIR_SEPARATOR (file_name[0]) && + G_IS_DIR_SEPARATOR (file_name[1]) && + file_name[2] && + !G_IS_DIR_SEPARATOR (file_name[2]) && + base >= file_name + 2) + { + const gchar *p = file_name + 2; + while (*p && !G_IS_DIR_SEPARATOR (*p)) + p++; + if (p == base + 1) { - displayed_size = (gdouble) size / (gdouble) EXBIBYTE_FACTOR; - return g_strdup_printf (_("%.1f EB"), displayed_size); + len = (guint) strlen (file_name) + 1; + base = g_new (gchar, len + 1); + strcpy (base, file_name); + base[len-1] = G_DIR_SEPARATOR; + base[len] = 0; + return base; + } + if (G_IS_DIR_SEPARATOR (*p)) + { + p++; + while (*p && !G_IS_DIR_SEPARATOR (*p)) + p++; + if (p == base + 1) + base++; } } +#endif + + len = (guint) 1 + base - file_name; + base = g_new (gchar, len + 1); + memmove (base, file_name, len); + base[len] = 0; + + return base; } +#if defined(MAXPATHLEN) +#define G_PATH_LENGTH MAXPATHLEN +#elif defined(PATH_MAX) +#define G_PATH_LENGTH PATH_MAX +#elif defined(_PC_PATH_MAX) +#define G_PATH_LENGTH sysconf(_PC_PATH_MAX) +#else +#define G_PATH_LENGTH 2048 +#endif /** - * g_file_read_link: - * @filename: the symbolic link - * @error: return location for a #GError + * g_get_current_dir: * - * Reads the contents of the symbolic link @filename like the POSIX - * readlink() function. The returned string is in the encoding used - * for filenames. Use g_filename_to_utf8() to convert it to UTF-8. + * Gets the current directory. * - * Returns: A newly-allocated string with the contents of the symbolic link, - * or %NULL if an error occurred. + * The returned string should be freed when no longer needed. + * The encoding of the returned string is system defined. + * On Windows, it is always UTF-8. * - * Since: 2.4 + * Since GLib 2.40, this function will return the value of the "PWD" + * environment variable if it is set and it happens to be the same as + * the current directory. This can make a difference in the case that + * the current directory is the target of a symbolic link. + * + * Returns: the current directory */ gchar * -g_file_read_link (const gchar *filename, - GError **error) +g_get_current_dir (void) { -#ifdef HAVE_READLINK - gchar *buffer; - guint size; - gint read_size; - - size = 256; - buffer = g_malloc (size); - - while (TRUE) +#ifdef G_OS_WIN32 + + gchar *dir = NULL; + wchar_t dummy[2], *wdir; + int len; + + len = GetCurrentDirectoryW (2, dummy); + wdir = g_new (wchar_t, len); + + if (GetCurrentDirectoryW (len, wdir) == len - 1) + dir = g_utf16_to_utf8 (wdir, -1, NULL, NULL, NULL); + + g_free (wdir); + + if (dir == NULL) + dir = g_strdup ("\\"); + + return dir; + +#else + const gchar *pwd; + gchar *buffer = NULL; + gchar *dir = NULL; + static gulong max_len = 0; + struct stat pwdbuf, dotbuf; + + pwd = g_getenv ("PWD"); + if (pwd != NULL && + g_stat (".", &dotbuf) == 0 && g_stat (pwd, &pwdbuf) == 0 && + dotbuf.st_dev == pwdbuf.st_dev && dotbuf.st_ino == pwdbuf.st_ino) + return g_strdup (pwd); + + if (max_len == 0) + max_len = (G_PATH_LENGTH == -1) ? 2048 : G_PATH_LENGTH; + + while (max_len < G_MAXULONG / 2) { - read_size = readlink (filename, buffer, size); - if (read_size < 0) { - int save_errno = errno; - gchar *display_filename = g_filename_display_name (filename); - - g_free (buffer); - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to read the symbolic link '%s': %s"), - display_filename, - g_strerror (save_errno)); - g_free (display_filename); - - return NULL; - } - - if (read_size < size) - { - buffer[read_size] = 0; - return buffer; - } - - size *= 2; - buffer = g_realloc (buffer, size); + g_free (buffer); + buffer = g_new (gchar, max_len + 1); + *buffer = 0; + dir = getcwd (buffer, max_len); + + if (dir || errno != ERANGE) + break; + + max_len *= 2; } -#else - g_set_error_literal (error, - G_FILE_ERROR, - G_FILE_ERROR_INVAL, - _("Symbolic links not supported")); - - return NULL; -#endif + + if (!dir || !*buffer) + { + /* hm, should we g_error() out here? + * this can happen if e.g. "./" has mode \0000 + */ + buffer[0] = G_DIR_SEPARATOR; + buffer[1] = 0; + } + + dir = g_strdup (buffer); + g_free (buffer); + + return dir; + +#endif /* !G_OS_WIN32 */ } -/* NOTE : Keep this part last to ensure nothing in this file uses the + +/* NOTE : Keep this part last to ensure nothing in this file uses thn * below binary compatibility versions. */ #if defined (G_OS_WIN32) && !defined (_WIN64) @@ -2286,13 +2553,21 @@ g_file_get_contents (const gchar *filename, #undef g_mkstemp +static gint +wrap_libc_open (const gchar *filename, + int flags, + int mode) +{ + return open (filename, flags, mode); +} + gint g_mkstemp (gchar *tmpl) { /* This is the backward compatibility system codepage version, * thus use normal open(). */ - return get_tmp_file (tmpl, (GTmpFileCallback) open, + return get_tmp_file (tmpl, wrap_libc_open, O_RDWR | O_CREAT | O_EXCL, 0600); } @@ -2323,4 +2598,16 @@ g_file_open_tmp (const gchar *tmpl, return retval; } +#undef g_get_current_dir + +gchar * +g_get_current_dir (void) +{ + gchar *utf8_dir = g_get_current_dir_utf8 (); + gchar *dir = g_locale_from_utf8 (utf8_dir, -1, NULL, NULL, NULL); + g_free (utf8_dir); + return dir; +} + #endif +