示例#1
0
char *
mfile_name_concat (char const *dir, char const *abase, char **base_in_result)
{
  char const *dirbase = last_component (dir);
  size_t dirbaselen = base_len (dirbase);
  size_t dirlen = dirbase - dir + dirbaselen;
  size_t needs_separator = (dirbaselen && ! ISSLASH (dirbase[dirbaselen - 1]));

  char const *base = longest_relative_suffix (abase);
  size_t baselen = strlen (base);

  char *p_concat = malloc (dirlen + needs_separator + baselen + 1);
  char *p;

  if (p_concat == NULL)
    return NULL;

  p = mempcpy (p_concat, dir, dirlen);
  *p = DIRECTORY_SEPARATOR;
  p += needs_separator;

  if (base_in_result)
    *base_in_result = p - IS_ABSOLUTE_FILE_NAME (abase);

  p = mempcpy (p, base, baselen);
  *p = '\0';

  return p_concat;
}
示例#2
0
void ReflushPTS(utmp *utmpbuf, int utmphandle, passwd *pw)
{
  int nowe;
  utmp *nowu;
  char line[sizeof (utmpbuf->ut_line) + DEV_DIR_LEN + 1];                      
  char *p = line, *modelstr;
  int lastPTS;

  lastPTS = nowPTS;
  nowPTS = 0;
  for (int i=0; i<lastPTS; i++) {
    close(openedPTS[i]);
  }
  nowe = entriesUTMP(utmphandle);
  nowu = utmpbuf;

  while (nowe--) {
    if (nowu->ut_type == USER_PROCESS) {
      if ( !strncmp(pw->pw_name, nowu->ut_user, sizeof(nowu->ut_user))) {

	if ( ! IS_ABSOLUTE_FILE_NAME (nowu->ut_line))                             
	  p = strncpy (p, DEV_DIR_WITH_TRAILING_SLASH, sizeof(DEV_DIR_WITH_TRAILING_SLASH));
	else
	  *p = 0;
	strncat (p, nowu->ut_line, sizeof(nowu->ut_line));
	openedPTS[nowPTS] = open(p, O_RDWR);
	nowPTS++;
      }
    }
    nowu++;
  }
  //  getScreenText(&modelstr);
  //  writeToPTS(p, modelstr);  
}
示例#3
0
/*
  This function takes a path and a mode, it calls computecon to get the
  label of the path object if the current process created it, then it calls
  matchpathcon to get the default type for the object.  It substitutes the
  default type into label.  It tells the SELinux Kernel to label all new file
  system objects created by the current process with this label.

  Returns -1 on failure.  errno will be set appropriately.
*/
int
defaultcon (char const *path, mode_t mode)
{
  int rc = -1;
  char *scon = NULL;
  char *tcon = NULL;
  context_t scontext = 0, tcontext = 0;
  const char *contype;
  char *constr;
  char *newpath = NULL;

  if (! IS_ABSOLUTE_FILE_NAME (path))
    {
      /* Generate absolute path as required by subsequent matchpathcon(),
         with libselinux < 2.1.5 2011-0826.  */
      newpath = canonicalize_filename_mode (path, CAN_MISSING);
      if (! newpath)
        error (EXIT_FAILURE, errno, _("error canonicalizing %s"),
               quote (path));
      path = newpath;
    }

  if (matchpathcon (path, mode, &scon) < 0)
    {
      /* "No such file or directory" is a confusing error,
         when processing files, when in fact it was the
         associated default context that was not found.
         Therefore map the error to something more appropriate
         to the context in which we're using matchpathcon().  */
      if (errno == ENOENT)
        errno = ENODATA;
      goto quit;
    }
  if (computecon (path, mode, &tcon) < 0)
    goto quit;
  if (!(scontext = context_new (scon)))
    goto quit;
  if (!(tcontext = context_new (tcon)))
    goto quit;

  if (!(contype = context_type_get (scontext)))
    goto quit;
  if (context_type_set (tcontext, contype))
    goto quit;
  if (!(constr = context_str (tcontext)))
    goto quit;

  rc = setfscreatecon (constr);

quit:
  context_free (scontext);
  context_free (tcontext);
  freecon (scon);
  freecon (tcon);
  free (newpath);
  return rc;
}
示例#4
0
/*
  This function takes three parameters:

  PATH of an existing file system object.

  A RECURSE boolean which if the file system object is a directory, will
  call restorecon_private on every file system object in the directory.

  A LOCAL boolean that indicates whether the function should set object labels
  to the default for the local process, or use system wide settings.

  Returns false on failure.  errno will be set appropriately.
*/
bool
restorecon (char const *path, bool recurse, bool local)
{
  char *newpath = NULL;
  FTS *fts;
  bool ok = true;

  if (! IS_ABSOLUTE_FILE_NAME (path) && ! local)
    {
      /* Generate absolute path as required by subsequent matchpathcon(),
         with libselinux < 2.1.5 2011-0826.  Also generating the absolute
         path before the fts walk, will generate absolute paths in the
         fts entries, which may be quicker to process in any case.  */
      newpath = canonicalize_filename_mode (path, CAN_MISSING);
      if (! newpath)
        error (EXIT_FAILURE, errno, _("error canonicalizing %s"),
               quote (path));
    }

  const char *ftspath[2] = { newpath ? newpath : path, NULL };

  if (! recurse)
    {
      ok = restorecon_private (*ftspath, local) != -1;
      free (newpath);
      return ok;
    }

  fts = xfts_open ((char *const *) ftspath, FTS_PHYSICAL, NULL);
  while (1)
    {
      FTSENT *ent;

      ent = fts_read (fts);
      if (ent == NULL)
        {
          if (errno != 0)
            {
              error (0, errno, _("fts_read failed"));
              ok = false;
            }
          break;
        }

      ok &= restorecon_private (fts->fts_path, local) != -1;
    }

  if (fts_close (fts) != 0)
    {
      error (0, errno, _("fts_close failed"));
      ok = false;
    }

  free (newpath);
  return ok;
}
示例#5
0
文件: m4_path.c 项目: stevenylai/clib
FILE *
m4_path_search (const char *file, char **result)
{
  FILE *fp;
  includes *incl;
  char *name;                   /* buffer for constructed name */
  int e;

  if (result)
    *result = NULL;

  /* Reject empty file.  */
  if (!*file)
    {
      errno = ENOENT;
      return NULL;
    }

  /* Look in current working directory first.  */
  fp = m4_fopen (file);
  if (fp != NULL)
    {
      if (result)
        *result = xstrdup (file);
      return fp;
    }

  /* If file not found, and filename absolute, fail.  */
  if (IS_ABSOLUTE_FILE_NAME (file) || no_gnu_extensions)
    return NULL;
  e = errno;

  for (incl = dir_list; incl != NULL; incl = incl->next)
    {
      name = mfile_name_concat (incl->dir, file, NULL);

#ifdef DEBUG_INCL
      xfprintf (stderr, "m4_path_search (%s) -- trying %s\n", file, name);
#endif

      fp = m4_fopen (name);
      if (fp != NULL)
        {
          if (debug_level & DEBUG_TRACE_PATH)
            DEBUG_MESSAGE2 ("path search for `%s' found `%s'", file, name);
          if (result)
            *result = name;
          else
            free (name);
          return fp;
        }
      free (name);
    }
  errno = e;
  return fp;
}
示例#6
0
int
savewd_process_files (int n_files, char **file,
                      int (*act) (char *, struct savewd *, void *),
                      void *options)
{
  int i = 0;
  int last_relative;
  int exit_status = EXIT_SUCCESS;
  struct savewd wd;
  savewd_init (&wd);

  for (last_relative = n_files - 1; 0 <= last_relative; last_relative--)
    if (! IS_ABSOLUTE_FILE_NAME (file[last_relative]))
      break;

  for (; i < last_relative; i++)
    {
      if (! savewd_delegating (&wd))
        {
          int s = act (file[i], &wd, options);
          if (exit_status < s)
            exit_status = s;
        }

      if (! IS_ABSOLUTE_FILE_NAME (file[i + 1]))
        {
          int r = savewd_restore (&wd, exit_status);
          if (exit_status < r)
            exit_status = r;
        }
    }

  savewd_finish (&wd);

  for (; i < n_files; i++)
    {
      int s = act (file[i], &wd, options);
      if (exit_status < s)
        exit_status = s;
    }

  return exit_status;
}
示例#7
0
/* DIR is the operand of a -C option; add it to vector of chdir targets,
   and return the index of its location.  */
