Modifies f_normalize_filename() to avoid using realpath() and
resolving symlinks. It is derived from the GNU Lib C implementation of
realpath() with glib GString and glib portable file-related functions.
---
gattrib/src/gattrib.c | 8 +++-
libgeda/include/prototype.h | 2 +-
libgeda/src/f_basic.c | 127 +++++++++++++++++++++++++++++++++++++------
libgeda/src/g_basic.c | 2 +-
libgeda/src/g_rc.c | 13 +++--
libgeda/src/s_hierarchy.c | 2 +-
6 files changed, 127 insertions(+), 27 deletions(-)
diff --git a/gattrib/src/gattrib.c b/gattrib/src/gattrib.c
index c3bdd49..60b6401 100644
--- a/gattrib/src/gattrib.c
+++ b/gattrib/src/gattrib.c
@@ -200,7 +200,13 @@ void gattrib_main(void *closure, int argc, char *argv[])
/* Construct the list of filenames from the command line.
* argv_index holds the position of the first filename */
while (argv_index < argc) {
- file_list = g_slist_append(file_list,
f_normalize_filename(argv[argv_index]));
+ gchar *filename = f_normalize_filename(argv[argv_index], NULL);
+ if (filename != NULL) {
+ file_list = g_slist_append(file_list, filename);
+ } else {
+ fprintf(stderr, "Couldn't find file [%s]\n", argv[argv_index]);
+ exit(1);
+ }
argv_index++;
}
}
diff --git a/libgeda/include/prototype.h b/libgeda/include/prototype.h
index 610611a..eabf6bb 100644
--- a/libgeda/include/prototype.h
+++ b/libgeda/include/prototype.h
@@ -16,7 +16,7 @@ int f_open_flags(TOPLEVEL *toplevel, const gchar *filename,
void f_close(TOPLEVEL *toplevel);
void f_save_close(TOPLEVEL *toplevel, char *filename);
int f_save(TOPLEVEL *toplevel, const char *filename);
-char* f_normalize_filename(const gchar *filename);
+gchar *f_normalize_filename (const gchar *filename, GError **error);
char *follow_symlinks (const gchar *filename, GError **error);
/* f_print.c */
diff --git a/libgeda/src/f_basic.c b/libgeda/src/f_basic.c
index cfaf94b..daf0ce6 100644
--- a/libgeda/src/f_basic.c
+++ b/libgeda/src/f_basic.c
@@ -204,7 +204,13 @@ int f_open_flags(TOPLEVEL *toplevel, const gchar *filename,
}
/* get full, absolute path to file */
- full_filename = f_normalize_filename(filename);
+ full_filename = f_normalize_filename (filename, &tmp_err);
+ if (full_filename == NULL) {
+ g_set_error (err, G_FILE_ERROR, tmp_err->code,
+ _("Cannot find file %s: %s"),
+ filename, g_strerror (tmp_err->code));
+ return 0;
+ }
/* write full, absolute filename into page_current->page_filename */
if (toplevel->page_current->page_filename) {
@@ -460,33 +466,118 @@ int f_save(TOPLEVEL *toplevel, const char *filename)
}
}
-/*! \brief Reformats a filename as an absolute resolved filename
+/*! \brief Builds an absolute pathname.
* \par Function Description
- * Given a filename in any format, this returns the full, absolute
- * resolved filename.
+ * This function derives an absolute pathname for the pathname
+ * pointed to by \a name with '.' and '..' resolved. It does not
+ * resolve symbolic links.
+ *
+ * It returns NULL and sets the \a error (if not NULL) if it failed
+ * to build the pathname or the pathname does not exists.
+ *
+ * \note
+ * The code for this function is derived from the realpath() of
+ * the GNU C Library (Copyright (C) 1996-2002, 2004, 2005, 2006 Free
+ * Software Foundation, Inc. / LGPL 2.1 or later).
*
- * \param [in] filename A character string containing the file
- * name to resolve.
- * \return A character string with the resolved filename.
+ * The part for the resolution of symbolic links has been discarded
+ * and it has been adapted for glib and for use on Windows.
+ *
+ * \param [in] name A character string containing the pathname
+ * to resolve.
+ * \param [in,out] error Return location for a GError, or NULL.
+ * \return A newly-allocated string with the resolved absolute
+ * pathname on success, NULL otherwise.
*/
-char* f_normalize_filename(const gchar *filename)
+gchar *f_normalize_filename (const gchar *name, GError **error)
{
- char filename_buffer[MAXPATHLEN]; /* nasty hack for realpath */
- char *full_filename;
+#ifdef G_OS_WIN32
+#define ROOT_MARKER_LEN 3
+#else
+#define ROOT_MARKER_LEN 1
+#endif /* G_OS_WIN32 */
+ GString *rpath;
+ const char *start, *end;
+
+ if (name == NULL) {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL,
+ g_strerror (EINVAL));
+ return NULL;
+ }
- /* Check for pathological case */
- if (filename == NULL) {
+ if (*name == '\0') {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT,
+ g_strerror (ENOENT));
return NULL;
}
- realpath(filename, filename_buffer); /* places reult in filename_buffer */
- full_filename = g_strdup (filename_buffer);
+ rpath = g_string_sized_new (strlen (name));
+
+ /* if relative path, prepend current dir */
+ if (!g_path_is_absolute (name)) {
+ gchar *cwd = g_get_current_dir ();
+ g_string_append (rpath, cwd);
+ g_free (cwd);
+ if (!G_IS_DIR_SEPARATOR (rpath->str[rpath->len - 1])) {
+ g_string_append_c (rpath, G_DIR_SEPARATOR);
+ }
+ } else {
+ g_string_append_len (rpath, name, ROOT_MARKER_LEN);
+ /* move to first path separator */
+ name += ROOT_MARKER_LEN - 1;
+ }
-#ifdef DEBUG
- printf("In f_normalize_filename, returning full_filename= %s \n",
full_filename);
-#endif
+ for (start = end = name; *start != '\0'; start = end) {
+ /* skip sequence of multiple path-separators */
+ while (G_IS_DIR_SEPARATOR (*start)) {
+ ++start;
+ }
+
+ /* find end of path component */
+ for (end = start; *end != '\0' && !G_IS_DIR_SEPARATOR (*end); ++end);
+
+ if (end - start == 0) {
+ break;
+ } else if (end - start == 1 && start[0] == '.') {
+ /* nothing */;
+ } else if (end - start == 2 && start[0] == '.' && start[1] == '.') {
+ /* back up to previous component, ignore if at root already. */
+ if (rpath->len > ROOT_MARKER_LEN) {
+ while (!G_IS_DIR_SEPARATOR (rpath->str[(--rpath->len) - 1]));
+ g_string_set_size (rpath, rpath->len);
+ }
+ } else {
+ /* path component, copy to new path */
+ if (!G_IS_DIR_SEPARATOR (rpath->str[rpath->len - 1])) {
+ g_string_append_c (rpath, G_DIR_SEPARATOR);
+ }
+
+ g_string_append_len (rpath, start, end - start);
+
+ if (!g_file_test (rpath->str, G_FILE_TEST_EXISTS)) {
+ g_set_error (error,G_FILE_ERROR, G_FILE_ERROR_NOENT,
+ g_strerror (ENOENT));
+ goto error;
+ } else if (!g_file_test (rpath->str, G_FILE_TEST_IS_DIR) &&
+ *end != '\0') {
+ g_set_error (error,G_FILE_ERROR, G_FILE_ERROR_NOTDIR,
+ g_strerror (ENOTDIR));
+ goto error;
+ }
+ }
+ }
+
+ if (G_IS_DIR_SEPARATOR (rpath->str[rpath->len - 1]) &&
+ rpath->len > ROOT_MARKER_LEN) {
+ g_string_set_size (rpath, rpath->len - 1);
+ }
+
+ return g_string_free (rpath, FALSE);
- return full_filename;
+ error:
+ g_string_free (rpath, TRUE);
+ return NULL;
+#undef ROOT_MARKER_LEN
}
/*! \brief Follow symlinks until a real file is found
diff --git a/libgeda/src/g_basic.c b/libgeda/src/g_basic.c
index 1cfd062..540761d 100644
--- a/libgeda/src/g_basic.c
+++ b/libgeda/src/g_basic.c
@@ -273,7 +273,7 @@ int g_read_file(const gchar *filename)
}
/* get full, absolute path to file */
- full_filename = f_normalize_filename(filename);
+ full_filename = f_normalize_filename (filename, NULL);
if (full_filename == NULL) {
return(-1);
}
diff --git a/libgeda/src/g_rc.c b/libgeda/src/g_rc.c
index a0472ab..5fb2f8e 100644
--- a/libgeda/src/g_rc.c
+++ b/libgeda/src/g_rc.c
@@ -203,7 +203,7 @@ gint g_rc_parse_system_rc(TOPLEVEL *toplevel, const gchar
*rcname)
G_DIR_SEPARATOR_S,
"system-", rcname,
NULL);
- filename = f_normalize_filename(tmp);
+ filename = f_normalize_filename (tmp, NULL);
if (filename == NULL) {
return 0;
}
@@ -248,7 +248,7 @@ gint g_rc_parse_home_rc(TOPLEVEL *toplevel, const gchar
*rcname)
G_DIR_SEPARATOR_S,
rcname,
NULL);
- filename = f_normalize_filename(tmp);
+ filename = f_normalize_filename (tmp, NULL);
if (filename == NULL) {
return 0;
}
@@ -284,7 +284,7 @@ gint g_rc_parse_local_rc(TOPLEVEL *toplevel, const gchar
*rcname)
gchar *err_msg;
tmp = g_strconcat (".", G_DIR_SEPARATOR_S, rcname, NULL);
- filename = f_normalize_filename (tmp);
+ filename = f_normalize_filename (tmp, NULL);
if (filename == NULL) {
return 0;
}
@@ -323,7 +323,10 @@ gint g_rc_parse_specified_rc(TOPLEVEL *toplevel, const
gchar *rcname)
return 0;
}
- filename = f_normalize_filename (rcname);
+ filename = f_normalize_filename (rcname, NULL);
+ if (filename == NULL) {
+ return 0;
+ }
rcbasename = g_path_get_basename (rcname);
@@ -362,7 +365,7 @@ void g_rc_parse(TOPLEVEL *toplevel,
/* set the GEDADATARC environment variable so that the rc files */
/* know where to look for others */
- rc_path = f_normalize_filename (g_rc_parse_path ());
+ rc_path = f_normalize_filename (g_rc_parse_path (), NULL);
g_setenv ("GEDADATARC", rc_path, TRUE);
g_free (rc_path);
diff --git a/libgeda/src/s_hierarchy.c b/libgeda/src/s_hierarchy.c
index 116b652..2e207c8 100644
--- a/libgeda/src/s_hierarchy.c
+++ b/libgeda/src/s_hierarchy.c
@@ -75,7 +75,7 @@ int s_hierarchy_down_schematic_single(TOPLEVEL *toplevel,
switch (flag) {
case HIERARCHY_NORMAL_LOAD:
{
- gchar *filename = f_normalize_filename (string);
+ gchar *filename = f_normalize_filename (string, NULL);
found = s_page_search (toplevel, filename);
g_free (filename);
--
1.5.6
_______________________________________________
geda-dev mailing list
[email protected]
http://www.seul.org/cgi-bin/mailman/listinfo/geda-dev