]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
gnulib module 'canonicalize'.
authorBruno Haible <bruno@clisp.org>
Mon, 17 Mar 2003 09:31:39 +0000 (09:31 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 23 Jun 2009 10:10:16 +0000 (12:10 +0200)
gettext-tools/lib/canonicalize.c [new file with mode: 0644]
gettext-tools/lib/canonicalize.h [new file with mode: 0644]
gettext-tools/m4/canonicalize.m4 [new file with mode: 0644]

diff --git a/gettext-tools/lib/canonicalize.c b/gettext-tools/lib/canonicalize.c
new file mode 100644 (file)
index 0000000..35b114e
--- /dev/null
@@ -0,0 +1,303 @@
+/* Return the canonical absolute name of a given file.
+   Copyright (C) 1996-2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C 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.1 of the License, or (at your option) any later version.
+
+   The GNU C 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 the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if !HAVE_CANONICALIZE_FILE_NAME || defined _LIBC
+
+#include <alloca.h>
+
+/* Specification.  */
+#include "canonicalize.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+#endif
+
+#include <limits.h>
+
+#if HAVE_SYS_PARAM_H || defined _LIBC
+# include <sys/param.h>
+#endif
+#ifndef MAXSYMLINKS
+# define MAXSYMLINKS 20
+#endif
+
+#include <sys/stat.h>
+
+#include <errno.h>
+#ifndef _LIBC
+# define __set_errno(e) errno = (e)
+# ifndef ENAMETOOLONG
+#  define ENAMETOOLONG EINVAL
+# endif
+#endif
+
+#ifdef _LIBC
+# include <shlib-compat.h>
+#else
+# define SHLIB_COMPAT(lib, introduced, obsoleted) 0
+# define versioned_symbol(lib, local, symbol, version)
+# define compat_symbol(lib, local, symbol, version)
+# define weak_alias(local, symbol)
+# define __canonicalize_file_name canonicalize_file_name
+# define __realpath rpl_realpath
+# include "pathmax.h"
+# define __alloca alloca
+# if HAVE_GETCWD
+#  define __getcwd getcwd
+# else
+#  define __getcwd(buf, max) getwd (buf)
+# endif
+# define __readlink readlink
+#endif
+
+/* Return the canonical absolute name of file NAME.  A canonical name
+   does not contain any `.', `..' components nor any repeated path
+   separators ('/') or symlinks.  All path components must exist.  If
+   RESOLVED is null, the result is malloc'd; otherwise, if the
+   canonical name is PATH_MAX chars or more, returns null with `errno'
+   set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
+   returns the name in RESOLVED.  If the name cannot be resolved and
+   RESOLVED is non-NULL, it contains the path of the first component
+   that cannot be resolved.  If the path can be resolved, RESOLVED
+   holds the same value as the value returned.  */
+
+char *
+__realpath (const char *name, char *resolved)
+{
+  char *rpath, *dest, *extra_buf = NULL;
+  const char *start, *end, *rpath_limit;
+  long int path_max;
+  int num_links = 0;
+
+  if (name == NULL)
+    {
+      /* As per Single Unix Specification V2 we must return an error if
+        either parameter is a null pointer.  We extend this to allow
+        the RESOLVED parameter to be NULL in case the we are expected to
+        allocate the room for the return value.  */
+      __set_errno (EINVAL);
+      return NULL;
+    }
+
+  if (name[0] == '\0')
+    {
+      /* As per Single Unix Specification V2 we must return an error if
+        the name argument points to an empty string.  */
+      __set_errno (ENOENT);
+      return NULL;
+    }
+
+#ifdef PATH_MAX
+  path_max = PATH_MAX;
+#else
+  path_max = pathconf (name, _PC_PATH_MAX);
+  if (path_max <= 0)
+    path_max = 1024;
+#endif
+
+  if (resolved == NULL)
+    {
+      rpath = malloc (path_max);
+      if (rpath == NULL)
+       return NULL;
+    }
+  else
+    rpath = resolved;
+  rpath_limit = rpath + path_max;
+
+  if (name[0] != '/')
+    {
+      if (!__getcwd (rpath, path_max))
+       {
+         rpath[0] = '\0';
+         goto error;
+       }
+      dest = strchr (rpath, '\0');
+    }
+  else
+    {
+      rpath[0] = '/';
+      dest = rpath + 1;
+    }
+
+  for (start = end = name; *start; start = end)
+    {
+#ifdef _LIBC
+      struct stat64 st;
+#else
+      struct stat st;
+#endif
+      int n;
+
+      /* Skip sequence of multiple path-separators.  */
+      while (*start == '/')
+       ++start;
+
+      /* Find end of path component.  */
+      for (end = start; *end && *end != '/'; ++end)
+       /* Nothing.  */;
+
+      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 (dest > rpath + 1)
+           while ((--dest)[-1] != '/');
+       }
+      else
+       {
+         size_t new_size;
+
+         if (dest[-1] != '/')
+           *dest++ = '/';
+
+         if (dest + (end - start) >= rpath_limit)
+           {
+             ptrdiff_t dest_offset = dest - rpath;
+             char *new_rpath;
+
+             if (resolved)
+               {
+                 __set_errno (ENAMETOOLONG);
+                 if (dest > rpath + 1)
+                   dest--;
+                 *dest = '\0';
+                 goto error;
+               }
+             new_size = rpath_limit - rpath;
+             if (end - start + 1 > path_max)
+               new_size += end - start + 1;
+             else
+               new_size += path_max;
+             new_rpath = (char *) realloc (rpath, new_size);
+             if (new_rpath == NULL)
+               goto error;
+             rpath = new_rpath;
+             rpath_limit = rpath + new_size;
+
+             dest = rpath + dest_offset;
+           }
+
+#ifdef _LIBC
+         dest = __mempcpy (dest, start, end - start);
+#else
+         memcpy (dest, start, end - start);
+         dest += end - start;
+#endif
+         *dest = '\0';
+
+#ifdef _LIBC
+         if (__lxstat64 (_STAT_VER, rpath, &st) < 0)
+#else
+         if (lstat (rpath, &st) < 0)
+#endif
+           goto error;
+
+#ifdef S_ISLNK
+         if (S_ISLNK (st.st_mode))
+           {
+             char *buf = __alloca (path_max);
+             size_t len;
+
+             if (++num_links > MAXSYMLINKS)
+               {
+                 __set_errno (ELOOP);
+                 goto error;
+               }
+
+             n = __readlink (rpath, buf, path_max);
+             if (n < 0)
+               goto error;
+             buf[n] = '\0';
+
+             if (!extra_buf)
+               extra_buf = __alloca (path_max);
+
+             len = strlen (end);
+             if ((long int) (n + len) >= path_max)
+               {
+                 __set_errno (ENAMETOOLONG);
+                 goto error;
+               }
+
+             /* Careful here, end may be a pointer into extra_buf... */
+             memmove (&extra_buf[n], end, len + 1);
+             name = end = memcpy (extra_buf, buf, n);
+
+             if (buf[0] == '/')
+               dest = rpath + 1;       /* It's an absolute symlink */
+             else
+               /* Back up to previous component, ignore if at root already: */
+               if (dest > rpath + 1)
+                 while ((--dest)[-1] != '/');
+           }
+#endif
+       }
+    }
+  if (dest > rpath + 1 && dest[-1] == '/')
+    --dest;
+  *dest = '\0';
+
+  return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath;
+
+error:
+  if (resolved)
+    strcpy (resolved, rpath);
+  else
+    free (rpath);
+  return NULL;
+}
+versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
+
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
+char *
+__old_realpath (const char *name, char *resolved)
+{
+  if (resolved == NULL)
+    {
+      __set_errno (EINVAL);
+      return NULL;
+    }
+
+  return __realpath (name, resolved);
+}
+compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0);
+#endif
+
+
+char *
+__canonicalize_file_name (const char *name)
+{
+  return __realpath (name, NULL);
+}
+weak_alias (__canonicalize_file_name, canonicalize_file_name)
+
+#endif
diff --git a/gettext-tools/lib/canonicalize.h b/gettext-tools/lib/canonicalize.h
new file mode 100644 (file)
index 0000000..c076e91
--- /dev/null
@@ -0,0 +1,21 @@
+/* Return the canonical absolute name of a given file.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Return a malloc'd string containing the canonical absolute name of the
+   named file.  The last file name component need not exist, and may be a
+   symlink to a nonexistent file.  */ 
+extern char *canonicalize_file_name (const char *name);
diff --git a/gettext-tools/m4/canonicalize.m4 b/gettext-tools/m4/canonicalize.m4
new file mode 100644 (file)
index 0000000..48e9836
--- /dev/null
@@ -0,0 +1,26 @@
+# canonicalize.m4 serial 1 (gettext-0.12)
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+AC_DEFUN([gl_CANONICALIZE],
+[
+  dnl Do this replacement check manually because the file name is shorter
+  dnl than the function name.
+  AC_CHECK_FUNC(canonicalize_file_name, , [
+    AC_LIBOBJ(canonicalize)
+    AC_DEFINE([realpath], [rpl_realpath],
+      [Define to a replacement function name for realpath().])
+    gl_PREREQ_CANONICALIZE
+  ])
+])
+
+# Prerequisites of lib/canonicalize.c.
+AC_DEFUN([gl_PREREQ_CANONICALIZE],
+[
+  AC_CHECK_HEADERS_ONCE(sys/param.h unistd.h)
+  AC_CHECK_FUNCS(getcwd)
+])