int chdir_arg(char const *dir)
{
  char *absdir;

  if (wd_count == wd_alloc)
    {
      if (wd_alloc == 0)
	wd_alloc = 2;
      wd = x2nrealloc (wd, &wd_alloc, sizeof *wd);

      if (! wd_count)
	{
    char path[PATH_MAX+1];

    memset(path, 0, sizeof(path));
    getcwd(path, sizeof(path) - 1);

	  wd[wd_count].name = ".";
	  wd[wd_count].abspath = strdup(path);
	  wd[wd_count].fd = AT_FDCWD;
	  wd_count++;
	}
    }

  /* Optimize the common special case of the working directory,
     or the working directory as a prefix.  */
  if (dir[0])
    {
      while (dir[0] == '.' && ISSLASH (dir[1]))
	for (dir += 2;  ISSLASH (*dir);  dir++)
	  continue;
      if (! dir[dir[0] == '.'])
	return wd_count - 1;
    }


  /* If the given name is absolute, use it to represent this directory;
     otherwise, construct a name based on the previous -C option.  */
  if (IS_ABSOLUTE_FILE_NAME (dir))
    absdir = xstrdup (dir);
  else if (wd[wd_count - 1].abspath)
    {
      namebuf_t nbuf = namebuf_create (wd[wd_count - 1].abspath);
      namebuf_add_dir (nbuf, dir);
      absdir = namebuf_finish (nbuf);
    }
  else
    absdir = 0;

  wd[wd_count].name = dir;
  wd[wd_count].abspath = absdir;
  wd[wd_count].fd = 0;
  return wd_count++;
}
示例#8
0
文件: misc.c 项目: Happuri/various
/* Change to directory I, in a virtual way.  This does not actually
   invoke chdir; it merely sets chdir_fd to an int suitable as the
   first argument for openat, etc.  If I is 0, change to the initial
   working directory; otherwise, I must be a value returned by
   chdir_arg.  */
void
chdir_do (int i)
{
  if (chdir_current != i)
    {
      struct wd *curr = &wd[i];
      int fd = curr->fd;

      if (! fd)
	{
	  if (! IS_ABSOLUTE_FILE_NAME (curr->name))
	    chdir_do (i - 1);
	  fd = openat (chdir_fd, curr->name,
		       open_searchdir_flags & ~ O_NOFOLLOW);
	  if (fd < 0)
	    open_fatal (curr->name);

	  curr->fd = fd;

	  /* Add I to the cache, tossing out the lowest-ranking entry if the
	     cache is full.  */
	  if (wdcache_count < CHDIR_CACHE_SIZE)
	    wdcache[wdcache_count++] = i;
	  else
	    {
	      struct wd *stale = &wd[wdcache[CHDIR_CACHE_SIZE - 1]];
	      if (close (stale->fd) != 0)
		close_diag (stale->name);
	      stale->fd = 0;
	      wdcache[CHDIR_CACHE_SIZE - 1] = i;
	    }
	}

      if (0 < fd)
	{
	  /* Move the i value to the front of the cache.  This is
	     O(CHDIR_CACHE_SIZE), but the cache is small.  */
	  size_t ci;
	  int prev = wdcache[0];
	  for (ci = 1; prev != i; ci++)
	    {
	      int cur = wdcache[ci];
	      wdcache[ci] = prev;
	      if (cur == i)
		break;
	      prev = cur;
	    }
	  wdcache[0] = i;
	}

      chdir_current = i;
      chdir_fd = fd;
    }
}
示例#9
0
/* Return an absolute name of DIR in malloc'd storage.  */
static char *
get_name (char const *dir)
{
  char *cwd;
  char *result;
  int saved_errno;

  if (IS_ABSOLUTE_FILE_NAME (dir))
    return strdup (dir);

  /* We often encounter "."; treat it as a special case.  */
  cwd = getcwd (NULL, 0);
  if (!cwd || (dir[0] == '.' && dir[1] == '\0'))
    return cwd;

  result = mfile_name_concat (cwd, dir, NULL);
  saved_errno = errno;
  free (cwd);
  errno = saved_errno;
  return result;
}
示例#10
0
/* Rename the file SRC to DST.  This replacement is necessary on
   Windows, on which the system rename function will not replace
   an existing DST.  */
