+/* Make path appear as if a chroot had occurred. This handles a leading
+ * "/" (either removing it or expanding it) and any leading or embedded
+ * ".." components that attempt to escape past the module's top dir.
+ *
+ * If dest is NULL, a buffer is allocated to hold the result. It is legal
+ * to call with the dest and the path (p) pointing to the same buffer, but
+ * rootdir will be ignored to avoid expansion of the string.
+ *
+ * The rootdir string contains a value to use in place of a leading slash.
+ * Specify NULL to get the default of "module_dir".
+ *
+ * The depth var is a count of how many '..'s to allow at the start of the
+ * path.
+ *
+ * We also clean the path in a manner similar to clean_fname() but with a
+ * few differences:
+ *
+ * Turns multiple adjacent slashes into a single slash, gets rid of "." dir
+ * elements (INCLUDING a trailing dot dir), PRESERVES a trailing slash, and
+ * ALWAYS collapses ".." elements (except for those at the start of the
+ * string up to "depth" deep). If the resulting name would be empty,
+ * change it into a ".". */
+char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth,
+ int flags)
+{
+ char *start, *sanp;
+ int rlen = 0, drop_dot_dirs = !relative_paths || !(flags & SP_KEEP_DOT_DIRS);
+
+ if (dest != p) {
+ int plen = strlen(p);
+ if (*p == '/') {
+ if (!rootdir)
+ rootdir = module_dir;
+ rlen = strlen(rootdir);
+ depth = 0;
+ p++;
+ }
+ if (dest) {
+ if (rlen + plen + 1 >= MAXPATHLEN)
+ return NULL;
+ } else if (!(dest = new_array(char, rlen + plen + 1)))
+ out_of_memory("sanitize_path");
+ if (rlen) {
+ memcpy(dest, rootdir, rlen);
+ if (rlen > 1)
+ dest[rlen++] = '/';
+ }
+ }