1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * \brief file related functions
33 #include <sys/param.h>
40 #include <sys/types.h>
48 # define WIN32_LEAN_AND_MEAN
49 # include <windows.h> /* for GetFullPathName */
52 #include "libgeda_priv.h"
54 #ifdef HAVE_LIBDMALLOC
58 /*! \brief Get the autosave filename for a file
59 * \par Function description
60 * Returns the expected autosave filename for the \a filename passed.
62 * \warning The result should be freed when no longer needed.
64 * \param [in] filename The filename to create an autosave filename for.
65 * \return A newly allocated string buffer.
67 gchar
*f_get_autosave_filename (const gchar
*filename
)
69 gchar
*result
, *basename
, *new_basename
, *dirname
;
70 basename
= g_path_get_basename(filename
);
71 dirname
= g_path_get_dirname(filename
);
72 new_basename
= g_strdup_printf(AUTOSAVE_BACKUP_FILENAME_STRING
,
74 result
= g_build_filename(dirname
, new_basename
, NULL
);
83 /*! \brief Check if a file has an active autosave file
84 * \par Function Description
85 * Checks whether an autosave file exists for the \a filename passed
86 * which has a modification time newer than the file itself. If the
87 * check fails, sets \a err with the reason. N.b. if the autosave
88 * file exists but it was not possible to get its modification time,
91 * \param [in] filename File to check
92 * \param [in,out] err #GError structure for error reporting, or
93 * NULL to disable error reporting
95 * \returns TRUE if autosave active, FALSE otherwise
97 gboolean
f_has_active_autosave (const gchar
*filename
, GError
**err
)
99 gboolean result
= FALSE
;
100 gchar
*auto_filename
;
103 GFileError g_errcode
= 0;
104 struct stat file_stat
, auto_stat
;
106 auto_filename
= f_get_autosave_filename (filename
);
107 if (stat (filename
, &file_stat
) != 0) {
110 if (stat (auto_filename
, &auto_stat
) != 0) {
114 /* A valid use of goto! (checks for raptors) */
115 if (auto_err
& ENOENT
) {
116 /* The autosave file does not exist. */
118 goto check_autosave_finish
;
121 g_errcode
= g_file_error_from_errno (auto_err
);
122 g_set_error (err
, G_FILE_ERROR
, g_errcode
,
123 _("Failed to stat [%s]: %s"),
124 auto_filename
, g_strerror (auto_err
));
126 goto check_autosave_finish
;
128 if (file_err
& ENOENT
) {
129 /* The autosave file exists, but the actual file does not. */
131 goto check_autosave_finish
;
134 g_errcode
= g_file_error_from_errno (file_err
);
135 g_set_error (err
, G_FILE_ERROR
, g_errcode
,
136 _("Failed to stat [%s]: %s"),
137 auto_filename
, g_strerror (file_err
));
139 goto check_autosave_finish
;
141 /* If we got this far, both files exist and we have managed to get
142 * their stat info. */
143 if (difftime (file_stat
.st_mtime
, auto_stat
.st_mtime
) < 0) {
147 check_autosave_finish
:
148 g_free (auto_filename
);
152 /*! \brief Opens the schematic file.
153 * \par Function Description
154 * Opens the schematic file by calling f_open_flags() with the
155 * F_OPEN_RC and F_OPEN_CHECK_BACKUP flags.
157 * \param [in,out] toplevel The TOPLEVEL object to load the schematic into.
158 * \param [in] filename A character string containing the file name
160 * \param [in,out] err #GError structure for error reporting, or
161 * NULL to disable error reporting
163 * \return 0 on failure, 1 on success.
165 int f_open(TOPLEVEL
*toplevel
, PAGE
*page
,
166 const gchar
*filename
, GError
**err
)
168 return f_open_flags (toplevel
, page
, filename
,
169 F_OPEN_RC
| F_OPEN_CHECK_BACKUP
, err
);
172 /*! \brief Opens the schematic file with fine-grained control over behaviour.
173 * \par Function Description
174 * Opens the schematic file and carries out a number of actions
175 * depending on the \a flags set. If #F_OPEN_RC is set, executes
176 * configuration files found in the target directory. If
177 * #F_OPEN_CHECK_BACKUP is set, warns user if a backup is found for
178 * the file being loaded, and possibly prompts user for whether to
179 * load the backup instead. If #F_OPEN_RESTORE_CWD is set, does not
180 * change the working directory to that of the file being loaded.
182 * \param [in,out] toplevel The TOPLEVEL object to load the schematic into.
183 * \param [in] filename A character string containing the file name
185 * \param [in] flags Combination of #FOpenFlags values.
186 * \param [in,out] err #GError structure for error reporting, or
187 * NULL to disable error reporting
189 * \return 0 on failure, 1 on success.
191 int f_open_flags(TOPLEVEL
*toplevel
, PAGE
*page
,
192 const gchar
*filename
,
193 const gint flags
, GError
**err
)
196 char *full_filename
= NULL
;
197 char *full_rcfilename
= NULL
;
198 char *file_directory
= NULL
;
199 char *saved_cwd
= NULL
;
200 char *backup_filename
= NULL
;
201 char load_backup_file
= 0;
202 GError
*tmp_err
= NULL
;
204 /* has the head been freed yet? */
205 /* probably not hack PAGE */
207 set_window(toplevel
, page
,
208 toplevel
->init_left
, toplevel
->init_right
,
209 toplevel
->init_top
, toplevel
->init_bottom
);
212 /* Cache the cwd so we can restore it later. */
213 if (flags
& F_OPEN_RESTORE_CWD
) {
214 saved_cwd
= g_get_current_dir();
217 /* get full, absolute path to file */
218 full_filename
= f_normalize_filename (filename
, &tmp_err
);
219 if (full_filename
== NULL
) {
220 g_set_error (err
, G_FILE_ERROR
, tmp_err
->code
,
221 _("Cannot find file %s: %s"),
222 filename
, tmp_err
->message
);
223 g_error_free(tmp_err
);
227 /* write full, absolute filename into page->page_filename */
228 g_free(page
->page_filename
);
229 page
->page_filename
= g_strdup(full_filename
);
231 /* Before we open the page, let's load the corresponding gafrc. */
232 /* First cd into file's directory. */
233 file_directory
= g_dirname (full_filename
);
235 if (file_directory
) {
236 if (chdir (file_directory
)) {
237 /* Error occurred with chdir */
238 #warning FIXME: What do we do?
242 /* Now open RC and process file */
243 if (flags
& F_OPEN_RC
) {
244 full_rcfilename
= g_build_filename (file_directory
, "gafrc", NULL
);
245 g_rc_parse_file (toplevel
, full_rcfilename
, &tmp_err
);
246 if (tmp_err
!= NULL
) {
247 /* Config files are allowed to be missing or skipped; check for
249 if (!g_error_matches (tmp_err
, G_FILE_ERROR
, G_FILE_ERROR_NOENT
) &&
250 !g_error_matches (tmp_err
, EDA_ERROR
, EDA_ERROR_RC_TWICE
)) {
251 s_log_message ("%s\n", tmp_err
->message
);
253 g_error_free (tmp_err
);
258 g_free (file_directory
);
260 if (flags
& F_OPEN_CHECK_BACKUP
) {
261 /* Check if there is a newer autosave backup file */
263 gboolean active_backup
= f_has_active_autosave (full_filename
, &tmp_err
);
264 backup_filename
= f_get_autosave_filename (full_filename
);
266 if (tmp_err
!= NULL
) g_warning ("%s\n", tmp_err
->message
);
268 message
= g_string_new ("");
269 g_string_append_printf(message
, _("\nWARNING: Found an autosave backup file:\n %s.\n\n"), backup_filename
);
270 if (tmp_err
!= NULL
) {
271 g_string_append(message
, _("I could not guess if it is newer, so you have to do it manually.\n"));
273 g_string_append(message
, _("The backup copy is newer than the schematic, so it seems you should load it instead of the original file.\n"));
275 g_string_append (message
, _("Gschem usually makes backup copies automatically, and this situation happens when it crashed or it was forced to exit abruptly.\n"));
276 if (toplevel
->load_newer_backup_func
== NULL
) {
277 g_warning ("%s", message
->str
);
278 g_warning (_("\nRun gschem and correct the situation.\n\n"));
280 /* Ask the user if load the backup or the original file */
281 if (toplevel
->load_newer_backup_func
282 (toplevel
->load_newer_backup_data
, message
)) {
283 /* Load the backup file */
284 load_backup_file
= 1;
287 g_string_free (message
, TRUE
);
289 if (tmp_err
!= NULL
) g_error_free (tmp_err
);
292 /* Now that we have set the current directory and read
293 * the RC file, it's time to read in the file. */
294 if (load_backup_file
== 1) {
295 /* Load the backup file */
296 s_page_append_list (toplevel
, page
,
297 o_read (toplevel
, NULL
, backup_filename
, &tmp_err
));
299 /* Load the original file */
300 s_page_append_list (toplevel
, page
,
301 o_read (toplevel
, NULL
, full_filename
, &tmp_err
));
307 g_propagate_error (err
, tmp_err
);
309 if (load_backup_file
== 0) {
310 /* If it's not the backup file */
311 page
->CHANGED
=0; /* added 4/7/98 */
313 /* We are loading the backup file, so gschem should ask
314 the user if save it or not when closing the page. */
318 g_free(full_filename
);
319 g_free(full_rcfilename
);
320 g_free (backup_filename
);
322 /* Reset the directory to the value it had when f_open was
324 if (flags
& F_OPEN_RESTORE_CWD
) {
325 if (chdir (saved_cwd
)) {
326 /* Error occurred with chdir */
327 #warning FIXME: What do we do?
335 /*! \brief Closes the schematic file
336 * \par Function Description
339 * \param [in,out] toplevel The TOPLEVEL object with schematic to be closed.
341 void f_close(TOPLEVEL
*toplevel
)
346 /*! \brief Save the schematic file
347 * \par Function Description
348 * This function saves the current schematic file in the toplevel object.
350 * \bug g_access introduces a race condition in certain cases, but
351 * solves bug #698565 in the normal use-case
353 * \param [in,out] toplevel The TOPLEVEL object containing the schematic.
354 * \param [in] filename The file name to save the schematic to.
355 * \param [in,out] err #GError structure for error reporting, or
356 * NULL to disable error reporting
357 * \return 1 on success, 0 on failure.
359 int f_save(TOPLEVEL
*toplevel
, PAGE
*page
, const char *filename
, GError
**err
)
361 gchar
*backup_filename
;
362 gchar
*real_filename
;
363 gchar
*only_filename
;
365 mode_t saved_umask
, mask
;
367 GError
*tmp_err
= NULL
;
369 /* Get the real filename and file permissions */
370 real_filename
= follow_symlinks (filename
, &tmp_err
);
372 if (real_filename
== NULL
) {
373 g_set_error (err
, tmp_err
->domain
, tmp_err
->code
,
374 _("Can't get the real filename of %s: %s"),
380 /* Check to see if filename is writable */
381 if (g_file_test(filename
, G_FILE_TEST_EXISTS
) &&
382 g_access(filename
, W_OK
) != 0) {
383 g_set_error (err
, G_FILE_ERROR
, G_FILE_ERROR_PERM
,
384 _("File %s is read-only"), filename
);
388 /* Get the directory in which the real filename lives */
389 dirname
= g_path_get_dirname (real_filename
);
390 only_filename
= g_path_get_basename(real_filename
);
392 /* Do a backup if it's not an undo file backup and it was never saved. */
393 if (page
->saved_since_first_loaded
== 0) {
394 if ( (g_file_test (real_filename
, G_FILE_TEST_EXISTS
)) &&
395 (!g_file_test(real_filename
, G_FILE_TEST_IS_DIR
)) )
397 backup_filename
= g_strdup_printf("%s%c%s~", dirname
,
398 G_DIR_SEPARATOR
, only_filename
);
400 /* Make the backup file read-write before saving a new one */
401 if ( g_file_test (backup_filename
, G_FILE_TEST_EXISTS
) &&
402 (! g_file_test (backup_filename
, G_FILE_TEST_IS_DIR
))) {
403 if (chmod(backup_filename
, S_IREAD
|S_IWRITE
) != 0) {
404 s_log_message (_("Could NOT set previous backup file [%s] read-write\n"),
409 if (rename(real_filename
, backup_filename
) != 0) {
410 s_log_message (_("Can't save backup file: %s."), backup_filename
);
413 /* Make the backup file readonly so a 'rm *' command will ask
414 the user before deleting it */
415 saved_umask
= umask(0);
416 mask
= (S_IWRITE
|S_IWGRP
|S_IEXEC
|S_IXGRP
|S_IXOTH
);
418 mask
&= ((~saved_umask
) & 0777);
419 if (chmod(backup_filename
, mask
) != 0) {
420 s_log_message (_("Could NOT set backup file [%s] readonly\n"),
426 g_free(backup_filename
);
429 /* If there is not an existing file with that name, compute the
430 * permissions and uid/gid that we will use for the newly-created file.
433 if (stat (real_filename
, &st
) != 0)
438 /* Use default permissions */
439 saved_umask
= umask(0);
440 st
.st_mode
= 0666 & ~saved_umask
;
443 st
.st_uid
= getuid ();
445 result
= stat (dirname
, &dir_st
);
447 if (result
== 0 && (dir_st
.st_mode
& S_ISGID
))
448 st
.st_gid
= dir_st
.st_gid
;
450 st
.st_gid
= getgid ();
451 #endif /* HAVE_CHOWN */
454 g_free (only_filename
);
456 if (o_save (toplevel
, s_page_objects (page
), real_filename
, &tmp_err
)) {
458 page
->saved_since_first_loaded
= 1;
460 /* Reset the last saved timer */
461 g_get_current_time (&page
->last_load_or_save_time
);
462 page
->ops_since_last_backup
= 0;
463 page
->do_autosave_backup
= 0;
465 /* Restore permissions. */
466 chmod (real_filename
, st
.st_mode
);
468 if (chown (real_filename
, st
.st_uid
, st
.st_gid
)) {
469 /* Error occured with chown */
470 #warning FIXME: What do we do?
474 g_free (real_filename
);
478 g_set_error (err
, tmp_err
->domain
, tmp_err
->code
,
479 _("Could NOT save file: %s"), tmp_err
->message
);
480 g_clear_error (&tmp_err
);
481 g_free (real_filename
);
486 /*! \brief Builds an absolute pathname.
487 * \par Function Description
488 * This function derives an absolute pathname for the pathname
489 * pointed to by \a name with '.' and '..' resolved. It does not
490 * resolve symbolic links.
492 * It returns NULL and sets the \a error (if not NULL) if it failed
493 * to build the pathname or the pathname does not exists.
496 * The code for this function is derived from the realpath() of
497 * the GNU C Library (Copyright (C) 1996-2002, 2004, 2005, 2006 Free
498 * Software Foundation, Inc. / LGPL 2.1 or later).
500 * The part for the resolution of symbolic links has been discarded
501 * and it has been adapted for glib and for use on Windows.
503 * \param [in] name A character string containing the pathname
505 * \param [in,out] error Return location for a GError, or NULL.
506 * \return A newly-allocated string with the resolved absolute
507 * pathname on success, NULL otherwise.
509 gchar
*f_normalize_filename (const gchar
*name
, GError
**error
)
515 const char *start
, *end
;
519 g_set_error (error
, G_FILE_ERROR
, G_FILE_ERROR_INVAL
,
520 "%s", g_strerror (EINVAL
));
525 g_set_error (error
, G_FILE_ERROR
, G_FILE_ERROR_NOENT
,
526 "%s", g_strerror (ENOENT
));
531 /* Windows method (modified) from libiberty's lrealpath.c, GPL V2+
533 * We assume we don't have symlinks and just canonicalize to a
534 * Windows absolute path. GetFullPathName converts ../ and ./ in
535 * relative paths to absolute paths, filling in current drive if
536 * one is not given or using the current directory of a specified
537 * drive (eg, "E:foo"). It also converts all forward slashes to
540 DWORD len
= GetFullPathName (name
, MAX_PATH
, buf
, NULL
);
543 if (len
== 0 || len
> MAX_PATH
- 1) {
544 result
= g_strdup (name
);
546 /* The file system is case-preserving but case-insensitive,
547 * canonicalize to lowercase, using the codepage associated
548 * with the process locale. */
549 CharLowerBuff (buf
, len
);
550 result
= g_strdup (buf
);
553 /* Test that the file actually exists, and fail if it doesn't. We
554 * do this to be consistent with the behaviour on POSIX
556 if (!g_file_test (result
, G_FILE_TEST_EXISTS
)) {
557 g_set_error (error
, G_FILE_ERROR
, G_FILE_ERROR_NOENT
,
558 "%s", g_strerror (ENOENT
));
565 #define ROOT_MARKER_LEN 1
567 rpath
= g_string_sized_new (strlen (name
));
569 /* if relative path, prepend current dir */
570 if (!g_path_is_absolute (name
)) {
571 gchar
*cwd
= g_get_current_dir ();
572 g_string_append (rpath
, cwd
);
574 if (!G_IS_DIR_SEPARATOR (rpath
->str
[rpath
->len
- 1])) {
575 g_string_append_c (rpath
, G_DIR_SEPARATOR
);
578 g_string_append_len (rpath
, name
, ROOT_MARKER_LEN
);
579 /* move to first path separator */
580 name
+= ROOT_MARKER_LEN
- 1;
583 for (start
= end
= name
; *start
!= '\0'; start
= end
) {
584 /* skip sequence of multiple path-separators */
585 while (G_IS_DIR_SEPARATOR (*start
)) {
589 /* find end of path component */
590 for (end
= start
; *end
!= '\0' && !G_IS_DIR_SEPARATOR (*end
); ++end
);
592 if (end
- start
== 0) {
594 } else if (end
- start
== 1 && start
[0] == '.') {
596 } else if (end
- start
== 2 && start
[0] == '.' && start
[1] == '.') {
597 /* back up to previous component, ignore if at root already. */
598 if (rpath
->len
> ROOT_MARKER_LEN
) {
599 while (!G_IS_DIR_SEPARATOR (rpath
->str
[(--rpath
->len
) - 1]));
600 g_string_set_size (rpath
, rpath
->len
);
603 /* path component, copy to new path */
604 if (!G_IS_DIR_SEPARATOR (rpath
->str
[rpath
->len
- 1])) {
605 g_string_append_c (rpath
, G_DIR_SEPARATOR
);
608 g_string_append_len (rpath
, start
, end
- start
);
610 if (!g_file_test (rpath
->str
, G_FILE_TEST_EXISTS
)) {
611 g_set_error (error
,G_FILE_ERROR
, G_FILE_ERROR_NOENT
,
612 "%s", g_strerror (ENOENT
));
614 } else if (!g_file_test (rpath
->str
, G_FILE_TEST_IS_DIR
) &&
616 g_set_error (error
,G_FILE_ERROR
, G_FILE_ERROR_NOTDIR
,
617 "%s", g_strerror (ENOTDIR
));
623 if (G_IS_DIR_SEPARATOR (rpath
->str
[rpath
->len
- 1]) &&
624 rpath
->len
> ROOT_MARKER_LEN
) {
625 g_string_set_size (rpath
, rpath
->len
- 1);
628 return g_string_free (rpath
, FALSE
);
631 g_string_free (rpath
, TRUE
);
633 #undef ROOT_MARKER_LEN
637 /*! \brief Follow symlinks until a real file is found
638 * \par Function Description
639 * Does readlink() recursively until we find a real filename.
641 * \param [in] filename The filename to search for.
642 * \param [in,out] err #GError structure for error reporting,
643 * or NULL to disable error reporting.
644 * \return The newly-allocated path to real file on success, NULL
647 * \note Originally taken from gedit's source code.
649 char *follow_symlinks (const gchar
*filename
, GError
**err
)
651 gchar
*followed_filename
= NULL
;
653 GError
*tmp_err
= NULL
;
655 if (filename
== NULL
) {
656 g_set_error (err
, G_FILE_ERROR
, G_FILE_ERROR_INVAL
,
657 "%s", g_strerror (EINVAL
));
661 if (strlen (filename
) + 1 > MAXPATHLEN
) {
662 g_set_error (err
, G_FILE_ERROR
, G_FILE_ERROR_NAMETOOLONG
,
663 "%s", g_strerror (ENAMETOOLONG
));
667 followed_filename
= g_strdup (filename
);
670 /* MinGW does not have symlinks */
671 return followed_filename
;
674 while (link_count
< MAX_LINK_LEVEL
) {
676 gchar
*linkname
= NULL
;
678 if (lstat (followed_filename
, &st
) != 0) {
679 /* We could not access the file, so perhaps it does not
680 * exist. Return this as a real name so that we can
681 * attempt to create the file.
683 return followed_filename
;
686 if (!S_ISLNK (st
.st_mode
)) {
687 /* It's not a link, so we've found what we're looking for! */
688 return followed_filename
;
693 linkname
= g_file_read_link (followed_filename
, &tmp_err
);
695 if (linkname
== NULL
) {
696 g_propagate_error(err
, tmp_err
);
697 g_free (followed_filename
);
701 /* If the linkname is not an absolute path name, append
702 * it to the directory name of the followed filename. E.g.
703 * we may have /foo/bar/baz.lnk -> eek.txt, which really
704 * is /foo/bar/eek.txt.
707 if (!g_path_is_absolute(linkname
)) {
708 gchar
*dirname
= NULL
;
711 dirname
= g_path_get_dirname(followed_filename
);
713 tmp
= g_build_filename (dirname
, linkname
, NULL
);
714 g_free (followed_filename
);
717 followed_filename
= tmp
;
719 g_free (followed_filename
);
720 followed_filename
= linkname
;
724 /* Too many symlinks */
725 g_set_error (err
, G_FILE_ERROR
, G_FILE_ERROR_LOOP
,
726 _("%s: %s"), g_strerror (EMLINK
), followed_filename
);
727 g_free (followed_filename
);
730 #endif /* __MINGW32__ */