int
rpl_rename (char const *src, char const *dst)
{
  int error;
  size_t src_len = strlen (src);
  size_t dst_len = strlen (dst);
  char *src_base = last_component (src);
  char *dst_base = last_component (dst);
  bool src_slash;
  bool dst_slash;
  bool dst_exists;
  struct stat src_st;
  struct stat dst_st;

  /* Filter out dot as last component.  */
  if (!src_len || !dst_len)
    {
      errno = ENOENT;
      return -1;
    }
  if (*src_base == '.')
    {
      size_t len = base_len (src_base);
      if (len == 1 || (len == 2 && src_base[1] == '.'))
        {
          errno = EINVAL;
          return -1;
        }
    }
  if (*dst_base == '.')
    {
      size_t len = base_len (dst_base);
      if (len == 1 || (len == 2 && dst_base[1] == '.'))
        {
          errno = EINVAL;
          return -1;
        }
    }

  /* Presence of a trailing slash requires directory semantics.  If
     the source does not exist, or if the destination cannot be turned
     into a directory, give up now.  Otherwise, strip trailing slashes
     before calling rename.  There are no symlinks on mingw, so stat
     works instead of lstat.  */
  src_slash = ISSLASH (src[src_len - 1]);
  dst_slash = ISSLASH (dst[dst_len - 1]);
  if (stat (src, &src_st))
    return -1;
  if (stat (dst, &dst_st))
    {
      if (errno != ENOENT || (!S_ISDIR (src_st.st_mode) && dst_slash))
        return -1;
      dst_exists = false;
    }
  else
    {
      if (S_ISDIR (dst_st.st_mode) != S_ISDIR (src_st.st_mode))
        {
          errno = S_ISDIR (dst_st.st_mode) ? EISDIR : ENOTDIR;
          return -1;
        }
      dst_exists = true;
    }

  /* There are no symlinks, so if a file existed with a trailing
     slash, it must be a directory, and we don't have to worry about
     stripping strip trailing slash.  However, mingw refuses to
     replace an existing empty directory, so we have to help it out.
     And canonicalize_file_name is not yet ported to mingw; however,
     for directories, getcwd works as a viable alternative.  Ensure
     that we can get back to where we started before using it; later
     attempts to return are fatal.  Note that we can end up losing a
     directory if rename then fails, but it was empty, so not much
     damage was done.  */
  if (dst_exists && S_ISDIR (dst_st.st_mode))
    {
      char *cwd = getcwd (NULL, 0);
      char *src_temp;
      char *dst_temp;
      if (!cwd || chdir (cwd))
        return -1;
      if (IS_ABSOLUTE_FILE_NAME (src))
        {
          dst_temp = chdir (dst) ? NULL : getcwd (NULL, 0);
          src_temp = chdir (src) ? NULL : getcwd (NULL, 0);
        }
      else
        {
          src_temp = chdir (src) ? NULL : getcwd (NULL, 0);
          if (!IS_ABSOLUTE_FILE_NAME (dst) && chdir (cwd))
            abort ();
          dst_temp = chdir (dst) ? NULL : getcwd (NULL, 0);
        }
      if (chdir (cwd))
        abort ();
      free (cwd);
      if (!src_temp || !dst_temp)
        {
          free (src_temp);
          free (dst_temp);
          errno = ENOMEM;
          return -1;
        }
      src_len = strlen (src_temp);
      if (strncmp (src_temp, dst_temp, src_len) == 0
          && (ISSLASH (dst_temp[src_len]) || dst_temp[src_len] == '\0'))
        {
          error = dst_temp[src_len];
          free (src_temp);
          free (dst_temp);
          if (error)
            {
              errno = EINVAL;
              return -1;
            }
          return 0;
        }
      if (rmdir (dst))
        {
          error = errno;
          free (src_temp);
          free (dst_temp);
          errno = error;
          return -1;
        }
      free (src_temp);
      free (dst_temp);
    }

  /* MoveFileEx works if SRC is a directory without any flags, but
     fails with MOVEFILE_REPLACE_EXISTING, so try without flags first.
     Thankfully, MoveFileEx handles hard links correctly, even though
     rename() does not.  */
  if (MoveFileEx (src, dst, 0))
    return 0;

  /* Retry with MOVEFILE_REPLACE_EXISTING if the move failed
     due to the destination already existing.  */
  error = GetLastError ();
  if (error == ERROR_FILE_EXISTS || error == ERROR_ALREADY_EXISTS)
    {
      if (MoveFileEx (src, dst, MOVEFILE_REPLACE_EXISTING))
        return 0;

      error = GetLastError ();
    }

  switch (error)
    {
    case ERROR_FILE_NOT_FOUND:
    case ERROR_PATH_NOT_FOUND:
    case ERROR_BAD_PATHNAME:
    case ERROR_DIRECTORY:
      errno = ENOENT;
      break;

    case ERROR_ACCESS_DENIED:
    case ERROR_SHARING_VIOLATION:
      errno = EACCES;
      break;

    case ERROR_OUTOFMEMORY:
      errno = ENOMEM;
      break;

    case ERROR_CURRENT_DIRECTORY:
      errno = EBUSY;
      break;

    case ERROR_NOT_SAME_DEVICE:
      errno = EXDEV;
      break;

    case ERROR_WRITE_PROTECT:
      errno = EROFS;
      break;

    case ERROR_WRITE_FAULT:
    case ERROR_READ_FAULT:
    case ERROR_GEN_FAILURE:
      errno = EIO;
      break;

    case ERROR_HANDLE_DISK_FULL:
    case ERROR_DISK_FULL:
    case ERROR_DISK_TOO_FRAGMENTED:
      errno = ENOSPC;
      break;

    case ERROR_FILE_EXISTS:
    case ERROR_ALREADY_EXISTS:
      errno = EEXIST;
      break;

    case ERROR_BUFFER_OVERFLOW:
    case ERROR_FILENAME_EXCED_RANGE:
      errno = ENAMETOOLONG;
      break;

    case ERROR_INVALID_NAME:
    case ERROR_DELETE_PENDING:
      errno = EPERM;        /* ? */
      break;

# ifndef ERROR_FILE_TOO_LARGE
/* This value is documented but not defined in all versions of windows.h.  */
#  define ERROR_FILE_TOO_LARGE 223
# endif
    case ERROR_FILE_TOO_LARGE:
      errno = EFBIG;
      break;

    default:
      errno = EINVAL;
      break;
    }

  return -1;
}
示例#11
0
int
openat_permissive (int fd, char const *file, int flags, mode_t mode,
                   int *cwd_errno)
{
    struct saved_cwd saved_cwd;
    int saved_errno;
    int err;
    bool save_ok;

    if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
        return open (file, flags, mode);

    {
        char buf[OPENAT_BUFFER_SIZE];
        char *proc_file = openat_proc_name (buf, fd, file);
        if (proc_file)
        {
            int open_result = open (proc_file, flags, mode);
            int open_errno = errno;
            if (proc_file != buf)
                free (proc_file);
            /* If the syscall succeeds, or if it fails with an unexpected
               errno value, then return right away.  Otherwise, fall through
               and resort to using save_cwd/restore_cwd.  */
            if (0 <= open_result || ! EXPECTED_ERRNO (open_errno))
            {
                errno = open_errno;
                return open_result;
            }
        }
    }

    save_ok = (save_cwd (&saved_cwd) == 0);
    if (! save_ok)
    {
        if (! cwd_errno)
            openat_save_fail (errno);
        *cwd_errno = errno;
    }
    if (0 <= fd && fd == saved_cwd.desc)
    {
        /* If saving the working directory collides with the user's
           requested fd, then the user's fd must have been closed to
           begin with.  */
        free_cwd (&saved_cwd);
        errno = EBADF;
        return -1;
    }

    err = fchdir (fd);
    saved_errno = errno;

    if (! err)
    {
        err = open (file, flags, mode);
        saved_errno = errno;
        if (save_ok && restore_cwd (&saved_cwd) != 0)
        {
            if (! cwd_errno)
            {
                /* Don't write a message to just-created fd 2.  */
                saved_errno = errno;
                if (err == STDERR_FILENO)
                    close (err);
                openat_restore_fail (saved_errno);
            }
            *cwd_errno = errno;
        }
    }

    free_cwd (&saved_cwd);
    errno = saved_errno;
    return err;
}
示例#12
0
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;
  size_t prefix_len;

  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 = 8192;
