diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | file-utils.c | 118 | ||||
-rw-r--r-- | libnul.h | 5 |
3 files changed, 124 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am index 4273d74..530e464 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,6 +9,7 @@ libnul_la_SOURCES = \ array.c \ epoll.c \ signal-handler.c \ + file-utils.c \ libnul.h clean-local: diff --git a/file-utils.c b/file-utils.c new file mode 100644 index 0000000..99806e4 --- /dev/null +++ b/file-utils.c @@ -0,0 +1,118 @@ +/* libnul + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * Copyright (C) 2009 Soren Sandmann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include <string.h> +#include "libnul.h" + +/* nul_canonicalize_filename cutted and pasted from GIO + * + * Author: Alexander Larsson + */ +char * +nul_canonicalize_filename (const char *filename) +{ + char *canon, *start, *p, *q; + char *cwd; + int i; + + g_return_val_if_fail (filename != NULL, NULL); + + if (!g_path_is_absolute (filename)) + { + cwd = g_get_current_dir (); + canon = g_build_filename (cwd, filename, NULL); + g_free (cwd); + } + else + canon = g_strdup (filename); + + start = (char *)g_path_skip_root (canon); + + /* POSIX allows double slashes at the start to + * mean something special (as does windows too). + * So, "//" != "/", but more than two slashes + * is treated as "/". + */ + i = 0; + for (p = start - 1; + (p >= canon) && + G_IS_DIR_SEPARATOR (*p); + p--) + i++; + if (i > 2) + { + i -= 1; + start -= i; + memmove (start, start+i, strlen (start+i)+1); + } + + p = start; + while (*p != 0) + { + if (p[0] == '.' && (p[1] == 0 || G_IS_DIR_SEPARATOR (p[1]))) + { + memmove (p, p+1, strlen (p+1)+1); + } + else if (p[0] == '.' && p[1] == '.' && + (p[2] == 0 || G_IS_DIR_SEPARATOR (p[2]))) + { + q = p + 2; + /* Skip previous separator */ + + p = p - 2; + if (p < start) + p = start; + while (p > start && !G_IS_DIR_SEPARATOR (*p)) + p--; + if (G_IS_DIR_SEPARATOR (*p)) + *p++ = G_DIR_SEPARATOR; + memmove (p, q, strlen (q)+1); + } + else + { + /* Skip until next separator */ + while (*p != 0 && !G_IS_DIR_SEPARATOR (*p)) + p++; + + if (*p != 0) + { + /* Canonicalize one separator */ + *p++ = G_DIR_SEPARATOR; + } + } + + /* Remove additional separators */ + q = p; + while (*q && G_IS_DIR_SEPARATOR (*q)) + q++; + + if (p != q) + memmove (p, q, strlen (q)+1); + } + + /* Remove trailing slashes */ + if (p > start && G_IS_DIR_SEPARATOR (*(p-1))) + *(p-1) = 0; + + return canon; +} + @@ -245,6 +245,11 @@ void nul_fd_remove_watch (int fd); gboolean nul_fd_is_watched (int fd); /* + * File utilities + */ +char *nul_canonicalize_filename (const char *filename); + +/* * Unix signal handlers */ typedef void (* signal_func_t) (int signo, gpointer data); |