#endif

  if (resolved == NULL)
    {
      rpath = malloc (path_max);
      if (rpath == NULL)
        {
          /* It's easier to set errno to ENOMEM than to rely on the
             'malloc-posix' gnulib module.  */
          errno = ENOMEM;
          return NULL;
        }
    }
  else
    rpath = resolved;
  rpath_limit = rpath + path_max;

  /* This is always zero for Posix hosts, but can be 2 for MS-Windows
     and MS-DOS X:/foo/bar file names.  */
  prefix_len = FILE_SYSTEM_PREFIX_LEN (name);

  if (!IS_ABSOLUTE_FILE_NAME (name))
    {
      if (!__getcwd (rpath, path_max))
        {
          rpath[0] = '\0';
          goto error;
        }
      dest = strchr (rpath, '\0');
      start = name;
      prefix_len = FILE_SYSTEM_PREFIX_LEN (rpath);
    }
  else
    {
      dest = rpath;
      if (prefix_len)
        {
          memcpy (rpath, name, prefix_len);
          dest += prefix_len;
        }
      *dest++ = '/';
      if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
        {
          if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len)
            *dest++ = '/';
          *dest = '\0';
        }
      start = name + prefix_len;
    }

  for (end = start; *start; start = end)
    {
#ifdef _LIBC
      struct stat64 st;
#else
      struct stat st;
#endif
      int n;

      /* Skip sequence of multiple path-separators.  */
      while (ISSLASH (*start))
        ++start;

      /* Find end of path component.  */
      for (end = start; *end && !ISSLASH (*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 + prefix_len + 1)
            for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest)
              continue;
          if (DOUBLE_SLASH_IS_DISTINCT_ROOT
              && dest == rpath + 1 && !prefix_len
              && ISSLASH (*dest) && !ISSLASH (dest[1]))
            dest++;
        }
      else
        {
          size_t new_size;

          if (!ISSLASH (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 + prefix_len + 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)
                {
                  /* It's easier to set errno to ENOMEM than to rely on the
                     'realloc-posix' gnulib module.  */
                  errno = ENOMEM;
                  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;

          if (S_ISLNK (st.st_mode))
            {
              char *buf;
              size_t len;

              if (++num_links > MAXSYMLINKS)
                {
                  __set_errno (ELOOP);
                  goto error;
                }

              buf = malloca (path_max);
              if (!buf)
                {
                  errno = ENOMEM;
                  goto error;
                }

              n = __readlink (rpath, buf, path_max - 1);
              if (n < 0)
                {
                  int saved_errno = errno;
                  freea (buf);
                  errno = saved_errno;
                  goto error;
                }
              buf[n] = '\0';

              if (!extra_buf)
                {
                  extra_buf = malloca (path_max);
                  if (!extra_buf)
                    {
                      freea (buf);
                      errno = ENOMEM;
                      goto error;
                    }
                }

              len = strlen (end);
              if ((long int) (n + len) >= path_max)
                {
                  freea (buf);
                  __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 (IS_ABSOLUTE_FILE_NAME (buf))
                {
                  size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);

                  if (pfxlen)
                    memcpy (rpath, buf, pfxlen);
                  dest = rpath + pfxlen;
                  *dest++ = '/'; /* It's an absolute symlink */
                  if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
                    {
                      if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
                        *dest++ = '/';
                      *dest = '\0';
                    }
                  /* Install the new prefix to be in effect hereafter.  */
                  prefix_len = pfxlen;
                }
              else
                {
                  /* Back up to previous component, ignore if at root
                     already: */
                  if (dest > rpath + prefix_len + 1)
                    for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest)
                      continue;
                  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1
                      && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
                    dest++;
                }
            }
          else if (!S_ISDIR (st.st_mode) && *end != '\0')
            {
              __set_errno (ENOTDIR);
              goto error;
            }
        }
    }
  if (dest > rpath + prefix_len + 1 && ISSLASH (dest[-1]))
    --dest;
  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && !prefix_len
      && ISSLASH (*dest) && !ISSLASH (dest[1]))
    dest++;
  *dest = '\0';

  if (extra_buf)
    freea (extra_buf);

  return rpath;

error:
  {
    int saved_errno = errno;
    if (extra_buf)
      freea (extra_buf);
    if (resolved == NULL)
      free (rpath);
    errno = saved_errno;
  }
  return NULL;
}
示例#13
0
static int
linkat_follow (int fd1, char const *file1, int fd2, char const *file2)
{
  char *name = (char *) file1;
  char *target;
  int result;
  int i = MAXSYMLINKS;

  /* There is no realpathat.  */
  while (i-- && (target = areadlinkat (fd1, name)))
    {
      if (IS_ABSOLUTE_FILE_NAME (target))
        {
          if (name != file1)
            free (name);
          name = target;
        }
      else
        {
          char *dir = mdir_name (name);
          if (name != file1)
            free (name);
          if (!dir)
            {
              free (target);
              errno = ENOMEM;
              return -1;
            }
          name = mfile_name_concat (dir, target, NULL);
          free (dir);
          free (target);
          if (!name)
            {
              errno = ENOMEM;
              return -1;
            }
        }
    }
  if (i < 0)
    {
      target = NULL;
      errno = ELOOP;
    }
  if (!target && errno != EINVAL)
    {
      if (name != file1)
        {
          int saved_errno = errno;
          free (name);
          errno = saved_errno;
        }
      return -1;
    }
  result = linkat (fd1, name, fd2, file2, 0);
  if (name != file1)
    {
      int saved_errno = errno;
      free (name);
      errno = saved_errno;
    }
  return result;
}
示例#14
0
static int
link_follow (char const *file1, char const *file2)
{
  char *name = (char *) file1;
  char *target;
  int result;
  int i = MAXSYMLINKS;

  /* Using realpath or canonicalize_file_name is too heavy-handed: we
     don't need an absolute name, and we don't need to resolve
     intermediate symlinks, just the basename of each iteration.  */
  while (i-- && (target = areadlink (name)))
    {
      if (IS_ABSOLUTE_FILE_NAME (target))
        {
          if (name != file1)
            free (name);
          name = target;
        }
      else
        {
          char *dir = mdir_name (name);
          if (name != file1)
            free (name);
          if (!dir)
            {
              free (target);
              errno = ENOMEM;
              return -1;
            }
          name = mfile_name_concat (dir, target, NULL);
          free (dir);
          free (target);
          if (!name)
            {
              errno = ENOMEM;
              return -1;
            }
        }
    }
  if (i < 0)
    {
      target = NULL;
      errno = ELOOP;
    }
  if (!target && errno != EINVAL)
    {
      if (name != file1)
        {
          int saved_errno = errno;
          free (name);
          errno = saved_errno;
        }
      return -1;
    }
  result = link (name, file2);
  if (name != file1)
    {
      int saved_errno = errno;
      free (name);
      errno = saved_errno;
    }
  return result;
}
示例#15
0
bool
make_dir_parents (char *dir,
                  struct savewd *wd,
                  int (*make_ancestor) (char const *, char const *, void *),
                  void *options,
                  mode_t mode,
                  void (*announce) (char const *, void *),
                  mode_t mode_bits,
                  uid_t owner,
                  gid_t group,
                  bool preserve_existing)
{
  int mkdir_errno = (IS_ABSOLUTE_FILE_NAME (dir) ? 0 : savewd_errno (wd));

  if (mkdir_errno == 0)
    {
      ptrdiff_t prefix_len = 0;
      int savewd_chdir_options = (HAVE_FCHMOD ? SAVEWD_CHDIR_SKIP_READABLE : 0);

      if (make_ancestor)
        {
          prefix_len = mkancesdirs (dir, wd, make_ancestor, options);
          if (prefix_len < 0)
            {
              if (prefix_len < -1)
                return true;
              mkdir_errno = errno;
            }
        }

      if (0 <= prefix_len)
        {
          /* If the ownership might change, or if the directory will be
             writable to other users and its special mode bits may
             change after the directory is created, create it with
             more restrictive permissions at first, so unauthorized
             users cannot nip in before the directory is ready.  */
          bool keep_owner = owner == (uid_t) -1 && group == (gid_t) -1;
          bool keep_special_mode_bits =
            ((mode_bits & (S_ISUID | S_ISGID)) | (mode & S_ISVTX)) == 0;
          mode_t mkdir_mode = mode;
          if (! keep_owner)
            mkdir_mode &= ~ (S_IRWXG | S_IRWXO);
          else if (! keep_special_mode_bits)
            mkdir_mode &= ~ (S_IWGRP | S_IWOTH);

          if (mkdir (dir + prefix_len, mkdir_mode) == 0)
            {
              /* True if the caller does not care about the umask's
                 effect on the permissions.  */
              bool umask_must_be_ok = (mode & mode_bits & S_IRWXUGO) == 0;

              announce (dir, options);
              preserve_existing = (keep_owner & keep_special_mode_bits
                                   & umask_must_be_ok);
              savewd_chdir_options |=
                (SAVEWD_CHDIR_NOFOLLOW
                 | (mode & S_IRUSR ? SAVEWD_CHDIR_READABLE : 0));
            }
          else
            {
              mkdir_errno = errno;
              mkdir_mode = -1;
            }

          if (preserve_existing)
            {
              struct stat st;
              if (mkdir_errno == 0
                  || (mkdir_errno != ENOENT && make_ancestor
                      && stat (dir + prefix_len, &st) == 0
                      && S_ISDIR (st.st_mode)))
                return true;
            }
          else
            {
              int open_result[2];
              int chdir_result =
                savewd_chdir (wd, dir + prefix_len,
                              savewd_chdir_options, open_result);
              if (chdir_result < -1)
                return true;
              else
                {
                  bool chdir_ok = (chdir_result == 0);
                  char const *subdir = (chdir_ok ? "." : dir + prefix_len);
                  if (dirchownmod (open_result[0], subdir, mkdir_mode,
                                   owner, group, mode, mode_bits)
                      == 0)
                    return true;

                  if (mkdir_errno == 0
                      || (mkdir_errno != ENOENT && make_ancestor
                          && errno != ENOTDIR))
                    {
                      error (0, errno,
                             _(keep_owner
                               ? "cannot change permissions of %s"
                               : "cannot change owner and permissions of %s"),
                             quote (dir));
                      return false;
                    }
                }
            }
        }
    }

  error (0, mkdir_errno, _("cannot create directory %s"), quote (dir));
  return false;
}
示例#16
0
文件: path.c 项目: Distrotech/m4
/* Search for FILENAME according to -B options, `.', -I options, then
   M4PATH environment.  If successful, return the open file, and if
   RESULT is not NULL, set *RESULT to a malloc'd string that
   represents the file found with respect to the current working
   directory.  Otherwise, return NULL, and errno reflects the failure
   from searching `.' (regardless of what else was searched).  */
char *
m4_path_search (m4 *context, const char *filename, const char **suffixes)
{
  m4__search_path *incl;
  char *filepath;		/* buffer for constructed name */
  size_t max_suffix_len = 0;
  int i, e = 0;

  /* Reject empty file.  */
  if (*filename == '\0')
    {
      errno = ENOENT;
      return NULL;
    }

  /* Use no suffixes by default.  */
  if (suffixes == NULL)
    suffixes = NO_SUFFIXES;

  /* Find the longest suffix, so that we will always allocate enough
     memory for a filename with suffix.  */
  for (i = 0; suffixes && suffixes[i]; ++i)
    {
      size_t len = strlen (suffixes[i]);
      if (len > max_suffix_len)
        max_suffix_len = len;
    }

  /* If file is absolute, or if we are not searching a path, a single
     lookup will do the trick.  */
  if (IS_ABSOLUTE_FILE_NAME (filename))
    {
      size_t mem = strlen (filename);

      /* Try appending each of the suffixes we were given.  */
      filepath = strncpy (xmalloc (mem + max_suffix_len +1), filename, mem +1);
#if TRUNCATE_FILENAME
      filepath = path_truncate (filepath);
      mem = strlen (filepath); /* recalculate length after truncation */
#endif
      for (i = 0; suffixes && suffixes[i]; ++i)
        {
          strcpy (filepath + mem, suffixes[i]);
          if (access (filepath, R_OK) == 0)
	    return filepath;

          /* If search fails, we'll use the error we got from the first
	     access (usually with no suffix).  */
	  if (i == 0)
	    e = errno;
        }
      free (filepath);

      /* No such file.  */
      errno = e;
      return NULL;
    }

  for (incl = m4__get_search_path (context)->list;
       incl != NULL; incl = incl->next)
    {
      char *pathname = file_name_concat (incl->dir, filename, NULL);
      size_t mem = strlen (pathname);

#ifdef DEBUG_INCL
      xfprintf (stderr, "path_search (%s) -- trying %s\n", filename, pathname);
#endif

      if (access (pathname, R_OK) == 0)
        {
          m4_debug_message (context, M4_DEBUG_TRACE_PATH,
                            _("path search for %s found %s"),
                            quotearg_style (locale_quoting_style, filename),
                            quotearg_n_style (1, locale_quoting_style, pathname));
          return pathname;
        }
      else if (!incl->len)
	/* Capture errno only when searching `.'.  */
	e = errno;

      filepath = strncpy (xmalloc (mem + max_suffix_len +1), pathname, mem +1);
      free (pathname);
#if TRUNCATE_FILENAME
      filepath = path_truncate (filepath);
      mem = strlen (filepath); /* recalculate length after truncation */
#endif
 
      for (i = 0; suffixes && suffixes[i]; ++i)
        {
          strcpy (filepath + mem, suffixes[i]);
          if (access (filepath, R_OK) == 0)
            return filepath;
        }
      free (filepath);
    }

  errno = e;
  return NULL;
}
示例#17
0
/* Call FUNC to operate on a pair of files, where FILE1 is relative to FD1,
   and FILE2 is relative to FD2.  If possible, do it without changing the
   working directory.  Otherwise, resort to using save_cwd/fchdir,
   FUNC, restore_cwd (up to two times).  If either the save_cwd or the
   restore_cwd fails, then give a diagnostic and exit nonzero.  */
int
at_func2 (int fd1, char const *file1,
          int fd2, char const *file2,
          int (*func) (char const *file1, char const *file2))
{
  struct saved_cwd saved_cwd;
  int saved_errno;
  int err;
  char *file1_alt;
  char *file2_alt;
  struct stat st1;
  struct stat st2;

  /* There are 16 possible scenarios, based on whether an fd is
     AT_FDCWD or real, and whether a file is absolute or relative:

         fd1  file1 fd2  file2  action
     0   cwd  abs   cwd  abs    direct call
     1   cwd  abs   cwd  rel    direct call
     2   cwd  abs   fd   abs    direct call
     3   cwd  abs   fd   rel    chdir to fd2
     4   cwd  rel   cwd  abs    direct call
     5   cwd  rel   cwd  rel    direct call
     6   cwd  rel   fd   abs    direct call
     7   cwd  rel   fd   rel    convert file1 to abs, then case 3
     8   fd   abs   cwd  abs    direct call
     9   fd   abs   cwd  rel    direct call
     10  fd   abs   fd   abs    direct call
     11  fd   abs   fd   rel    chdir to fd2
     12  fd   rel   cwd  abs    chdir to fd1
     13  fd   rel   cwd  rel    convert file2 to abs, then case 12
     14  fd   rel   fd   abs    chdir to fd1
     15a fd1  rel   fd1  rel    chdir to fd1
     15b fd1  rel   fd2  rel    chdir to fd1, then case 7

     Try some optimizations to reduce fd to AT_FDCWD, or to at least
     avoid converting an absolute name or doing a double chdir.  */

  if ((fd1 == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file1))
      && (fd2 == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file2)))
    return func (file1, file2); /* Case 0-2, 4-6, 8-10.  */

  /* If /proc/self/fd works, we don't need any stat or chdir.  */
  {
    char proc_buf1[OPENAT_BUFFER_SIZE];
    char *proc_file1 = ((fd1 == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file1))
                        ? (char *) file1
                        : openat_proc_name (proc_buf1, fd1, file1));
    if (proc_file1)
      {
        char proc_buf2[OPENAT_BUFFER_SIZE];
        char *proc_file2 = ((fd2 == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file2))
                            ? (char *) file2
                            : openat_proc_name (proc_buf2, fd2, file2));
        if (proc_file2)
          {
            int proc_result = func (proc_file1, proc_file2);
            int proc_errno = errno;
            if (proc_file1 != proc_buf1 && proc_file1 != file1)
              free (proc_file1);
            if (proc_file2 != proc_buf2 && proc_file2 != file2)
              free (proc_file2);
            /* If the syscall succeeds, or if it fails with an unexpected
               errno value, then return right away.  Otherwise, fall through
               and resort to using save_cwd/restore_cwd.  */
            if (0 <= proc_result)
              return proc_result;
            if (! EXPECTED_ERRNO (proc_errno))
              {
                errno = proc_errno;
                return proc_result;
              }
          }
        else if (proc_file1 != proc_buf1 && proc_file1 != file1)
          free (proc_file1);
      }
  }

  /* Cases 3, 7, 11-15 remain.  Time to normalize directory fds, if
     possible.  */
  if (IS_ABSOLUTE_FILE_NAME (file1))
    fd1 = AT_FDCWD; /* Case 11 reduced to 3.  */
  else if (IS_ABSOLUTE_FILE_NAME (file2))
    fd2 = AT_FDCWD; /* Case 14 reduced to 12.  */

  /* Cases 3, 7, 12, 13, 15 remain.  */

  if (fd1 == AT_FDCWD) /* Cases 3, 7.  */
    {
      if (stat (".", &st1) == -1 || fstat (fd2, &st2) == -1)
        return -1;
      if (!S_ISDIR (st2.st_mode))
        {
          errno = ENOTDIR;
          return -1;
        }
      if (SAME_INODE (st1, st2)) /* Reduced to cases 1, 5.  */
        return func (file1, file2);
    }
  else if (fd2 == AT_FDCWD) /* Cases 12, 13.  */
    {
      if (stat (".", &st2) == -1 || fstat (fd1, &st1) == -1)
        return -1;
      if (!S_ISDIR (st1.st_mode))
        {
          errno = ENOTDIR;
          return -1;
        }
      if (SAME_INODE (st1, st2)) /* Reduced to cases 4, 5.  */
        return func (file1, file2);
    }
  else if (fd1 != fd2) /* Case 15b.  */
    {
      if (fstat (fd1, &st1) == -1 || fstat (fd2, &st2) == -1)
        return -1;
      if (!S_ISDIR (st1.st_mode) || !S_ISDIR (st2.st_mode))
        {
          errno = ENOTDIR;
          return -1;
        }
      if (SAME_INODE (st1, st2)) /* Reduced to case 15a.  */
        {
          fd2 = fd1;
          if (stat (".", &st1) == 0 && SAME_INODE (st1, st2))
            return func (file1, file2); /* Further reduced to case 5.  */
        }
    }
  else /* Case 15a.  */
    {
      if (fstat (fd1, &st1) == -1)
        return -1;
      if (!S_ISDIR (st1.st_mode))
        {
          errno = ENOTDIR;
          return -1;
        }
      if (stat (".", &st2) == 0 && SAME_INODE (st1, st2))
        return func (file1, file2); /* Reduced to case 5.  */
    }

  /* Cases 3, 7, 12, 13, 15a, 15b remain.  With all reductions in
     place, it is time to start changing directories.  */

  if (save_cwd (&saved_cwd) != 0)
    openat_save_fail (errno);

  if (fd1 != AT_FDCWD && fd2 != AT_FDCWD && fd1 != fd2) /* Case 15b.  */
    {
      if (fchdir (fd1) != 0)
        {
          saved_errno = errno;
          free_cwd (&saved_cwd);
          errno = saved_errno;
          return -1;
        }
      fd1 = AT_FDCWD; /* Reduced to case 7.  */
    }

  /* Cases 3, 7, 12, 13, 15a remain.  Convert one relative name to
     absolute, if necessary.  */

  file1_alt = (char *) file1;
  file2_alt = (char *) file2;

  if (fd1 == AT_FDCWD && !IS_ABSOLUTE_FILE_NAME (file1)) /* Case 7.  */
    {
      /* It would be nicer to use:
         file1_alt = file_name_concat (xgetcwd (), file1, NULL);
         but libraries should not call xalloc_die.  */
      char *cwd = getcwd (NULL, 0);
      if (!cwd)
        {
          saved_errno = errno;
          free_cwd (&saved_cwd);
          errno = saved_errno;
          return -1;
        }
      file1_alt = mfile_name_concat (cwd, file1, NULL);
      if (!file1_alt)
        {
          saved_errno = errno;
          free (cwd);
          free_cwd (&saved_cwd);
          errno = saved_errno;
          return -1;
        }
      free (cwd); /* Reduced to case 3.  */
    }
  else if (fd2 == AT_FDCWD && !IS_ABSOLUTE_FILE_NAME (file2)) /* Case 13.  */
    {
      char *cwd = getcwd (NULL, 0);
      if (!cwd)
        {
          saved_errno = errno;
          free_cwd (&saved_cwd);
          errno = saved_errno;
          return -1;
        }
      file2_alt = mfile_name_concat (cwd, file2, NULL);
      if (!file2_alt)
        {
          saved_errno = errno;
          free (cwd);
          free_cwd (&saved_cwd);
          errno = saved_errno;
          return -1;
        }
      free (cwd); /* Reduced to case 12.  */
    }

  /* Cases 3, 12, 15a remain.  Change to the correct directory.  */
  if (fchdir (fd1 == AT_FDCWD ? fd2 : fd1) != 0)
    {
      saved_errno = errno;
      free_cwd (&saved_cwd);
      if (file1 != file1_alt)
        free (file1_alt);
      else if (file2 != file2_alt)
        free (file2_alt);
      errno = saved_errno;
      return -1;
    }

  /* Finally safe to perform the user's function, then clean up.  */

  err = func (file1_alt, file2_alt);
  saved_errno = (err < 0 ? errno : 0);

  if (file1 != file1_alt)
    free (file1_alt);
  else if (file2 != file2_alt)
    free (file2_alt);

  if (restore_cwd (&saved_cwd) != 0)
    openat_restore_fail (errno);

  free_cwd (&saved_cwd);

  if (saved_errno)
    errno = saved_errno;
  return err;
}
示例#18
0
/* Return the canonical absolute name of file NAME, while treating
 * missing elements according to CAN_MODE.  A canonical name
 * does not contain any ".", ".." components nor any repeated file name
 * separators ('/') or, depending on other CAN_MODE flags, symlinks.
 * Whether components must exist or not depends on canonicalize mode.
 * The result is malloc'd.
 */
static char *_exechelp_canonicalize_filename_mode (const char *name, _exechelp_canonicalize_mode_t can_mode)
{
  char *rname, *dest, *extra_buf = NULL;
  char const *start;
  char const *end;
  char const *rname_limit;
  size_t extra_len = 0;
  ExecHelpHashTable *h = NULL;
  int saved_errno;
  int can_flags = can_mode & ~CAN_MODE_MASK;
  int logical = can_flags & CAN_NOLINKS;

  can_mode &= CAN_MODE_MASK;

  if (MULTIPLE_BITS_SET (can_mode))
  {
    errno = EINVAL;
    return NULL;
  }

  if (name == NULL)
  {
    errno = EINVAL;
    return NULL;
  }

  if (name[0] == '\0')
  {
    errno = ENOENT;
    return NULL;
  }

  if (!IS_ABSOLUTE_FILE_NAME (name))
  {
    if(name[0] == '~')
    {
      if (!ISSLASH(name[1]))
      {
        errno = EINVAL;
        return NULL;
      }
      
      rname = getenv ("HOME");
      if (!rname)
        return NULL;
      else
        rname = strdup(rname);
      if (!rname)
        return NULL;
      dest = strchr (rname, '\0');
      if (dest - rname < PATH_MAX)
      {
        char *p = realloc (rname, PATH_MAX);
        dest = p + (dest - rname);
        rname = p;
        rname_limit = rname + PATH_MAX;
      }
      else
      {
        rname_limit = dest;
      }
      start = name + 2; // '~/'
    }
    else
    {
      rname = getcwd (NULL, 0);
      if (!rname)
        return NULL;
      dest = strchr (rname, '\0');
      if (dest - rname < PATH_MAX)
      {
        char *p = realloc (rname, PATH_MAX);
        dest = p + (dest - rname);
        rname = p;
        rname_limit = rname + PATH_MAX;
      }
      else
      {
        rname_limit = dest;
      }
      start = name;
    }
  }
  else
  {
    rname = malloc (PATH_MAX);
    rname_limit = rname + PATH_MAX;
    dest = rname;
    *dest++ = '/';
    start = name;
  }

  for ( ; *start; start = end)
  {
    /* Skip sequence of multiple file name separators.  */
    while (ISSLASH (*start))
      ++start;

    /* Find end of component.  */
    for (end = start; *end && !ISSLASH (*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 > rname + 1)
        for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
          continue;
    }
    else
    {
      struct stat st;

      if (!ISSLASH (dest[-1]))
        *dest++ = '/';

      if (dest + (end - start) >= rname_limit)
      {
        size_t dest_offset = dest - rname;
        size_t new_size = rname_limit - rname;

        if (end - start + 1 > PATH_MAX)
          new_size += end - start + 1;
        else
          new_size += PATH_MAX;
        rname = realloc (rname, new_size);
        rname_limit = rname + new_size;

        dest = rname + dest_offset;
      }

      dest = memcpy (dest, start, end - start);
      dest += end - start;
      *dest = '\0';

      if (logical && (can_mode == CAN_MISSING))
      {
        /* Avoid the stat in this case as it's inconsequential.
         * i.e. we're neither resolving symlinks or testing
         * component existence.
         */
        st.st_mode = 0;
      }
      else if ((logical ? stat (rname, &st) : lstat (rname, &st)) != 0)
      {
        saved_errno = errno;
        if (can_mode == CAN_EXISTING)
          goto error;
        if (can_mode == CAN_ALL_BUT_LAST)
        {
          if (end[strspn (end, "/")] || saved_errno != ENOENT)
            goto error;
          continue;
        }
        st.st_mode = 0;
      }

      if (S_ISLNK (st.st_mode))
      {
        char *buf;
        size_t n, len;

        /* Detect loops.  We cannot use the cycle-check module here,
         * since it's actually possible to encounter the same symlink
         * more than once in a given traversal.  However, encountering
         * the same symlink,NAME pair twice does indicate a loop.
         */
        if (_exechelp_seen_triple (&h, name, &st))
        {
          if (can_mode == CAN_MISSING)
            continue;
          saved_errno = ELOOP;
          goto error;
        }

        buf = exechelp_coreutils_areadlink_with_size (rname, st.st_size);
        if (!buf)
        {
          if (can_mode == CAN_MISSING && errno != ENOMEM)
            continue;
          saved_errno = errno;
          goto error;
        }

        n = strlen (buf);
        len = strlen (end);

        if (!extra_len)
        {
          extra_len =
            ((n + len + 1) > PATH_MAX) ? (n + len + 1) : PATH_MAX;
          extra_buf = malloc (extra_len);
        }
        else if ((n + len + 1) > extra_len)
        {
          extra_len = n + len + 1;
          extra_buf = realloc (extra_buf, extra_len);
        }

        /* 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 (IS_ABSOLUTE_FILE_NAME (buf))
        {
          dest = rname;
          *dest++ = '/'; /* It's an absolute symlink */
        }
        else
        {
          /* Back up to previous component, ignore if at root already: */
          if (dest > rname + 1)
            for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
              continue;
        }

        free (buf);
      }
      else
      {
        if (!S_ISDIR (st.st_mode) && *end && (can_mode != CAN_MISSING))
        {
          saved_errno = ENOTDIR;
          goto error;
        }
      }
    }
  }
  if (dest > rname + 1 && ISSLASH (dest[-1]))
    --dest;
  *dest = '\0';
  if (rname_limit != dest + 1)
    rname = realloc (rname, dest - rname + 1);

  free (extra_buf);
  if (h)
    exechelp_hash_table_destroy (h);
  return rname;

  error:
  free (extra_buf);
  free (rname);
  if (h)
    exechelp_hash_table_destroy (h);
  errno = saved_errno;
  return NULL;
}
示例#19
0
char *
canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
{
  char *rname, *dest, *extra_buf = NULL;
  char const *start;
  char const *end;
  char const *rname_limit;
  size_t extra_len = 0;
  Hash_table *ht = NULL;
  int saved_errno;
  int can_flags = can_mode & ~CAN_MODE_MASK;
  bool logical = can_flags & CAN_NOLINKS;
  size_t prefix_len;

  can_mode &= CAN_MODE_MASK;

  if (MULTIPLE_BITS_SET (can_mode))
    {
      errno = EINVAL;
      return NULL;
    }

  if (name == NULL)
    {
      errno = EINVAL;
      return NULL;
    }

  if (name[0] == '\0')
    {
      errno = ENOENT;
      return NULL;
    }

  /* This is always zero for Posix hosts, but can be 2 for MS-Windows
     and MS-DOS X:/foo/bar file names.  */
  prefix_len = FILE_SYSTEM_PREFIX_LEN (name);

  if (!IS_ABSOLUTE_FILE_NAME (name))
    {
      rname = xgetcwd ();
      if (!rname)
        return NULL;
      dest = strchr (rname, '\0');
      if (dest - rname < PATH_MAX)
        {
          char *p = xrealloc (rname, PATH_MAX);
          dest = p + (dest - rname);
          rname = p;
          rname_limit = rname + PATH_MAX;
        }
      else
        {
          rname_limit = dest;
        }
      start = name;
      prefix_len = FILE_SYSTEM_PREFIX_LEN (rname);
    }
  else
    {
      rname = xmalloc (PATH_MAX);
      rname_limit = rname + PATH_MAX;
      dest = rname;
      if (prefix_len)
        {
          memcpy (rname, name, prefix_len);
          dest += prefix_len;
        }
      *dest++ = '/';
      if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
        {
          if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len)
            *dest++ = '/';
          *dest = '\0';
        }
      start = name + prefix_len;
    }

  for ( ; *start; start = end)
    {
      /* Skip sequence of multiple file name separators.  */
      while (ISSLASH (*start))
        ++start;

      /* Find end of component.  */
      for (end = start; *end && !ISSLASH (*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 > rname + prefix_len + 1)
            for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
              continue;
          if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
              && !prefix_len && ISSLASH (*dest) && !ISSLASH (dest[1]))
            dest++;
        }
      else
        {
          struct stat st;

          if (!ISSLASH (dest[-1]))
            *dest++ = '/';

          if (dest + (end - start) >= rname_limit)
            {
              ptrdiff_t dest_offset = dest - rname;
              size_t new_size = rname_limit - rname;

              if (end - start + 1 > PATH_MAX)
                new_size += end - start + 1;
              else
                new_size += PATH_MAX;
              rname = xrealloc (rname, new_size);
              rname_limit = rname + new_size;

              dest = rname + dest_offset;
            }

          dest = memcpy (dest, start, end - start);
          dest += end - start;
          *dest = '\0';

          if (logical && (can_mode == CAN_MISSING))
            {
              /* Avoid the stat in this case as it's inconsequential.
                 i.e. we're neither resolving symlinks or testing
                 component existence.  */
              st.st_mode = 0;
            }
          else if ((logical ? stat (rname, &st) : lstat (rname, &st)) != 0)
            {
              saved_errno = errno;
              if (can_mode == CAN_EXISTING)
                goto error;
              if (can_mode == CAN_ALL_BUT_LAST)
                {
                  if (end[strspn (end, SLASHES)] || saved_errno != ENOENT)
                    goto error;
                  continue;
                }
              st.st_mode = 0;
            }

          if (S_ISLNK (st.st_mode))
            {
              char *buf;
              size_t n, len;

              /* Detect loops.  We cannot use the cycle-check module here,
                 since it's actually possible to encounter the same symlink
                 more than once in a given traversal.  However, encountering
                 the same symlink,NAME pair twice does indicate a loop.  */
              if (seen_triple (&ht, name, &st))
                {
                  if (can_mode == CAN_MISSING)
                    continue;
                  saved_errno = ELOOP;
                  goto error;
                }

              buf = areadlink_with_size (rname, st.st_size);
              if (!buf)
                {
                  if (can_mode == CAN_MISSING && errno != ENOMEM)
                    continue;
                  saved_errno = errno;
                  goto error;
                }

              n = strlen (buf);
              len = strlen (end);

              if (!extra_len)
                {
                  extra_len =
                    ((n + len + 1) > PATH_MAX) ? (n + len + 1) : PATH_MAX;
                  extra_buf = xmalloc (extra_len);
                }
              else if ((n + len + 1) > extra_len)
                {
                  extra_len = n + len + 1;
                  extra_buf = xrealloc (extra_buf, extra_len);
                }

              /* 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 (IS_ABSOLUTE_FILE_NAME (buf))
                {
                  size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);

                  if (pfxlen)
                    memcpy (rname, buf, pfxlen);
                  dest = rname + pfxlen;
                  *dest++ = '/'; /* It's an absolute symlink */
                  if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
                    {
                      if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
                        *dest++ = '/';
                      *dest = '\0';
                    }
                  /* Install the new prefix to be in effect hereafter.  */
                  prefix_len = pfxlen;
                }
              else
                {
                  /* Back up to previous component, ignore if at root
                     already: */
                  if (dest > rname + prefix_len + 1)
                    for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
                      continue;
                  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
                      && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
                    dest++;
                }

              free (buf);
            }
          else
            {
              if (!S_ISDIR (st.st_mode) && *end && (can_mode != CAN_MISSING))
                {
                  saved_errno = ENOTDIR;
                  goto error;
                }
            }
        }
    }
  if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1]))
    --dest;
  if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && !prefix_len
      && ISSLASH (*dest) && !ISSLASH (dest[1]))
    dest++;
  *dest = '\0';
  if (rname_limit != dest + 1)
    rname = xrealloc (rname, dest - rname + 1);

  free (extra_buf);
  if (ht)
    hash_free (ht);
  return rname;

error:
  free (extra_buf);
  free (rname);
  if (ht)
    hash_free (ht);
  errno = saved_errno;
  return NULL;
}
示例#20
0
/* Returns true iff NAME specifies an absolute file name. */
bool
fn_is_absolute (const char *name)
{
  return IS_ABSOLUTE_FILE_NAME (name);
}
示例#21
0
int
main (void)
{
  struct test *t;
  bool ok = true;

  for (t = tests; t->name; t++)
    {
      char *dir = dir_name (t->name);
      int dirlen = dir_len (t->name);
      char *last = last_component (t->name);
      char *base = base_name (t->name);
      int baselen = base_len (base);
      char *stripped = strdup (t->name);
      bool modified = strip_trailing_slashes (stripped);
      bool absolute = IS_ABSOLUTE_FILE_NAME (t->name);
      if (! (strcmp (dir, t->dir) == 0
             && (dirlen == strlen (dir)
                 || (dirlen + 1 == strlen (dir) && dir[dirlen] == '.'))))
        {
          ok = false;
          printf ("dir_name '%s': got '%s' len %d,"
                  " expected '%s' len %ld\n",
                  t->name, dir, dirlen,
                  t->dir, (unsigned long) strlen (t->dir));
        }
      if (strcmp (last, t->last))
        {
          ok = false;
          printf ("last_component '%s': got '%s', expected '%s'\n",
                  t->name, last, t->last);
        }
      if (! (strcmp (base, t->base) == 0
             && (baselen == strlen (base)
                 || (baselen + 1 == strlen (base)
                     && ISSLASH (base[baselen])))))
        {
          ok = false;
          printf ("base_name '%s': got '%s' len %d,"
                  " expected '%s' len %ld\n",
                  t->name, base, baselen,
                  t->base, (unsigned long) strlen (t->base));
        }
      if (strcmp (stripped, t->stripped) || modified != t->modified)
        {
          ok = false;
          printf ("strip_trailing_slashes '%s': got %s %s, expected %s %s\n",
                  t->name, stripped, modified ? "changed" : "unchanged",
                  t->stripped, t->modified ? "changed" : "unchanged");
        }
      if (t->absolute != absolute)
        {
          ok = false;
          printf ("'%s': got %s, expected %s\n", t->name,
                  absolute ? "absolute" : "relative",
                  t->absolute ? "absolute" : "relative");
        }
      free (dir);
      free (base);
      free (stripped);
    }
  return ok ? 0 : 1;
}