Пример #1
0
int stat(const char *file_name, struct stat *buf)
{
	return fstatat(AT_FDCWD, file_name, buf, 0);
}
Пример #2
0
/* Recursively scan the directory identified by ST.  */
struct directory *
scan_directory (struct tar_stat_info *st)
{
  char const *dir = st->orig_file_name;
  char *dirp = get_directory_entries (st);
  dev_t device = st->stat.st_dev;
  bool cmdline = ! st->parent;
  namebuf_t nbuf;
  char *tmp;
  struct directory *directory;
  char ch;

  if (! dirp)
    savedir_error (dir);

  info_attach_exclist (st);

  tmp = xstrdup (dir);
  zap_slashes (tmp);

  directory = procdir (tmp, st,
		       (cmdline ? PD_FORCE_INIT : 0),
		       &ch);

  free (tmp);

  nbuf = namebuf_create (dir);

  if (dirp)
    {
      if (directory->children != NO_CHILDREN)
	{
	  char *entry;	/* directory entry being scanned */
	  struct dumpdir_iter *itr;

	  makedumpdir (directory, dirp);

	  for (entry = dumpdir_first (directory->dump, 1, &itr);
	       entry;
	       entry = dumpdir_next (itr))
	    {
	      char *full_name = namebuf_name (nbuf, entry + 1);

	      if (*entry == 'I') /* Ignored entry */
		*entry = 'N';
	      else if (excluded_name (full_name, st))
		*entry = 'N';
	      else
		{
		  int fd = st->fd;
		  void (*diag) (char const *) = 0;
		  struct tar_stat_info stsub;
		  tar_stat_init (&stsub);

		  if (fd < 0)
		    {
		      errno = - fd;
		      diag = open_diag;
		    }
		  else if (fstatat (fd, entry + 1, &stsub.stat,
				    fstatat_flags) != 0)
		    diag = stat_diag;
		  else if (S_ISDIR (stsub.stat.st_mode))
		    {
		      int subfd = subfile_open (st, entry + 1,
						open_read_flags);
		      if (subfd < 0)
			diag = open_diag;
		      else
			{
			  stsub.fd = subfd;
			  if (fstat (subfd, &stsub.stat) != 0)
			    diag = stat_diag;
			}
		    }

		  if (diag)
		    {
		      file_removed_diag (full_name, false, diag);
		      *entry = 'N';
		    }
		  else if (S_ISDIR (stsub.stat.st_mode))
		    {
		      int pd_flag = 0;
		      if (!recursion_option)
			pd_flag |= PD_FORCE_CHILDREN | NO_CHILDREN;
		      else if (directory->children == ALL_CHILDREN)
			pd_flag |= PD_FORCE_CHILDREN | ALL_CHILDREN;
		      *entry = 'D';

		      stsub.parent = st;
		      procdir (full_name, &stsub, pd_flag, entry);
		      restore_parent_fd (&stsub);
		    }
		  else if (one_file_system_option &&
			   device != stsub.stat.st_dev)
		    *entry = 'N';
		  else if (*entry == 'Y')
		    /* New entry, skip further checks */;
		  /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */
		  else if (OLDER_STAT_TIME (stsub.stat, m)
			   && (!after_date_option
			       || OLDER_STAT_TIME (stsub.stat, c)))
		    *entry = 'N';
		  else
		    *entry = 'Y';

		  tar_stat_destroy (&stsub);
		}
	    }
	  free (itr);
	}
      else if (directory->tagfile)
	maketagdumpdir (directory);
    }

  namebuf_free (nbuf);

  free (dirp);

  return directory;
}
Пример #3
0
int
server_file_index(struct httpd *env, struct client *clt, struct stat *st)
{
	char			  path[PATH_MAX];
	char			  tmstr[21];
	struct http_descriptor	 *desc = clt->clt_descreq;
	struct server_config	 *srv_conf = clt->clt_srv_conf;
	struct dirent		**namelist, *dp;
	int			  namesize, i, ret, fd = -1, namewidth, skip;
	int			  code = 500;
	struct evbuffer		 *evb = NULL;
	struct media_type	 *media;
	const char		 *stripped, *style;
	char			 *escapeduri, *escapedhtml, *escapedpath;
	struct tm		  tm;
	time_t			  t, dir_mtime;

	if ((ret = server_file_method(clt)) != 0) {
		code = ret;
		goto abort;
	}

	/* Request path is already canonicalized */
	stripped = server_root_strip(desc->http_path, srv_conf->strip);
	if ((size_t)snprintf(path, sizeof(path), "%s%s",
	    srv_conf->root, stripped) >= sizeof(path))
		goto abort;

	/* Now open the file, should be readable or we have another problem */
	if ((fd = open(path, O_RDONLY)) == -1)
		goto abort;

	/* Save last modification time */
	dir_mtime = MINIMUM(time(NULL), st->st_mtim.tv_sec);

	if ((evb = evbuffer_new()) == NULL)
		goto abort;

	if ((namesize = scandir(path, &namelist, NULL, alphasort)) == -1)
		goto abort;

	/* Indicate failure but continue going through the list */
	skip = 0;

	if ((escapedpath = escape_html(desc->http_path)) == NULL)
		goto fail;

	/* A CSS stylesheet allows minimal customization by the user */
	style = "body { background-color: white; color: black; font-family: "
	    "sans-serif; }\nhr { border: 0; border-bottom: 1px dashed; }\n";
	/* Generate simple HTML index document */
	if (evbuffer_add_printf(evb,
	    "<!DOCTYPE html>\n"
	    "<html>\n"
	    "<head>\n"
	    "<title>Index of %s</title>\n"
	    "<style type=\"text/css\"><!--\n%s\n--></style>\n"
	    "</head>\n"
	    "<body>\n"
	    "<h1>Index of %s</h1>\n"
	    "<hr>\n<pre>\n",
	    escapedpath, style, escapedpath) == -1)
		skip = 1;

	free(escapedpath);

	for (i = 0; i < namesize; i++) {
		dp = namelist[i];

		if (skip ||
		    fstatat(fd, dp->d_name, st, 0) == -1) {
			free(dp);
			continue;
		}

		t = st->st_mtime;
		localtime_r(&t, &tm);
		strftime(tmstr, sizeof(tmstr), "%d-%h-%Y %R", &tm);
		namewidth = 51 - strlen(dp->d_name);

		if ((escapeduri = url_encode(dp->d_name)) == NULL)
			goto fail;
		if ((escapedhtml = escape_html(dp->d_name)) == NULL)
			goto fail;

		if (dp->d_name[0] == '.' &&
		    !(dp->d_name[1] == '.' && dp->d_name[2] == '\0')) {
			/* ignore hidden files starting with a dot */
		} else if (S_ISDIR(st->st_mode)) {
			namewidth -= 1; /* trailing slash */
			if (evbuffer_add_printf(evb,
			    "<a href=\"%s%s/\">%s/</a>%*s%s%20s\n",
			    strchr(escapeduri, ':') != NULL ? "./" : "",
			    escapeduri, escapedhtml,
			    MAXIMUM(namewidth, 0), " ", tmstr, "-") == -1)
				skip = 1;
		} else if (S_ISREG(st->st_mode)) {
			if (evbuffer_add_printf(evb,
			    "<a href=\"%s%s\">%s</a>%*s%s%20llu\n",
			    strchr(escapeduri, ':') != NULL ? "./" : "",
			    escapeduri, escapedhtml,
			    MAXIMUM(namewidth, 0), " ",
			    tmstr, st->st_size) == -1)
				skip = 1;
		}
		free(escapeduri);
		free(escapedhtml);
		free(dp);
	}
	free(namelist);

	if (skip ||
	    evbuffer_add_printf(evb,
	    "</pre>\n<hr>\n</body>\n</html>\n") == -1)
		goto abort;

	close(fd);
	fd = -1;

	media = media_find_config(env, srv_conf, "index.html");
	ret = server_response_http(clt, 200, media, EVBUFFER_LENGTH(evb),
	    dir_mtime);
	switch (ret) {
	case -1:
		goto fail;
	case 0:
		/* Connection is already finished */
		evbuffer_free(evb);
		goto done;
	default:
		break;
	}

	if (server_bufferevent_write_buffer(clt, evb) == -1)
		goto fail;
	evbuffer_free(evb);
	evb = NULL;

	bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE);
	if (clt->clt_persist)
		clt->clt_toread = TOREAD_HTTP_HEADER;
	else
		clt->clt_toread = TOREAD_HTTP_NONE;
	clt->clt_done = 0;

 done:
	server_reset_http(clt);
	return (0);
 fail:
	bufferevent_disable(clt->clt_bev, EV_READ|EV_WRITE);
	bufferevent_free(clt->clt_bev);
	clt->clt_bev = NULL;
 abort:
	if (fd != -1)
		close(fd);
	if (evb != NULL)
		evbuffer_free(evb);
	server_abort_http(clt, code, desc->http_path);
	return (-1);
}
Пример #4
0
Файл: fs.c Проект: PeteGozz/vdev
// callback to be fed int vdev_load_all_at.
// builds up the children listing of vdevfs_scandirat_context.parent_dir.
// if we find a directory, open it and enqueue its file descriptor to dir_queue.
// return 0 on success
// return -ENOMEM on OOM
static int
vdevfs_scandirat_context_callback (int dirfd, struct dirent *dent, void *cls)
{

  struct vdevfs_scandirat_context *ctx =
    (struct vdevfs_scandirat_context *) cls;

  int rc = 0;
  int fd = 0;
  struct stat sb;
  struct fskit_entry *child;
  char linkbuf[8193];		// for resolving an underlying symlink
  char const *method_name;	// for logging
  char *joined_path = NULL;
  struct vdevfs_scandirat_queue *next = NULL;

  // skip . and ..
  if (strcmp (dent->d_name, ".") == 0 || strcmp (dent->d_name, "..") == 0)
    {
      return 0;
    }
  // learn more...
  rc = fstatat (dirfd, dent->d_name, &sb, AT_SYMLINK_NOFOLLOW);
  if (rc != 0)
    {

      rc = -errno;

      // mask errors; just log the serious ones
      if (rc != -ENOENT && rc != -EACCES)
	{

	  vdev_error ("fstatat(%d, '%s') rc = %d\n", dirfd, dent->d_name, rc);
	}

      return 0;
    }
  // directory?  get an fd to it if so, so we can keep scanning
  if (S_ISDIR (sb.st_mode))
    {

      // try to get at it 
      fd = openat (dirfd, dent->d_name, O_RDONLY);
      if (fd < 0)
	{

	  rc = -errno;

	  // mask errors; just log the serious ones 
	  if (rc != -ENOENT && rc != -EACCES)
	    {

	      vdev_error ("openat(%d, '%s') rc = %d\n", dirfd,
			  dent->d_name, rc);
	    }

	  return 0;
	}
      // woo! save it 
      joined_path = vdev_fullpath (ctx->parent_path, dent->d_name, NULL);
      if (joined_path == NULL)
	{

	  close (fd);
	  return -ENOMEM;
	}

      next = VDEV_CALLOC (struct vdevfs_scandirat_queue, 1);
      if (next == NULL)
	{

	  close (fd);
	  free (joined_path);
	  return -ENOMEM;
	}

      next->fd = fd;
      next->path = joined_path;
      next->next = NULL;

      ctx->tail->next = next;
      ctx->tail = ctx->tail->next;
    }
Пример #5
0
static gboolean
checkout_one_file_at (OstreeRepo                        *repo,
                      OstreeRepoCheckoutOptions         *options,
                      GFile                             *source,
                      GFileInfo                         *source_info,
                      int                                destination_dfd,
                      const char                        *destination_name,
                      GCancellable                      *cancellable,
                      GError                           **error)
{
  gboolean ret = FALSE;
  const char *checksum;
  gboolean is_symlink;
  gboolean can_cache;
  gboolean need_copy = TRUE;
  char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
  g_autoptr(GInputStream) input = NULL;
  g_autoptr(GVariant) xattrs = NULL;
  gboolean is_whiteout;

  is_symlink = g_file_info_get_file_type (source_info) == G_FILE_TYPE_SYMBOLIC_LINK;

  checksum = ostree_repo_file_get_checksum ((OstreeRepoFile*)source);

  is_whiteout = !is_symlink && options->process_whiteouts &&
    g_str_has_prefix (destination_name, WHITEOUT_PREFIX);

  /* First, see if it's a Docker whiteout,
   * https://github.com/docker/docker/blob/1a714e76a2cb9008cd19609059e9988ff1660b78/pkg/archive/whiteouts.go
   */
  if (is_whiteout)
    {
      const char *name = destination_name + (sizeof (WHITEOUT_PREFIX) - 1);

      if (!name[0])
        {
          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                       "Invalid empty whiteout '%s'", name);
          goto out;
        }

      g_assert (name[0] != '/'); /* Sanity */

      if (!glnx_shutil_rm_rf_at (destination_dfd, name, cancellable, error))
        goto out;

      need_copy = FALSE;
    }
  else if (!is_symlink)
    {
      gboolean did_hardlink = FALSE;
      /* Try to do a hardlink first, if it's a regular file.  This also
       * traverses all parent repos.
       */
      OstreeRepo *current_repo = repo;

      while (current_repo)
        {
          gboolean is_bare = ((current_repo->mode == OSTREE_REPO_MODE_BARE
                               && options->mode == OSTREE_REPO_CHECKOUT_MODE_NONE) ||
                              (current_repo->mode == OSTREE_REPO_MODE_BARE_USER
                               && options->mode == OSTREE_REPO_CHECKOUT_MODE_USER));
          gboolean current_can_cache = (options->enable_uncompressed_cache
                                        && current_repo->enable_uncompressed_cache);
          gboolean is_archive_z2_with_cache = (current_repo->mode == OSTREE_REPO_MODE_ARCHIVE_Z2
                                               && options->mode == OSTREE_REPO_CHECKOUT_MODE_USER
                                               && current_can_cache);

          /* But only under these conditions */
          if (is_bare || is_archive_z2_with_cache)
            {
              /* Override repo mode; for archive-z2 we're looking in
                 the cache, which is in "bare" form */
              _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, OSTREE_REPO_MODE_BARE);
              if (!checkout_file_hardlink (current_repo,
                                           options,
                                           loose_path_buf,
                                           destination_dfd, destination_name,
                                           TRUE, &did_hardlink,
                                           cancellable, error))
                goto out;

              if (did_hardlink && options->devino_to_csum_cache)
                {
                  struct stat stbuf;
                  OstreeDevIno *key;
                  
                  if (TEMP_FAILURE_RETRY (fstatat (destination_dfd, destination_name, &stbuf, AT_SYMLINK_NOFOLLOW)) != 0)
                    {
                      glnx_set_error_from_errno (error);
                      goto out;
                    }
                  
                  key = g_new (OstreeDevIno, 1);
                  key->dev = stbuf.st_dev;
                  key->ino = stbuf.st_ino;
                  memcpy (key->checksum, checksum, OSTREE_SHA256_STRING_LEN+1);
                  
                  g_hash_table_add ((GHashTable*)options->devino_to_csum_cache, key);
                }

              if (did_hardlink)
                break;
            }
          current_repo = current_repo->parent_repo;
        }

      need_copy = !did_hardlink;
    }

  can_cache = (options->enable_uncompressed_cache
               && repo->enable_uncompressed_cache);

  /* Ok, if we're archive-z2 and we didn't find an object, uncompress
   * it now, stick it in the cache, and then hardlink to that.
   */
  if (can_cache
      && !is_whiteout
      && !is_symlink
      && need_copy
      && repo->mode == OSTREE_REPO_MODE_ARCHIVE_Z2
      && options->mode == OSTREE_REPO_CHECKOUT_MODE_USER)
    {
      gboolean did_hardlink;
      
      if (!ostree_repo_load_file (repo, checksum, &input, NULL, NULL,
                                  cancellable, error))
        goto out;

      /* Overwrite any parent repo from earlier */
      _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, OSTREE_REPO_MODE_BARE);

      if (!checkout_object_for_uncompressed_cache (repo, loose_path_buf,
                                                   source_info, input,
                                                   cancellable, error))
        {
          g_prefix_error (error, "Unpacking loose object %s: ", checksum);
          goto out;
        }
      
      g_clear_object (&input);

      /* Store the 2-byte objdir prefix (e.g. e3) in a set.  The basic
       * idea here is that if we had to unpack an object, it's very
       * likely we're replacing some other object, so we may need a GC.
       *
       * This model ensures that we do work roughly proportional to
       * the size of the changes.  For example, we don't scan any
       * directories if we didn't modify anything, meaning you can
       * checkout the same tree multiple times very quickly.
       *
       * This is also scale independent; we don't hardcode e.g. looking
       * at 1000 objects.
       *
       * The downside is that if we're unlucky, we may not free
       * an object for quite some time.
       */
      g_mutex_lock (&repo->cache_lock);
      {
        gpointer key = GUINT_TO_POINTER ((g_ascii_xdigit_value (checksum[0]) << 4) + 
                                         g_ascii_xdigit_value (checksum[1]));
        if (repo->updated_uncompressed_dirs == NULL)
          repo->updated_uncompressed_dirs = g_hash_table_new (NULL, NULL);
        g_hash_table_insert (repo->updated_uncompressed_dirs, key, key);
      }
      g_mutex_unlock (&repo->cache_lock);

      if (!checkout_file_hardlink (repo, options, loose_path_buf,
                                   destination_dfd, destination_name,
                                   FALSE, &did_hardlink,
                                   cancellable, error))
        {
          g_prefix_error (error, "Using new cached uncompressed hardlink of %s to %s: ", checksum, destination_name);
          goto out;
        }

      need_copy = !did_hardlink;
    }

  /* Fall back to copy if we couldn't hardlink */
  if (need_copy)
    {
      if (!ostree_repo_load_file (repo, checksum, &input, NULL, &xattrs,
                                  cancellable, error))
        goto out;

      if (options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES)
        {
          if (!checkout_file_unioning_from_input_at (repo, options, source_info, xattrs, input,
                                                     destination_dfd,
                                                     destination_name,
                                                     cancellable, error)) 
            {
              g_prefix_error (error, "Union checkout of %s to %s: ", checksum, destination_name);
              goto out;
            }
        }
      else
        {
          if (!checkout_file_from_input_at (repo, options, source_info, xattrs, input,
                                            destination_dfd,
                                            destination_name,
                                            cancellable, error))
            {
              g_prefix_error (error, "Checkout of %s to %s: ", checksum, destination_name);
              goto out;
            }
        }

      if (input)
        {
          if (!g_input_stream_close (input, cancellable, error))
            goto out;
        }
    }

  ret = TRUE;
 out:
  return ret;
}
Пример #6
0
/*
 * Iterate over all zvols in a given pool by walking the /dev/zvol/dsk/<pool>
 * hierarchy.
 */
int
zpool_iter_zvol(zpool_handle_t *zhp, int (*cb)(const char *, void *),
    void *data)
{
	libzfs_handle_t *hdl = zhp->zpool_hdl;
	char (*paths)[MAXPATHLEN];
	size_t size = 4;
	int curr, base, ret = 0;
//	int fd;
//	DIR *dirp;
//	struct dirent *dp;
	struct stat st;

	if ((base = open("/dev/zvol/dsk", O_RDONLY)) < 0)
		return (errno == ENOENT ? 0 : -1);

#if 0
	if (fstatat(base, zhp->zpool_name, &st, 0) != 0) {
		int err = errno;
		(void) close(base);
		return (err == ENOENT ? 0 : -1);
	}
#endif
	/*
	 * Oddly this wasn't a directory -- ignore that failure since we
	 * know there are no links lower in the (non-existant) hierarchy.
	 */
	if (!S_ISDIR(st.st_mode)) {
		(void) close(base);
		return (0);
	}

	if ((paths = zfs_alloc(hdl, size * sizeof (paths[0]))) == NULL) {
		(void) close(base);
		return (-1);
	}

	(void) strlcpy(paths[0], zhp->zpool_name, sizeof (paths[0]));
	curr = 0;

#if 0
	while (curr >= 0) {
		if (fstatat(base, paths[curr], &st, AT_SYMLINK_NOFOLLOW) != 0)
			goto err;

		if (S_ISDIR(st.st_mode)) {
			if ((fd = openat(base, paths[curr], O_RDONLY)) < 0)
				goto err;

			if ((dirp = fdopendir(fd)) == NULL) {
				(void) close(fd);
				goto err;
			}

			while ((dp = readdir(dirp)) != NULL) {
				if (dp->d_name[0] == '.')
					continue;

				if (curr + 1 == size) {
					paths = zfs_realloc(hdl, paths,
					    size * sizeof (paths[0]),
					    size * 2 * sizeof (paths[0]));
					if (paths == NULL) {
						(void) closedir(dirp);
						(void) close(fd);
						goto err;
					}

					size *= 2;
				}

				(void) strlcpy(paths[curr + 1], paths[curr],
				    sizeof (paths[curr + 1]));
				(void) strlcat(paths[curr], "/",
				    sizeof (paths[curr]));
				(void) strlcat(paths[curr], dp->d_name,
				    sizeof (paths[curr]));
				curr++;
			}

			(void) closedir(dirp);

		} else {
			if ((ret = cb(paths[curr], data)) != 0)
				break;
		}

		curr--;
	}
#endif

	free(paths);
	(void) close(base);

	return (ret);

err:
	free(paths);
	(void) close(base);
	return (-1);
}
Пример #7
0
/* remove all files/directories below dirName -- don't cross mountpoints */
static int recursiveRemove(char *dirName)
{
	struct stat rb;
	DIR *dir;
	int rc = -1;
	int dfd;

	if (!(dir = opendir(dirName))) {
		warn("failed to open %s", dirName);
		goto done;
	}

	dfd = dirfd(dir);

	if (fstat(dfd, &rb)) {
		warn("failed to stat %s", dirName);
		goto done;
	}

	while(1) {
		struct dirent *d;

		errno = 0;
		if (!(d = readdir(dir))) {
			if (errno) {
				warn("failed to read %s", dirName);
				goto done;
			}
			break;	/* end of directory */
		}

		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
			continue;

		if (d->d_type == DT_DIR) {
			struct stat sb;

			if (fstatat(dfd, d->d_name, &sb, AT_SYMLINK_NOFOLLOW)) {
				warn("failed to stat %s/%s", dirName, d->d_name);
				continue;
			}

			/* remove subdirectories if device is same as dir */
			if (sb.st_dev == rb.st_dev) {
				char subdir[ strlen(dirName) +
					     strlen(d->d_name) + 2 ];

				sprintf(subdir, "%s/%s", dirName, d->d_name);
				recursiveRemove(subdir);
			} else
				continue;
		}

		if (unlinkat(dfd, d->d_name,
			     d->d_type == DT_DIR ? AT_REMOVEDIR : 0))
			warn("failed to unlink %s/%s", dirName, d->d_name);
	}

	rc = 0;	/* success */

done:
	if (dir)
		closedir(dir);
	return rc;
}
Пример #8
0
/**
 * Migrate symbolik links
 */
bool MigrateFile::migrateSymLink(void)
{
   bool retVal = false;
   int res;
   int renameRes;
   int metaRes;
   struct stat fromStatData;
   bool wasModified;

   int statRes = fstatat(this->dirFD, this->fileName.c_str(), &fromStatData, AT_SYMLINK_NOFOLLOW);
   if (statRes < 0)
   {
      std::cerr << "Failed to stat (" << this->filePath << "): " << System::getErrString() <<
         std::endl;
      return false;
   }

   // + 20 is arbitary, but must be set for the linkTo size test below as well
   char* linkTo = (char *)malloc(MAX_LINK_SIZE  + 20);
   if (!linkTo)
   {
      std::cerr << "malloc failed (" << this->filePath <<"): " << System::getErrString() <<
         std::endl;
      return false;
   }

   // read linkTo and test its size
   int linkLength = readlinkat(this->dirFD, this->fileName.c_str(), linkTo, MAX_LINK_SIZE + 20);
   if (linkLength + 1 > MAX_LINK_SIZE ) // +1 as we also need to store the \0
   {
      std::cerr << "Symlink too long: " << this->filePath << std::endl;
      goto out;
   }

   linkTo[linkLength] = '\0'; // we need to add the closing character ourself

   if (linkLength < 0)
   {
      std::cerr << "Failed to read link: " << this->filePath << std::endl;
      goto out;
   }

   res = runCreateIoctl(&fromStatData, linkTo);
   if (res) {
      std::cerr << "Failed to create symlink (" << this->filePath << "): "
         << System::getErrString() << std::endl;
      goto out;
   }

   // only request a mode update if we had to remove some bits when we created the file
   if (fromStatData.st_mode & (S_ISVTX | S_ISUID | S_ISGID) )
   {
      metaRes = copyOwnerAndModeLink(&fromStatData); // mode and owner
      if (metaRes == false)
      {
         removeTmpOnErr();
         goto out;
      }
   }

   /* Just before the rename and to keep a possible race window a short as possible, we do a
    * sanity check, if the file was changed in the mean time */
   wasModified = this->fileWasModified(&fromStatData);
   if (wasModified)
   {
      removeTmpOnErr();
      goto out;
   }

   renameRes = renameat(this->dirFD, this->tmpName.c_str(), this->dirFD, this->fileName.c_str());
   if (renameRes)
   {
      std::cerr << "Renaming tmpFile failed (" << this->tmpName << "->" << this->filePath << "): "
         << System::getErrString() << std::endl;
      removeTmpOnErr();
      goto out;
   }

   // now copy over the time stamps, NOTE: although we renamed the file, tmpFD is still valid.
   metaRes = copyTimesLink(&fromStatData);
   if (metaRes == false)
   {
      removeTmpOnErr();
      goto out;
   }


   retVal = true;

out:
   free(linkTo);
   return retVal;
}
Пример #9
0
int
main(int argc, char *argv[])
{
	struct stat sb;
	struct timespec ts[2];
	int atflag;
	int Aflag, aflag, cflag, mflag, ch, fd, len, rval, timeset;
	char *p;
	char *myname;
#ifdef SHELL
	char *optarg;
#endif

	myname = basename(argv[0]);
	Aflag = aflag = cflag = mflag = timeset = 0;
	atflag = 0;
	ts[0].tv_sec = ts[1].tv_sec = 0;
	ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW;

#ifdef SHELL
	while ((ch = nextopt("A:acd:fhmr:t:")) != '\0') {
		optarg = shoptarg;
#else
	while ((ch = getopt(argc, argv, "A:acd:fhmr:t:")) != -1)
#endif
		switch(ch) {
		case 'A':
			Aflag = timeoffset(optarg);
			break;
		case 'a':
			aflag = 1;
			break;
		case 'c':
			cflag = 1;
			break;
		case 'd':
			timeset = 1;
			stime_darg(optarg, ts);
			break;
		case 'f':
			/* No-op for compatibility. */
			break;
		case 'h':
			cflag = 1;
			atflag = AT_SYMLINK_NOFOLLOW;
			break;
		case 'm':
			mflag = 1;
			break;
		case 'r':
			timeset = 1;
			stime_file(optarg, ts);
			break;
		case 't':
			timeset = 1;
			stime_arg1(optarg, ts);
			break;
		default:
			usage(myname);
		}
#ifdef SHELL
	}
	argc -= argptr - argv;
	argv = argptr;
#else
	argc -= optind;
	argv += optind;
#endif

	if (aflag == 0 && mflag == 0)
		aflag = mflag = 1;

	if (timeset) {
		if (Aflag) {
			/*
			 * We're setting the time to an offset from a specified
			 * time.  God knows why, but it means that we can set
			 * that time once and for all here.
			 */
			if (aflag)
				ts[0].tv_sec += Aflag;
			if (mflag)
				ts[1].tv_sec += Aflag;
			Aflag = 0;		/* done our job */
		}
	} else {
		/*
		 * If no -r or -t flag, at least two operands, the first of
		 * which is an 8 or 10 digit number, use the obsolete time
		 * specification, otherwise use the current time.
		 */
		if (argc > 1) {
			strtol(argv[0], &p, 10);
			len = p - argv[0];
			if (*p == '\0' && (len == 8 || len == 10)) {
				timeset = 1;
				stime_arg2(*argv++, len == 10, ts);
			}
		}
		/* Both times default to the same. */
		ts[1] = ts[0];
	}

	if (!aflag)
		ts[0].tv_nsec = UTIME_OMIT;
	if (!mflag)
		ts[1].tv_nsec = UTIME_OMIT;

	if (*argv == NULL)
		usage(myname);

	if (Aflag)
		cflag = 1;

	for (rval = 0; *argv; ++argv) {
		/* See if the file exists. */
		if (fstatat(AT_FDCWD, *argv, &sb, atflag) != 0) {
			if (errno != ENOENT) {
				rval = 1;
				warn("%s", *argv);
				continue;
			}
			if (!cflag) {
				/* Create the file. */
				fd = open(*argv,
				    O_WRONLY | O_CREAT, DEFFILEMODE);
				if (fd == -1 || fstat(fd, &sb) || close(fd)) {
					rval = 1;
					warn("%s", *argv);
					continue;
				}

				/* If using the current time, we're done. */
				if (!timeset)
					continue;
			} else
				continue;
		}

		/*
		 * We're adjusting the times based on the file times, not a
		 * specified time (that gets handled above).
		 */
		if (Aflag) {
			if (aflag) {
				ts[0] = sb.st_atim;
				ts[0].tv_sec += Aflag;
			}
			if (mflag) {
				ts[1] = sb.st_mtim;
				ts[1].tv_sec += Aflag;
			}
		}

		if (!utimensat(AT_FDCWD, *argv, ts, atflag))
			continue;

		rval = 1;
		warn("%s", *argv);
	}
	return (rval);
}
Пример #10
0
char *
__getcwd (char *buf, size_t size)
{
  /* Lengths of big file name components and entire file names, and a
     deep level of file name nesting.  These numbers are not upper
     bounds; they are merely large values suitable for initial
     allocations, designed to be large enough for most real-world
     uses.  */
  enum
    {
      BIG_FILE_NAME_COMPONENT_LENGTH = 255,
      BIG_FILE_NAME_LENGTH = MIN (4095, PATH_MAX - 1),
      DEEP_NESTING = 100
    };

#ifdef AT_FDCWD
  int fd = AT_FDCWD;
  bool fd_needs_closing = false;
#else
  char dots[DEEP_NESTING * sizeof ".." + BIG_FILE_NAME_COMPONENT_LENGTH + 1];
  char *dotlist = dots;
  size_t dotsize = sizeof dots;
  size_t dotlen = 0;
#endif
  DIR *dirstream = NULL;
  dev_t rootdev, thisdev;
  ino_t rootino, thisino;
  char *dir;
  register char *dirp;
  struct stat st;
  size_t allocated = size;
  size_t used;

#if HAVE_PARTLY_WORKING_GETCWD && !defined AT_FDCWD
  /* The system getcwd works, except it sometimes fails when it
     shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT.  If
     AT_FDCWD is not defined, the algorithm below is O(N**2) and this
     is much slower than the system getcwd (at least on GNU/Linux).
     So trust the system getcwd's results unless they look
     suspicious.  */
# undef getcwd
  dir = getcwd (buf, size);
  if (dir || (errno != ERANGE && !is_ENAMETOOLONG (errno) && errno != ENOENT))
    return dir;
#endif

  if (size == 0)
    {
      if (buf != NULL)
	{
	  __set_errno (EINVAL);
	  return NULL;
	}

      allocated = BIG_FILE_NAME_LENGTH + 1;
    }

  if (buf == NULL)
    {
      dir = malloc (allocated);
      if (dir == NULL)
	return NULL;
    }
  else
    dir = buf;

  dirp = dir + allocated;
  *--dirp = '\0';

  if (__lstat (".", &st) < 0)
    goto lose;
  thisdev = st.st_dev;
  thisino = st.st_ino;

  if (__lstat ("/", &st) < 0)
    goto lose;
  rootdev = st.st_dev;
  rootino = st.st_ino;

  while (!(thisdev == rootdev && thisino == rootino))
    {
      struct dirent *d;
      dev_t dotdev;
      ino_t dotino;
      bool mount_point;
      int parent_status;
      size_t dirroom;
      size_t namlen;

      /* Look at the parent directory.  */
#ifdef AT_FDCWD
      fd = openat (fd, "..", O_RDONLY);
      if (fd < 0)
	goto lose;
      fd_needs_closing = true;
      parent_status = fstat (fd, &st);
#else
      dotlist[dotlen++] = '.';
      dotlist[dotlen++] = '.';
      dotlist[dotlen] = '\0';
      parent_status = __lstat (dotlist, &st);
#endif
      if (parent_status != 0)
	goto lose;

      if (dirstream && __closedir (dirstream) != 0)
	{
	  dirstream = NULL;
	  goto lose;
	}

      /* Figure out if this directory is a mount point.  */
      dotdev = st.st_dev;
      dotino = st.st_ino;
      mount_point = dotdev != thisdev;

      /* Search for the last directory.  */
#ifdef AT_FDCWD
      dirstream = fdopendir (fd);
      if (dirstream == NULL)
	goto lose;
      fd_needs_closing = false;
#else
      dirstream = __opendir (dotlist);
      if (dirstream == NULL)
	goto lose;
      dotlist[dotlen++] = '/';
#endif
      for (;;)
	{
	  /* Clear errno to distinguish EOF from error if readdir returns
	     NULL.  */
	  __set_errno (0);
	  d = __readdir (dirstream);
	  if (d == NULL)
	    {
	      if (errno == 0)
		/* EOF on dirstream, which means that the current directory
		   has been removed.  */
		__set_errno (ENOENT);
	      goto lose;
	    }
	  if (d->d_name[0] == '.' &&
	      (d->d_name[1] == '\0' ||
	       (d->d_name[1] == '.' && d->d_name[2] == '\0')))
	    continue;
	  if (MATCHING_INO (d, thisino) || mount_point)
	    {
	      int entry_status;
#ifdef AT_FDCWD
	      entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
#else
	      /* Compute size needed for this file name, or for the file
		 name ".." in the same directory, whichever is larger.
	         Room for ".." might be needed the next time through
		 the outer loop.  */
	      size_t name_alloc = _D_ALLOC_NAMLEN (d);
	      size_t filesize = dotlen + MAX (sizeof "..", name_alloc);

	      if (filesize < dotlen)
		goto memory_exhausted;

	      if (dotsize < filesize)
		{
		  /* My, what a deep directory tree you have, Grandma.  */
		  size_t newsize = MAX (filesize, dotsize * 2);
		  size_t i;
		  if (newsize < dotsize)
		    goto memory_exhausted;
		  if (dotlist != dots)
		    free (dotlist);
		  dotlist = malloc (newsize);
		  if (dotlist == NULL)
		    goto lose;
		  dotsize = newsize;

		  i = 0;
		  do
		    {
		      dotlist[i++] = '.';
		      dotlist[i++] = '.';
		      dotlist[i++] = '/';
		    }
		  while (i < dotlen);
		}

	      strcpy (dotlist + dotlen, d->d_name);
	      entry_status = __lstat (dotlist, &st);
#endif
	      /* We don't fail here if we cannot stat() a directory entry.
		 This can happen when (network) file systems fail.  If this
		 entry is in fact the one we are looking for we will find
		 out soon as we reach the end of the directory without
		 having found anything.  */
	      if (entry_status == 0 && S_ISDIR (st.st_mode)
		  && st.st_dev == thisdev && st.st_ino == thisino)
		break;
	    }
	}

      dirroom = dirp - dir;
      namlen = _D_EXACT_NAMLEN (d);

      if (dirroom <= namlen)
	{
	  if (size != 0)
	    {
	      __set_errno (ERANGE);
	      goto lose;
	    }
	  else
	    {
	      char *tmp;
	      size_t oldsize = allocated;

	      allocated += MAX (allocated, namlen);
	      if (allocated < oldsize
		  || ! (tmp = realloc (dir, allocated)))
		goto memory_exhausted;

	      /* Move current contents up to the end of the buffer.
		 This is guaranteed to be non-overlapping.  */
	      dirp = memcpy (tmp + allocated - (oldsize - dirroom),
			     tmp + dirroom,
			     oldsize - dirroom);
	      dir = tmp;
	    }
	}
      dirp -= namlen;
      memcpy (dirp, d->d_name, namlen);
      *--dirp = '/';

      thisdev = dotdev;
      thisino = dotino;
    }

  if (dirstream && __closedir (dirstream) != 0)
    {
      dirstream = NULL;
      goto lose;
    }

  if (dirp == &dir[allocated - 1])
    *--dirp = '/';

#ifndef AT_FDCWD
  if (dotlist != dots)
    free (dotlist);
#endif

  used = dir + allocated - dirp;
  memmove (dir, dirp, used);

  if (buf == NULL && size == 0)
    /* Ensure that the buffer is only as large as necessary.  */
    buf = realloc (dir, used);

  if (buf == NULL)
    /* Either buf was NULL all along, or `realloc' failed but
       we still have the original string.  */
    buf = dir;

  return buf;

 memory_exhausted:
  __set_errno (ENOMEM);
 lose:
  {
    int save = errno;
    if (dirstream)
      __closedir (dirstream);
#ifdef AT_FDCWD
    if (fd_needs_closing)
      close (fd);
#else
    if (dotlist != dots)
      free (dotlist);
#endif
    if (buf == NULL)
      free (dir);
    __set_errno (save);
  }
  return NULL;
}
Пример #11
0
static int dir_cleanup(
                Item *i,
                const char *p,
                DIR *d,
                const struct stat *ds,
                usec_t cutoff,
                dev_t rootdev,
                bool mountpoint,
                int maxdepth,
                bool keep_this_level)
{
        struct dirent *dent;
        struct timespec times[2];
        bool deleted = false;
        int r = 0;

        while ((dent = readdir(d))) {
                struct stat s;
                usec_t age;
                char _cleanup_free_ *sub_path = NULL;

                if (streq(dent->d_name, ".") ||
                    streq(dent->d_name, ".."))
                        continue;

                if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {

                        if (errno != ENOENT) {
                                log_error("stat(%s/%s) failed: %m", p, dent->d_name);
                                r = -errno;
                        }

                        continue;
                }

                /* Stay on the same filesystem */
                if (s.st_dev != rootdev)
                        continue;

                /* Try to detect bind mounts of the same filesystem instance; they
                 * do not differ in device major/minors. This type of query is not
                 * supported on all kernels or filesystem types though. */
                if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
                        continue;

                /* Do not delete read-only files owned by root */
                if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
                        continue;

                if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) {
                        r = log_oom();
                        goto finish;
                }

                /* Is there an item configured for this path? */
                if (hashmap_get(items, sub_path))
                        continue;

                if (find_glob(globs, sub_path))
                        continue;

                if (S_ISDIR(s.st_mode)) {

                        if (mountpoint &&
                            streq(dent->d_name, "lost+found") &&
                            s.st_uid == 0)
                                continue;

                        if (maxdepth <= 0)
                                log_warning("Reached max depth on %s.", sub_path);
                        else {
                                DIR _cleanup_closedir_ *sub_dir;
                                int q;

                                sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
                                if (sub_dir == NULL) {
                                        if (errno != ENOENT) {
                                                log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
                                                r = -errno;
                                        }

                                        continue;
                                }

                                q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);

                                if (q < 0)
                                        r = q;
                        }

                        /* Note: if you are wondering why we don't
                         * support the sticky bit for excluding
                         * directories from cleaning like we do it for
                         * other file system objects: well, the sticky
                         * bit already has a meaning for directories,
                         * so we don't want to overload that. */

                        if (keep_this_level)
                                continue;

                        /* Ignore ctime, we change it when deleting */
                        age = MAX(timespec_load(&s.st_mtim),
                                  timespec_load(&s.st_atim));
                        if (age >= cutoff)
                                continue;

                        if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) {
                                log_debug("rmdir '%s'\n", sub_path);

                                if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
                                        if (errno != ENOENT && errno != ENOTEMPTY) {
                                                log_error("rmdir(%s): %m", sub_path);
                                                r = -errno;
                                        }
                                }
                        }

                } else {
                        /* Skip files for which the sticky bit is
                         * set. These are semantics we define, and are
                         * unknown elsewhere. See XDG_RUNTIME_DIR
                         * specification for details. */
                        if (s.st_mode & S_ISVTX)
                                continue;

                        if (mountpoint && S_ISREG(s.st_mode)) {
                                if (streq(dent->d_name, ".journal") &&
                                    s.st_uid == 0)
                                        continue;

                                if (streq(dent->d_name, "aquota.user") ||
                                    streq(dent->d_name, "aquota.group"))
                                        continue;
                        }

                        /* Ignore sockets that are listed in /proc/net/unix */
                        if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
                                continue;

                        /* Ignore device nodes */
                        if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
                                continue;

                        /* Keep files on this level around if this is
                         * requested */
                        if (keep_this_level)
                                continue;

                        age = MAX3(timespec_load(&s.st_mtim),
                                   timespec_load(&s.st_atim),
                                   timespec_load(&s.st_ctim));

                        if (age >= cutoff)
                                continue;

                        log_debug("unlink '%s'\n", sub_path);

                        if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
                                if (errno != ENOENT) {
                                        log_error("unlink(%s): %m", sub_path);
                                        r = -errno;
                                }
                        }

                        deleted = true;
                }
        }

finish:
        if (deleted) {
                /* Restore original directory timestamps */
                times[0] = ds->st_atim;
                times[1] = ds->st_mtim;

                if (futimens(dirfd(d), times) < 0)
                        log_error("utimensat(%s): %m", p);
        }

        return r;
}
int
main (void)
{
  int i;
  test_func funcs[2] = { mkfifoat, test_mknodat };
  int result;

  /* Remove any leftovers from a previous partial run.  */
  ignore_value (system ("rm -rf " BASE "*"));

  /* Basic tests.  */
  result = test_mkfifo (do_mkfifoat, true);
  ASSERT (test_mkfifo (do_mknodat, false) == result);
  dfd = open (".", O_RDONLY);
  ASSERT (0 <= dfd);
  ASSERT (test_mkfifo (do_mkfifoat, false) == result);
  ASSERT (test_mkfifo (do_mknodat, false) == result);

  /* Test directory-relative handling of both functions.  */
  for (i = 0; i < 2; i++)
    {
      struct stat st;
      test_func func = funcs[i];

      /* Test behaviour for invalid file descriptors.  */
      {
        errno = 0;
        ASSERT (func (-1, "foo", 0600) == -1);
        ASSERT (errno == EBADF
                || errno == ENOSYS /* seen on mingw */
               );
      }
      {
        errno = 0;
        ASSERT (func (99, "foo", 0600) == -1);
        ASSERT (errno == EBADF
                || errno == ENOSYS /* seen on mingw */
               );
      }

      /* Create fifo while cwd is '.', then stat it from '..'.  */
      if (func (AT_FDCWD, BASE "fifo", 0600) != 0)
        ASSERT (errno == ENOSYS); /* seen on native Windows */
      else
        {
          errno = 0;
          ASSERT (func (dfd, BASE "fifo", 0600) == -1);
          ASSERT (errno == EEXIST);
          ASSERT (chdir ("..") == 0);
          errno = 0;
          ASSERT (fstatat (AT_FDCWD, BASE "fifo", &st, 0) == -1);
          ASSERT (errno == ENOENT);
          memset (&st, 0, sizeof st);
          ASSERT (fstatat (dfd, BASE "fifo", &st, 0) == 0);
          ASSERT (S_ISFIFO (st.st_mode));
          ASSERT (unlinkat (dfd, BASE "fifo", 0) == 0);
        }

      /* Create fifo while cwd is '..', then stat it from '.'.  */
      if (func (dfd, BASE "fifo", 0600) != 0)
        ASSERT (errno == ENOSYS); /* seen on native Windows */
      else
        {
          ASSERT (fchdir (dfd) == 0);
          errno = 0;
          ASSERT (func (AT_FDCWD, BASE "fifo", 0600) == -1);
          ASSERT (errno == EEXIST);
          memset (&st, 0, sizeof st);
          ASSERT (fstatat (AT_FDCWD, BASE "fifo", &st, AT_SYMLINK_NOFOLLOW)
                  == 0);
          ASSERT (S_ISFIFO (st.st_mode));
          memset (&st, 0, sizeof st);
          ASSERT (fstatat (dfd, BASE "fifo", &st, AT_SYMLINK_NOFOLLOW) == 0);
          ASSERT (S_ISFIFO (st.st_mode));
          ASSERT (unlink (BASE "fifo") == 0);
        }
    }

  ASSERT (close (dfd) == 0);

  return 0;
}
Пример #13
0
int main()
{
  int fd;
  char cwd[128];
  struct stat sbuf;
  struct utimbuf ubuf;

  getcwd(cwd, 128);
  //staptest// getcwd (XXXX, 128) = NNNN

  fd = creat("foobar", S_IREAD|S_IWRITE);
  //staptest// [[[[open ("foobar", O_WRONLY|O_CREAT[[[[.O_LARGEFILE]]]]?|O_TRUNC!!!!creat ("foobar"!!!!openat (AT_FDCWD, "foobar", O_WRONLY|O_CREAT|O_TRUNC]]]], 0600) = NNNN

  fstat(fd, &sbuf);
  //staptest// fstat (NNNN, XXXX) = 0

  fstat(-1, &sbuf);
  //staptest// fstat (-1, XXXX) = -NNNN (EBADF)

  // Here we specify -1 to both arguments, to avoid a SIGSEGV.
  fstat(-1, (struct stat *)-1);
#if __WORDSIZE != 64
  // Notice we're not checking for 0x[f]+ here for the 2nd
  // argument. On RHEL[67] {x86_64,s390x}, for a 32-bit exe, glibc
  // substituted a real structure address (verified with strace).
  // staptest// fstat (-1, XXXX) = -NNNN
#else
  //staptest// fstat (-1, 0x[f]+) = -NNNN
#endif

  close(fd);

  stat("foobar", &sbuf);
  //staptest// [[[[stat ("foobar", XXXX!!!!fstatat (AT_FDCWD, "foobar", XXXX, 0x0]]]]) = 0

  stat((char *)-1, &sbuf);
#if defined(__s390__)
  //staptest// stat (0x[7]?[f]+, XXXX) = -NNNN
#else
  //staptest// [[[[stat (0x[f]+, XXXX!!!!fstatat (AT_FDCWD, 0x[f]+, XXXX, 0x0]]]]) = -NNNN
#endif

  // Here we specify -1 to both arguments, to avoid a SIGSEGV.
  stat((char *)-1, (struct stat *)-1);
#if __WORDSIZE != 64
  // Notice we're not checking for 0x[f]+ here for the 2nd
  // argument. On RHEL[67] {x86_64,s390x}, for a 32-bit exe, glibc
  // substituted a real structure address (verified with strace).
  //staptest// stat (0x[7]?[f]+, XXXX) = -NNNN
#else
  //staptest// [[[[stat (0x[f]+, 0x[f]+!!!!fstatat (AT_FDCWD, 0x[f]+, 0x[f]+, 0x0]]]]) = -NNNN
#endif

  lstat("foobar", &sbuf);
  //staptest// [[[[lstat ("foobar", XXXX!!!!fstatat (AT_FDCWD, "foobar", XXXX, AT_SYMLINK_NOFOLLOW]]]]) = 0

  lstat((char *)-1, &sbuf);
#if defined(__s390__)
  //staptest// lstat (0x[7]?[f]+, XXXX) = -NNNN (EFAULT)
#else
  //staptest// [[[[lstat (0x[f]+, XXXX!!!!fstatat (AT_FDCWD, 0x[f]+, XXXX, AT_SYMLINK_NOFOLLOW]]]]) = -NNNN (EFAULT)
#endif

  // Here we specify -1 to both arguments, to avoid a SIGSEGV.
  lstat((char *)-1, (struct stat *)-1);
#if __WORDSIZE != 64
  // Notice we're not checking for 0x[f]+ here for the 2nd
  // argument. On RHEL[67] {x86_64,s390x}, for a 32-bit exe, glibc
  // substituted a real structure address (verified with strace).
  //staptest// lstat (0x[7]?[f]+, XXXX) = -NNNN
#else
  //staptest// [[[[lstat (0x[f]+, 0x[f]+!!!!fstatat (AT_FDCWD, 0x[f]+, 0x[f]+, AT_SYMLINK_NOFOLLOW]]]]) = -NNNN
#endif

#if GLIBC_SUPPORT
  fstatat(AT_FDCWD, "foobar", &sbuf, AT_SYMLINK_NOFOLLOW);
  //staptest// fstatat (AT_FDCWD, "foobar", XXXX, AT_SYMLINK_NOFOLLOW) = 0

  fstatat(-1, "foobar", &sbuf, AT_SYMLINK_NOFOLLOW);
  //staptest// fstatat (-1, "foobar", XXXX, AT_SYMLINK_NOFOLLOW) = -NNNN (EBADF)

  fstatat(AT_FDCWD, (char *)-1, &sbuf, AT_SYMLINK_NOFOLLOW);
#if defined(__s390__)
  //staptest// fstatat (AT_FDCWD, 0x[7]?[f]+, XXXX, AT_SYMLINK_NOFOLLOW) = -NNNN (EFAULT)
#else
  //staptest// fstatat (AT_FDCWD, 0x[f]+, XXXX, AT_SYMLINK_NOFOLLOW) = -NNNN (EFAULT)
#endif

  // Try to avoid a SIGSEGV.
  fstatat(-1, "foobar", (struct stat *)-1, AT_SYMLINK_NOFOLLOW);
#if __WORDSIZE != 64
  // Notice we're not checking for 0x[f]+ here for the 3rd
  // argument. On RHEL[67] {x86_64,s390x}, for a 32-bit exe, glibc
  // substituted a real structure address (verified with strace).
  //staptest// fstatat (-1, "foobar", XXXX, AT_SYMLINK_NOFOLLOW) = -NNNN
#else
  //staptest// fstatat (-1, "foobar", 0x[f]+, AT_SYMLINK_NOFOLLOW) = -NNNN
#endif

  fstatat(AT_FDCWD, "foobar", &sbuf, -1);
  //staptest// fstatat (AT_FDCWD, "foobar", XXXX, AT_[^ ]+|XXXX) = -NNNN (EINVAL)
#endif

  ubuf.actime = 1;
  ubuf.modtime = 1135641600;
  utime("foobar", &ubuf);
#if defined(__aarch64__)
  //staptest// utimensat (AT_FDCWD, "foobar", \[1.[0]+\]\[1135641600.[0]+\], 0x0) =
#elif defined(__ia64__) || defined(__arm__)
  //staptest// utimes ("foobar", \[1.000000\]\[1135641600.000000\]) =
#else
  //staptest// utime ("foobar", \[Thu Jan  1 00:00:01 1970, Tue Dec 27 00:00:00 2005\]) = 0
#endif

  ubuf.actime =  1135690000;
  ubuf.modtime = 1135700000;
  utime("foobar", &ubuf);
#if defined(__aarch64__)
  //staptest// utimensat (AT_FDCWD, "foobar", \[1135690000.[0]+\]\[1135700000.[0]+\], 0x0) =
#elif defined(__ia64__) || defined(__arm__)
  //staptest// utimes ("foobar", \[1135690000.000000\]\[1135700000.000000\]) =
#else
  //staptest// utime ("foobar", \[Tue Dec 27 13:26:40 2005, Tue Dec 27 16:13:20 2005\]) = 0
#endif

  ubuf.actime = 1;
  ubuf.modtime = 1135641600;
  utime((char *)-1, &ubuf);
#if defined(__aarch64__)
  //staptest// utimensat (AT_FDCWD, 0x[f]+, \[1.[0]+\]\[1135641600.[0]+\], 0x0) = -NNNN
#elif defined(__ia64__) || defined(__arm__)
  //staptest// utimes (0x[f]+, \[1.000000\]\[1135641600.000000\]) = -NNNN
#elif defined(__s390__)
  //staptest// utime (0x[7]?[f]+, \[Thu Jan  1 00:00:01 1970, Tue Dec 27 00:00:00 2005\]) = -NNNN
#else
  //staptest// utime (0x[f]+, \[Thu Jan  1 00:00:01 1970, Tue Dec 27 00:00:00 2005\]) = -NNNN
#endif

#if defined(__ia64__) || defined(__arm__) || defined(__aarch64__)
  // Avoid a SIGSEGV by specifying NULL, not -1.
  utime("foobar", (struct utimbuf *)NULL);
  //staptest// [[[[utimes ("foobar", NULL!!!!utimensat (AT_FDCWD, "foobar", NULL, 0x0]]]]) = NNNN
#else
  utime("foobar", (struct utimbuf *)-1);
  //staptest// utime ("foobar", \[Thu Jan  1 00:00:00 1970, Thu Jan  1 00:00:00 1970\]) = -NNNN
#endif

  return 0;
}
Пример #14
0
int get_size(const char *pkgname, const char *apkpath,
             const char *fwdlock_apkpath, const char *asecpath,
             int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
             int64_t* _asecsize)
{
    DIR *d;
    int dfd;
    struct dirent *de;
    struct stat s;
    char path[PKG_PATH_MAX];

    int64_t codesize = 0;
    int64_t datasize = 0;
    int64_t cachesize = 0;
    int64_t asecsize = 0;

        /* count the source apk as code -- but only if it's not
         * on the /system partition and its not on the sdcard.
         */
    if (validate_system_app_path(apkpath) &&
            strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
        if (stat(apkpath, &s) == 0) {
            codesize += stat_size(&s);
        }
    }
        /* count the forward locked apk as code if it is given
         */
    if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
        if (stat(fwdlock_apkpath, &s) == 0) {
            codesize += stat_size(&s);
        }
    }
        /* count the cached dexfile as code */
    if (!create_cache_path(path, apkpath)) {
        if (stat(path, &s) == 0) {
            codesize += stat_size(&s);
        }
    }

        /* compute asec size if it is given
         */
    if (asecpath != NULL && asecpath[0] != '!') {
        if (stat(asecpath, &s) == 0) {
            asecsize += stat_size(&s);
        }
    }

    if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, 0)) {
        goto done;
    }

    d = opendir(path);
    if (d == NULL) {
        goto done;
    }
    dfd = dirfd(d);

    /* most stuff in the pkgdir is data, except for the "cache"
     * directory and below, which is cache, and the "lib" directory
     * and below, which is code...
     */
    while ((de = readdir(d))) {
        const char *name = de->d_name;

        if (de->d_type == DT_DIR) {
            int subfd;
                /* always skip "." and ".." */
            if (name[0] == '.') {
                if (name[1] == 0) continue;
                if ((name[1] == '.') && (name[2] == 0)) continue;
            }
            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
            if (subfd >= 0) {
                int64_t size = calculate_dir_size(subfd);
                if (!strcmp(name,"lib")) {
                    codesize += size;
                } else if(!strcmp(name,"cache")) {
                    cachesize += size;
                } else {
                    datasize += size;
                }
            }
        } else {
            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
                datasize += stat_size(&s);
            }
        }
    }
    closedir(d);
done:
    *_codesize = codesize;
    *_datasize = datasize;
    *_cachesize = cachesize;
    *_asecsize = asecsize;
    return 0;
}
Пример #15
0
char *
__getcwd (char *buf, size_t size)
{
  /* Lengths of big file name components and entire file names, and a
     deep level of file name nesting.  These numbers are not upper
     bounds; they are merely large values suitable for initial
     allocations, designed to be large enough for most real-world
     uses.  */
  enum
    {
      BIG_FILE_NAME_COMPONENT_LENGTH = 255,
      BIG_FILE_NAME_LENGTH = MIN (4095, PATH_MAX - 1),
      DEEP_NESTING = 100
    };

#if HAVE_OPENAT_SUPPORT
  int fd = AT_FDCWD;
  bool fd_needs_closing = false;
#else
  char dots[DEEP_NESTING * sizeof ".." + BIG_FILE_NAME_COMPONENT_LENGTH + 1];
  char *dotlist = dots;
  size_t dotsize = sizeof dots;
  size_t dotlen = 0;
#endif
  DIR *dirstream = NULL;
  dev_t rootdev, thisdev;
  ino_t rootino, thisino;
  char *dir;
  register char *dirp;
  struct stat st;
  size_t allocated = size;
  size_t used;

#if HAVE_MINIMALLY_WORKING_GETCWD
  /* If AT_FDCWD is not defined, the algorithm below is O(N**2) and
     this is much slower than the system getcwd (at least on
     GNU/Linux).  So trust the system getcwd's results unless they
     look suspicious.

     Use the system getcwd even if we have openat support, since the
     system getcwd works even when a parent is unreadable, while the
     openat-based approach does not.

     But on AIX 5.1..7.1, the system getcwd is not even minimally
     working: If the current directory name is slightly longer than
     PATH_MAX, it omits the first directory component and returns
     this wrong result with errno = 0.  */

# undef getcwd
  dir = getcwd (buf, size);
  if (dir || (size && errno == ERANGE))
    return dir;

  /* Solaris getcwd (NULL, 0) fails with errno == EINVAL, but it has
     internal magic that lets it work even if an ancestor directory is
     inaccessible, which is better in many cases.  So in this case try
     again with a buffer that's almost always big enough.  */
  if (errno == EINVAL && buf == NULL && size == 0)
    {
      char big_buffer[BIG_FILE_NAME_LENGTH + 1];
      dir = getcwd (big_buffer, sizeof big_buffer);
      if (dir)
        return strdup (dir);
    }

# if HAVE_PARTLY_WORKING_GETCWD
  /* The system getcwd works, except it sometimes fails when it
     shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT.    */
  if (errno != ERANGE && errno != ENAMETOOLONG && errno != ENOENT)
    return NULL;
# endif
#endif

  if (size == 0)
    {
      if (buf != NULL)
        {
          __set_errno (EINVAL);
          return NULL;
        }

      allocated = BIG_FILE_NAME_LENGTH + 1;
    }

  if (buf == NULL)
    {
      dir = malloc (allocated);
      if (dir == NULL)
        return NULL;
    }
  else
    dir = buf;

  dirp = dir + allocated;
  *--dirp = '\0';

  if (__lstat (".", &st) < 0)
    goto lose;
  thisdev = st.st_dev;
  thisino = st.st_ino;

  if (__lstat ("/", &st) < 0)
    goto lose;
  rootdev = st.st_dev;
  rootino = st.st_ino;

  while (!(thisdev == rootdev && thisino == rootino))
    {
      struct dirent *d;
      dev_t dotdev;
      ino_t dotino;
      bool mount_point;
      int parent_status;
      size_t dirroom;
      size_t namlen;
      bool use_d_ino = true;

      /* Look at the parent directory.  */
#if HAVE_OPENAT_SUPPORT
      fd = openat (fd, "..", O_RDONLY);
      if (fd < 0)
        goto lose;
      fd_needs_closing = true;
      parent_status = fstat (fd, &st);
#else
      dotlist[dotlen++] = '.';
      dotlist[dotlen++] = '.';
      dotlist[dotlen] = '\0';
      parent_status = __lstat (dotlist, &st);
#endif
      if (parent_status != 0)
        goto lose;

      if (dirstream && __closedir (dirstream) != 0)
        {
          dirstream = NULL;
          goto lose;
        }

      /* Figure out if this directory is a mount point.  */
      dotdev = st.st_dev;
      dotino = st.st_ino;
      mount_point = dotdev != thisdev;

      /* Search for the last directory.  */
#if HAVE_OPENAT_SUPPORT
      dirstream = fdopendir (fd);
      if (dirstream == NULL)
        goto lose;
      fd_needs_closing = false;
#else
      dirstream = __opendir (dotlist);
      if (dirstream == NULL)
        goto lose;
      dotlist[dotlen++] = '/';
#endif
      for (;;)
        {
          /* Clear errno to distinguish EOF from error if readdir returns
             NULL.  */
          __set_errno (0);
          d = __readdir (dirstream);

          /* When we've iterated through all directory entries without finding
             one with a matching d_ino, rewind the stream and consider each
             name again, but this time, using lstat.  This is necessary in a
             chroot on at least one system (glibc-2.3.6 + linux 2.6.12), where
             .., ../.., ../../.., etc. all had the same device number, yet the
             d_ino values for entries in / did not match those obtained
             via lstat.  */
          if (d == NULL && errno == 0 && use_d_ino)
            {
              use_d_ino = false;
              rewinddir (dirstream);
              d = __readdir (dirstream);
            }

          if (d == NULL)
            {
              if (errno == 0)
                /* EOF on dirstream, which can mean e.g., that the current
                   directory has been removed.  */
                __set_errno (ENOENT);
              goto lose;
            }
          if (d->d_name[0] == '.' &&
              (d->d_name[1] == '\0' ||
               (d->d_name[1] == '.' && d->d_name[2] == '\0')))
            continue;

          if (use_d_ino)
            {
              bool match = (MATCHING_INO (d, thisino) || mount_point);
              if (! match)
                continue;
            }

          {
            int entry_status;
#if HAVE_OPENAT_SUPPORT
            entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
#else
            /* Compute size needed for this file name, or for the file
               name ".." in the same directory, whichever is larger.
               Room for ".." might be needed the next time through
               the outer loop.  */
            size_t name_alloc = _D_ALLOC_NAMLEN (d);
            size_t filesize = dotlen + MAX (sizeof "..", name_alloc);

            if (filesize < dotlen)
              goto memory_exhausted;

            if (dotsize < filesize)
              {
                /* My, what a deep directory tree you have, Grandma.  */
                size_t newsize = MAX (filesize, dotsize * 2);
                size_t i;
                if (newsize < dotsize)
                  goto memory_exhausted;
                if (dotlist != dots)
                  free (dotlist);
                dotlist = malloc (newsize);
                if (dotlist == NULL)
                  goto lose;
                dotsize = newsize;

                i = 0;
                do
                  {
                    dotlist[i++] = '.';
                    dotlist[i++] = '.';
                    dotlist[i++] = '/';
                  }
                while (i < dotlen);
              }

            memcpy (dotlist + dotlen, d->d_name, _D_ALLOC_NAMLEN (d));
            entry_status = __lstat (dotlist, &st);
#endif
            /* We don't fail here if we cannot stat() a directory entry.
               This can happen when (network) file systems fail.  If this
               entry is in fact the one we are looking for we will find
               out soon as we reach the end of the directory without
               having found anything.  */
            if (entry_status == 0 && S_ISDIR (st.st_mode)
                && st.st_dev == thisdev && st.st_ino == thisino)
              break;
          }
        }

      dirroom = dirp - dir;
      namlen = _D_EXACT_NAMLEN (d);

      if (dirroom <= namlen)
        {
          if (size != 0)
            {
              __set_errno (ERANGE);
              goto lose;
            }
          else
            {
              char *tmp;
              size_t oldsize = allocated;

              allocated += MAX (allocated, namlen);
              if (allocated < oldsize
                  || ! (tmp = realloc (dir, allocated)))
                goto memory_exhausted;

              /* Move current contents up to the end of the buffer.
                 This is guaranteed to be non-overlapping.  */
              dirp = memcpy (tmp + allocated - (oldsize - dirroom),
                             tmp + dirroom,
                             oldsize - dirroom);
              dir = tmp;
            }
        }
      dirp -= namlen;
      memcpy (dirp, d->d_name, namlen);
      *--dirp = '/';

      thisdev = dotdev;
      thisino = dotino;
    }

  if (dirstream && __closedir (dirstream) != 0)
    {
      dirstream = NULL;
      goto lose;
    }

  if (dirp == &dir[allocated - 1])
    *--dirp = '/';

#if ! HAVE_OPENAT_SUPPORT
  if (dotlist != dots)
    free (dotlist);
#endif

  used = dir + allocated - dirp;
  memmove (dir, dirp, used);

  if (size == 0)
    /* Ensure that the buffer is only as large as necessary.  */
    buf = realloc (dir, used);

  if (buf == NULL)
    /* Either buf was NULL all along, or 'realloc' failed but
       we still have the original string.  */
    buf = dir;

  return buf;

 memory_exhausted:
  __set_errno (ENOMEM);
 lose:
  {
    int save = errno;
    if (dirstream)
      __closedir (dirstream);
#if HAVE_OPENAT_SUPPORT
    if (fd_needs_closing)
      close (fd);
#else
    if (dotlist != dots)
      free (dotlist);
#endif
    if (buf == NULL)
      free (dir);
    __set_errno (save);
  }
  return NULL;
}
Пример #16
0
static gboolean
find_booted_deployment (OstreeSysroot       *self,
                        GPtrArray           *deployments,
                        OstreeDeployment   **out_deployment,
                        GCancellable        *cancellable,
                        GError             **error)
{
  gboolean ret = FALSE;
  struct stat root_stbuf;
  struct stat self_stbuf;
  glnx_unref_object OstreeDeployment *ret_deployment = NULL;

  if (stat ("/", &root_stbuf) != 0)
    {
      glnx_set_error_from_errno (error);
      goto out;
    }

  if (!ensure_sysroot_fd (self, error))
    goto out;

  if (fstat (self->sysroot_fd, &self_stbuf) != 0)
    {
      glnx_set_error_from_errno (error);
      goto out;
    }

  if (root_stbuf.st_dev == self_stbuf.st_dev &&
      root_stbuf.st_ino == self_stbuf.st_ino)
    { 
      guint i;
      const char *bootlink_arg;
      __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kernel_args = NULL;
      
      if (!parse_kernel_commandline (&kernel_args, cancellable, error))
        goto out;
      
      bootlink_arg = _ostree_kernel_args_get_last_value (kernel_args, "ostree");
      if (bootlink_arg)
        {
          for (i = 0; i < deployments->len; i++)
            {
              OstreeDeployment *deployment = deployments->pdata[i];
              g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
              struct stat stbuf;

              if (fstatat (self->sysroot_fd, deployment_path, &stbuf, 0) != 0)
                {
                  glnx_set_error_from_errno (error);
                  goto out;
                }

              if (stbuf.st_dev == root_stbuf.st_dev &&
                  stbuf.st_ino == root_stbuf.st_ino)
                {
                  ret_deployment = g_object_ref (deployment);
                  break;
                }
            }

          if (ret_deployment == NULL)
            {
              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                           "Unexpected state: ostree= kernel argument found, but / is not a deployment root");
              goto out;
            }
        }
      else
        {
          /* Not an ostree system */
        }
    }

  ret = TRUE;
  ot_transfer_out_value (out_deployment, &ret_deployment);
 out:
  return ret;
}
Пример #17
0
static int fd_copy_directory(
                int df,
                const char *from,
                const struct stat *st,
                int dt,
                const char *to,
                dev_t original_device,
                bool merge) {

        _cleanup_close_ int fdf = -1, fdt = -1;
        _cleanup_closedir_ DIR *d = NULL;
        struct dirent *de;
        bool created;
        int r;

        assert(st);
        assert(to);

        if (from)
                fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
        else
                fdf = fcntl(df, F_DUPFD_CLOEXEC, 3);

        d = fdopendir(fdf);
        if (!d)
                return -errno;
        fdf = -1;

        r = mkdirat(dt, to, st->st_mode & 07777);
        if (r >= 0)
                created = true;
        else if (errno == EEXIST && merge)
                created = false;
        else
                return -errno;

        fdt = openat(dt, to, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
        if (fdt < 0)
                return -errno;

        r = 0;

        if (created) {
                if (fchown(fdt, st->st_uid, st->st_gid) < 0)
                        r = -errno;

                if (fchmod(fdt, st->st_mode & 07777) < 0)
                        r = -errno;
        }

        FOREACH_DIRENT(de, d, return -errno) {
                struct stat buf;
                int q;

                if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
                        r = -errno;
                        continue;
                }

                if (buf.st_dev != original_device)
                        continue;

                if (S_ISREG(buf.st_mode))
                        q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name);
                else if (S_ISDIR(buf.st_mode))
                        q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, merge);
                else if (S_ISLNK(buf.st_mode))
                        q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
                else if (S_ISFIFO(buf.st_mode))
                        q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name);
                else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode))
                        q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name);
                else
                        q = -ENOTSUP;

                if (q == -EEXIST && merge)
                        q = 0;

                if (q < 0)
                        r = q;
        }

        return r;
}
Пример #18
0
gboolean
_ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self,
                                          int            bootversion,
                                          GPtrArray    **out_loader_configs,
                                          GCancellable  *cancellable,
                                          GError       **error)
{
  gboolean ret = FALSE;
  int fd; /* Temporary owned by iterator */
  g_autofree char *entries_path = g_strdup_printf ("boot/loader.%d/entries", bootversion);
  g_autoptr(GPtrArray) ret_loader_configs = NULL;
  g_auto(GLnxDirFdIterator) dfd_iter = { 0, };

  if (!ensure_sysroot_fd (self, error))
    goto out;

  ret_loader_configs = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);

  fd = glnx_opendirat_with_errno (self->sysroot_fd, entries_path, TRUE);
  if (fd == -1)
    {
      if (errno == ENOENT)
        goto done;
      else
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  if (!glnx_dirfd_iterator_init_take_fd (fd, &dfd_iter, error))
    goto out;

  while (TRUE)
    {
      struct dirent *dent;
      struct stat stbuf;

      if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error))
        goto out;
          
      if (dent == NULL)
        break;

      if (fstatat (dfd_iter.fd, dent->d_name, &stbuf, 0) != 0)
        {
          glnx_set_error_from_errno (error);
          goto out;
        }

      if (g_str_has_prefix (dent->d_name, "ostree-") &&
          g_str_has_suffix (dent->d_name, ".conf") &&
          S_ISREG (stbuf.st_mode))
        {
          glnx_unref_object OstreeBootconfigParser *config = ostree_bootconfig_parser_new ();
  
          if (!ostree_bootconfig_parser_parse_at (config, dfd_iter.fd, dent->d_name, cancellable, error))
            {
              g_prefix_error (error, "Parsing %s: ", dent->d_name);
              goto out;
            }

          g_ptr_array_add (ret_loader_configs, g_object_ref (config));
        }
    }

  /* Callers expect us to give them a sorted array */
  g_ptr_array_sort (ret_loader_configs, compare_loader_configs_for_sorting);

 done:
  gs_transfer_out_value (out_loader_configs, &ret_loader_configs);
  ret = TRUE;
 out:
  return ret;
}
Пример #19
0
/**
 * ostree_repo_list_static_delta_names:
 * @self: Repo
 * @out_deltas: (out) (element-type utf8) (transfer container): String name of deltas (checksum-checksum.delta)
 * @cancellable: Cancellable
 * @error: Error
 *
 * This function synchronously enumerates all static deltas in the
 * repository, returning its result in @out_deltas.
 */
gboolean
ostree_repo_list_static_delta_names (OstreeRepo                  *self,
                                     GPtrArray                  **out_deltas,
                                     GCancellable                *cancellable,
                                     GError                     **error)
{
  g_autoptr(GPtrArray) ret_deltas = g_ptr_array_new_with_free_func (g_free);

  g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
  gboolean exists;
  if (!ot_dfd_iter_init_allow_noent (self->repo_dir_fd, "deltas", &dfd_iter,
                                     &exists, error))
    return FALSE;
  if (!exists)
    {
      /* Note early return */
      ot_transfer_out_value (out_deltas, &ret_deltas);
      return TRUE;
    }

  while (TRUE)
    {
      g_auto(GLnxDirFdIterator) sub_dfd_iter = { 0, };
      struct dirent *dent;

      if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
        return FALSE;
      if (dent == NULL)
        break;
      if (dent->d_type != DT_DIR)
        continue;

      if (!glnx_dirfd_iterator_init_at (dfd_iter.fd, dent->d_name, FALSE,
                                        &sub_dfd_iter, error))
        return FALSE;

      while (TRUE)
        {
          struct dirent *sub_dent;
          const char *name1;
          const char *name2;
          g_autofree char *superblock_subpath = NULL;
          struct stat stbuf;

          if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&sub_dfd_iter, &sub_dent,
                                                           cancellable, error))
            return FALSE;
          if (sub_dent == NULL)
            break;
          if (dent->d_type != DT_DIR)
            continue;

          name1 = dent->d_name;
          name2 = sub_dent->d_name;

          superblock_subpath = g_strconcat (name2, "/superblock", NULL);
          if (fstatat (sub_dfd_iter.fd, superblock_subpath, &stbuf, 0) < 0)
            {
              if (errno != ENOENT)
                {
                  glnx_set_error_from_errno (error);
                  return FALSE;
                }
            }
          else
            {
              g_autofree char *buf = g_strconcat (name1, name2, NULL);
              GString *out = g_string_new ("");
              char checksum[OSTREE_SHA256_STRING_LEN+1];
              guchar csum[OSTREE_SHA256_DIGEST_LEN];
              const char *dash = strchr (buf, '-');

              ostree_checksum_b64_inplace_to_bytes (buf, csum);
              ostree_checksum_inplace_from_bytes (csum, checksum);
              g_string_append (out, checksum);
              if (dash)
                {
                  g_string_append_c (out, '-');
                  ostree_checksum_b64_inplace_to_bytes (dash+1, csum);
                  ostree_checksum_inplace_from_bytes (csum, checksum);
                  g_string_append (out, checksum);
                }

              g_ptr_array_add (ret_deltas, g_string_free (out, FALSE));
            }
        }
    }

  ot_transfer_out_value (out_deltas, &ret_deltas);
  return TRUE;
}
Пример #20
0
void
copymkdir(int rootfd, char const * dir, int skelfd, mode_t mode, uid_t uid,
    gid_t gid, int flags)
{
	char		*p, lnk[MAXPATHLEN], copybuf[4096];
	int		len, homefd, srcfd, destfd;
	ssize_t		sz;
	struct stat     st;
	struct dirent  *e;
	DIR		*d;

	if (*dir == '/')
		dir++;

	if (mkdirat(rootfd, dir, mode) != 0 && errno != EEXIST) {
		warn("mkdir(%s)", dir);
		return;
	}
	fchownat(rootfd, dir, uid, gid, AT_SYMLINK_NOFOLLOW);
	if (flags > 0)
		chflagsat(rootfd, dir, flags, AT_SYMLINK_NOFOLLOW);

	if (skelfd == -1)
		return;

	homefd = openat(rootfd, dir, O_DIRECTORY);
	if ((d = fdopendir(skelfd)) == NULL) {
		close(skelfd);
		close(homefd);
		return;
	}

	while ((e = readdir(d)) != NULL) {
		if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0)
			continue;

		p = e->d_name;
		if (fstatat(skelfd, p, &st, AT_SYMLINK_NOFOLLOW) == -1)
			continue;

		if (strncmp(p, "dot.", 4) == 0)	/* Conversion */
			p += 3;

		if (S_ISDIR(st.st_mode)) {
			copymkdir(homefd, p, openat(skelfd, e->d_name, O_DIRECTORY),
			    st.st_mode & _DEF_DIRMODE, uid, gid, st.st_flags);
			continue;
		}

		if (S_ISLNK(st.st_mode) &&
		    (len = readlinkat(skelfd, e->d_name, lnk, sizeof(lnk) -1))
		    != -1) {
			lnk[len] = '\0';
			symlinkat(lnk, homefd, p);
			fchownat(homefd, p, uid, gid, AT_SYMLINK_NOFOLLOW);
			continue;
		}

		if (!S_ISREG(st.st_mode))
			continue;

		if ((srcfd = openat(skelfd, e->d_name, O_RDONLY)) == -1)
			continue;
		destfd = openat(homefd, p, O_RDWR | O_CREAT | O_EXCL,
		    st.st_mode);
		if (destfd == -1) {
			close(srcfd);
			continue;
		}

		while ((sz = read(srcfd, copybuf, sizeof(copybuf))) > 0)
			write(destfd, copybuf, sz);

		close(srcfd);
		/*
		 * Propagate special filesystem flags
		 */
		fchown(destfd, uid, gid);
		fchflags(destfd, st.st_flags);
		close(destfd);
	}
	closedir(d);
}
Пример #21
0
int
rpl_utimensat (int fd, char const *file, struct timespec const times[2],
               int flag)
{
# ifdef __linux__
    struct timespec ts[2];
# endif

    /* See comments in utimens.c for details.  */
    static int utimensat_works_really; /* 0 = unknown, 1 = yes, -1 = no.  */
    if (0 <= utimensat_works_really)
    {
        int result;
# ifdef __linux__
        struct stat st;
        /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
           systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
           but work if both times are either explicitly specified or
           UTIME_NOW.  Work around it with a preparatory [l]stat prior
           to calling utimensat; fortunately, there is not much timing
           impact due to the extra syscall even on file systems where
           UTIME_OMIT would have worked.  FIXME: Simplify this in 2012,
           when file system bugs are no longer common.  */
        if (times && (times[0].tv_nsec == UTIME_OMIT
                      || times[1].tv_nsec == UTIME_OMIT))
        {
            if (fstatat (fd, file, &st, flag))
                return -1;
            if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
                return 0;
            if (times[0].tv_nsec == UTIME_OMIT)
                ts[0] = get_stat_atime (&st);
            else
                ts[0] = times[0];
            if (times[1].tv_nsec == UTIME_OMIT)
                ts[1] = get_stat_mtime (&st);
            else
                ts[1] = times[1];
            times = ts;
        }
#  ifdef __hppa__
        /* Linux kernel 2.6.22.19 on hppa does not reject invalid tv_nsec
           values.  */
        else if (times
                 && ((times[0].tv_nsec != UTIME_NOW
                      && (times[0].tv_nsec < 0
                          || times[0].tv_nsec >= 1000000000))
                     || (times[1].tv_nsec != UTIME_NOW
                         && (times[1].tv_nsec < 0
                             || times[1].tv_nsec >= 1000000000))))
        {
            errno = EINVAL;
            return -1;
        }
#  endif
# endif /* __linux__ */
        result = utimensat (fd, file, times, flag);
        /* Linux kernel 2.6.25 has a bug where it returns EINVAL for
           UTIME_NOW or UTIME_OMIT with non-zero tv_sec, which
           local_utimensat works around.  Meanwhile, EINVAL for a bad
           flag is indeterminate whether the native utimensat works, but
           local_utimensat will also reject it.  */
        if (result == -1 && errno == EINVAL && (flag & ~AT_SYMLINK_NOFOLLOW))
            return result;
        if (result == 0 || (errno != ENOSYS && errno != EINVAL))
        {
            utimensat_works_really = 1;
            return result;
        }
    }
    /* No point in trying openat/futimens, since on Linux, futimens is
       implemented with the same syscall as utimensat.  Only avoid the
       native utimensat due to an ENOSYS failure; an EINVAL error was
       data-dependent, and the next caller may pass valid data.  */
    if (0 <= utimensat_works_really && errno == ENOSYS)
        utimensat_works_really = -1;
    return local_utimensat (fd, file, times, flag);
}
Пример #22
0
int get_size(const char *pkgname, userid_t userid, const char *apkpath,
             const char *libdirpath, const char *fwdlock_apkpath, const char *asecpath,
             int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
             int64_t* _asecsize)
{
    DIR *d;
    int dfd;
    struct dirent *de;
    struct stat s;
    char path[PKG_PATH_MAX];

    int64_t codesize = 0;
    int64_t datasize = 0;
    int64_t cachesize = 0;
    int64_t asecsize = 0;

        /* count the source apk as code -- but only if it's not
         * on the /system partition and its not on the sdcard.
         */
    if (validate_system_app_path(apkpath) &&
            strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
        if (stat(apkpath, &s) == 0) {
            codesize += stat_size(&s);
        }
    }
        /* count the forward locked apk as code if it is given
         */
    if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
        if (stat(fwdlock_apkpath, &s) == 0) {
            codesize += stat_size(&s);
        }
    }
        /* count the cached dexfile as code */
    if (!create_cache_path(path, apkpath)) {
        if (stat(path, &s) == 0) {
            codesize += stat_size(&s);
        }
    }

        /* add in size of any libraries */
        /* If the app is on the SD card, the libraries are stored in asecpath.
         * If we don't check that asecpath is defined, the libraries will be
         * counted twice. Once in asecsize and once in codesize. */
    if ((asecpath == NULL || asecpath[0] == '!') &&
            libdirpath != NULL && libdirpath[0] != '!') {
        d = opendir(libdirpath);
        if (d != NULL) {
            dfd = dirfd(d);
            codesize += calculate_dir_size(dfd);
            closedir(d);
        }
    }

        /* compute asec size if it is given
         */
    if (asecpath != NULL && asecpath[0] != '!') {
        if (stat(asecpath, &s) == 0) {
            asecsize += stat_size(&s);
        }
    }

    if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, userid)) {
        goto done;
    }

    d = opendir(path);
    if (d == NULL) {
        goto done;
    }
    dfd = dirfd(d);

    /* most stuff in the pkgdir is data, except for the "cache"
     * directory and below, which is cache, and the "lib" directory
     * and below, which is code...
     */
    while ((de = readdir(d))) {
        const char *name = de->d_name;

        if (de->d_type == DT_DIR) {
            int subfd;
            int64_t statsize = 0;
            int64_t dirsize = 0;
                /* always skip "." and ".." */
            if (name[0] == '.') {
                if (name[1] == 0) continue;
                if ((name[1] == '.') && (name[2] == 0)) continue;
            }
            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
                statsize = stat_size(&s);
            }
            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
            if (subfd >= 0) {
                dirsize = calculate_dir_size(subfd);
            }
            if(!strcmp(name,"lib")) {
                codesize += dirsize + statsize;
            } else if(!strcmp(name,"cache")) {
                cachesize += dirsize + statsize;
            } else {
                datasize += dirsize + statsize;
            }
        } else if (de->d_type == DT_LNK && !strcmp(name,"lib")) {
            // This is the symbolic link to the application's library
            // code.  We'll count this as code instead of data, since
            // it is not something that the app creates.
            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
                codesize += stat_size(&s);
            }
        } else {
            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
                datasize += stat_size(&s);
            }
        }
    }
    closedir(d);
done:
    *_codesize = codesize;
    *_datasize = datasize;
    *_cachesize = cachesize;
    *_asecsize = asecsize;
    return 0;
}
Пример #23
0
fsal_status_t XFSFSAL_unlink(fsal_handle_t * p_parent_directory_handle,      /* IN */
                             fsal_name_t * p_object_name,       /* IN */
                             fsal_op_context_t * p_context,  /* IN */
                             fsal_attrib_list_t * p_parent_directory_attributes /* [IN/OUT ] */
    )
{

  fsal_status_t status;
  int rc, errsv;
  struct stat buffstat, buffstat_parent;
  int fd;

  /* sanity checks. */
  if(!p_parent_directory_handle || !p_context || !p_object_name)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_unlink);

  /* build the FID path */
  TakeTokenFSCall();
  status =
      fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_DIRECTORY);
  ReleaseTokenFSCall();
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_unlink);

  /* get directory metadata */
  TakeTokenFSCall();
  rc = fstat(fd, &buffstat_parent);
  errsv = errno;
  ReleaseTokenFSCall();
  if(rc)
    {
      close(fd);

      if(errsv == ENOENT)
        Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_unlink);
      else
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink);
    }

  /* build the child path */

  /* get file metadata */
  TakeTokenFSCall();
  rc = fstatat(fd, p_object_name->name, &buffstat, AT_SYMLINK_NOFOLLOW);
  errsv = errno;
  ReleaseTokenFSCall();
  if(rc)
    {
      close(fd);
      Return(posix2fsal_error(errno), errno, INDEX_FSAL_unlink);
    }

  /* check access rights */

  /* Sticky bit on the directory => the user who wants to delete the file must own it or its parent dir */
  if((buffstat_parent.st_mode & S_ISVTX)
     && buffstat_parent.st_uid != ((xfsfsal_op_context_t *)p_context)->credential.user
     && buffstat.st_uid != ((xfsfsal_op_context_t *)p_context)->credential.user
     && ((xfsfsal_op_context_t *)p_context)->credential.user != 0)
    {
      close(fd);
      Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_unlink);
    }

  /* client must be able to lookup the parent directory and modify it */
  status =
      fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat_parent, NULL);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_unlink);

  /******************************
   * DELETE FROM THE FILESYSTEM *
   ******************************/
  TakeTokenFSCall();
  /* If the object to delete is a directory, use 'rmdir' to delete the object, else use 'unlink' */
  rc = (S_ISDIR(buffstat.st_mode)) ? unlinkat(fd, p_object_name->name,
                                              AT_REMOVEDIR) : unlinkat(fd,
                                                                       p_object_name->name,
                                                                       0);
  errsv = errno;
  ReleaseTokenFSCall();

  close(fd);

  if(rc)
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink);

  /***********************
   * FILL THE ATTRIBUTES *
   ***********************/

  if(p_parent_directory_attributes)
    {
      status =
          XFSFSAL_getattrs(p_parent_directory_handle, p_context,
                           p_parent_directory_attributes);
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_parent_directory_attributes->asked_attributes);
          FSAL_SET_MASK(p_parent_directory_attributes->asked_attributes,
                        FSAL_ATTR_RDATTR_ERR);
        }
    }
  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_unlink);

}
Пример #24
0
fsal_status_t XFSFSAL_readdir(fsal_dir_t * dir_descriptor, /* IN */
                              fsal_cookie_t startposition,  /* IN */
                              fsal_attrib_mask_t get_attr_mask, /* IN */
                              fsal_mdsize_t buffersize, /* IN */
                              fsal_dirent_t * p_pdirent,        /* OUT */
                              fsal_cookie_t * end_position,        /* OUT */
                              fsal_count_t * p_nb_entries,      /* OUT */
                              fsal_boolean_t * p_end_of_dir     /* OUT */
    )
{
  xfsfsal_dir_t * p_dir_descriptor = (xfsfsal_dir_t * ) dir_descriptor;
  xfsfsal_cookie_t start_position;
  xfsfsal_cookie_t * p_end_position = (xfsfsal_cookie_t *) end_position;
  fsal_status_t st;
  fsal_count_t max_dir_entries;
  char buff[BUF_SIZE];
  struct linux_dirent *dp = NULL;
  int bpos = 0;
  int tmpfd = 0;

  char d_type;
  struct stat buffstat;

  int errsv = 0, rc = 0;

  memset(buff, 0, BUF_SIZE);

  /*****************/
  /* sanity checks */
  /*****************/

  if(!p_dir_descriptor || !p_pdirent || !p_end_position || !p_nb_entries || !p_end_of_dir)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir);

  max_dir_entries = (buffersize / sizeof(fsal_dirent_t));

  /***************************/
  /* seek into the directory */
  /***************************/
  start_position.data.cookie = (off_t) startposition.data;
  errno = 0;
  if(start_position.data.cookie == 0)
    {
      //rewinddir(p_dir_descriptor->p_dir);
      rc = errno;
    }
  else
    {
      //seekdir(p_dir_descriptor->p_dir, start_position.cookie);
      rc = errno;
    }

  if(rc)
    Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir);

  /************************/
  /* browse the directory */
  /************************/

  *p_nb_entries = 0;
  while(*p_nb_entries < max_dir_entries)
    {
    /***********************/
      /* read the next entry */
    /***********************/
      TakeTokenFSCall();
      rc = syscall(SYS_getdents, p_dir_descriptor->fd, buff, BUF_SIZE);
      ReleaseTokenFSCall();
      if(rc < 0)
        {
          rc = errno;
          Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir);
        }
      /* End of directory */
      if(rc == 0)
        {
          *p_end_of_dir = 1;
          break;
        }

    /***********************************/
      /* Get information about the entry */
    /***********************************/

      for(bpos = 0; bpos < rc;)
        {
          dp = (struct linux_dirent *)(buff + bpos);
          d_type = *(buff + bpos + dp->d_reclen - 1);
                                                    /** @todo not used for the moment. Waiting for information on symlink management */
          bpos += dp->d_reclen;

          /* LogFullDebug(COMPONENT_FSAL, "\tino=%8ld|%8lx off=%d|%x reclen=%d|%x name=%s|%d", dp->d_ino, dp->d_ino, (int)dp->d_off, (int)dp->d_off, 
             dp->d_reclen, dp->d_reclen, dp->d_name, (int)dp->d_name[0]  ) ; */

          if(!(*p_nb_entries < max_dir_entries))
            break;

          /* skip . and .. */
          if(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
            continue;

          /* build the full path of the file into "fsalpath */
          if(FSAL_IS_ERROR
             (st =
              FSAL_str2name(dp->d_name, FSAL_MAX_NAME_LEN,
                            &(p_pdirent[*p_nb_entries].name))))
            ReturnStatus(st, INDEX_FSAL_readdir);

          d_type = DT_UNKNOWN;
          if((tmpfd =
              openat(p_dir_descriptor->fd, dp->d_name, O_RDONLY | O_NOFOLLOW, 0600)) < 0)
            {
              if(errno != ELOOP)        /* ( p_dir_descriptor->fd, dp->d_name) is not a symlink */
                Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_readdir);
              else
                d_type = DT_LNK;
            }

          /* get object handle */
          TakeTokenFSCall();
          if(d_type != DT_LNK)
            {
              st = fsal_internal_fd2handle((fsal_op_context_t *)&(p_dir_descriptor->context),
					   tmpfd, &(p_pdirent[*p_nb_entries].handle));
              close(tmpfd);
            }
          else
            {
              if(fstatat(p_dir_descriptor->fd, dp->d_name, &buffstat, AT_SYMLINK_NOFOLLOW)
                 < 0)
                {
                  ReleaseTokenFSCall();
                  Return(posix2fsal_error(errno), errno, INDEX_FSAL_readdir);
                }

              st = fsal_internal_inum2handle(&p_dir_descriptor->context,
                                             buffstat.st_ino, &(p_pdirent[*p_nb_entries].handle));

              if(FSAL_IS_ERROR(st))
                {
                  ReleaseTokenFSCall();
                  ReturnStatus(st, INDEX_FSAL_readdir);
                }
              p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask;

              st = posix2fsal_attributes(&buffstat, &p_pdirent[*p_nb_entries].attributes);
              if(FSAL_IS_ERROR(st))
                {
                  ReleaseTokenFSCall();
                  FSAL_CLEAR_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes);
                  FSAL_SET_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes,
                                FSAL_ATTR_RDATTR_ERR);
                  ReturnStatus(st, INDEX_FSAL_getattrs);
                }

            }
          ReleaseTokenFSCall();

          if(FSAL_IS_ERROR(st))
            ReturnStatus(st, INDEX_FSAL_readdir);

    /************************
     * Fills the attributes *
     ************************/
          if(d_type != DT_LNK)
            {
              p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask;

              st = XFSFSAL_getattrs((xfsfsal_handle_t
                                     *) (&(p_pdirent[*p_nb_entries].handle)),
                                    (xfsfsal_op_context_t *) & p_dir_descriptor->context,
                                    &p_pdirent[*p_nb_entries].attributes);
              if(FSAL_IS_ERROR(st))
                {
                  FSAL_CLEAR_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes);
                  FSAL_SET_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes,
                                FSAL_ATTR_RDATTR_ERR);
                }
            }
          //p_pdirent[*p_nb_entries].cookie.cookie = dp->d_off;
          ((xfsfsal_cookie_t *) (&p_pdirent[*p_nb_entries].cookie))->data.cookie = dp->d_off;
          p_pdirent[*p_nb_entries].nextentry = NULL;
          if(*p_nb_entries)
            p_pdirent[*p_nb_entries - 1].nextentry = &(p_pdirent[*p_nb_entries]);

          //(*p_end_position) = p_pdirent[*p_nb_entries].cookie;
          memcpy((char *)p_end_position, (char *)&p_pdirent[*p_nb_entries].cookie,
                 sizeof(xfsfsal_cookie_t));

          (*p_nb_entries)++;

        }                       /* for */
    }                           /* While */

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir);

}
Пример #25
0
int
pkg_sshserve(int fd)
{
	struct stat st;
	char *line = NULL;
	char *file, *age;
	size_t linecap = 0, r;
	ssize_t linelen;
	time_t mtime = 0;
	const char *errstr;
	int ffd;
	char buf[BUFSIZ];
	char fpath[MAXPATHLEN];
	char rpath[MAXPATHLEN];
	const char *restricted = NULL;

	restricted = pkg_object_string(pkg_config_get("SSH_RESTRICT_DIR"));

	printf("ok: pkg "PKGVERSION"\n");
	for (;;) {
		if ((linelen = getline(&line, &linecap, stdin)) < 0)
			break;

		if (linelen == 0)
			continue;

		/* trim cr */
		if (line[linelen - 1] == '\n')
			line[linelen - 1] = '\0';

		if (strcmp(line, "quit") == 0)
			return (EPKG_OK);

		if (strncmp(line, "get ", 4) != 0) {
			printf("ko: unknown command '%s'\n", line);
			continue;
		}

		file = line + 4;

		if (*file == '/')
			file++;
		else if (*file == '\0') {
			printf("ko: bad command get, expecting 'get file age'\n");
			continue;
		}

		pkg_debug(1, "SSH server> file requested: %s", file);

		age = file;
		while (!isspace(*age)) {
			if (*age == '\0') {
				age = NULL;
				break;
			}
			age++;
		}

		if (age == NULL) {
			printf("ko: bad command get, expecting 'get file age'\n");
			continue;
		}

		*age = '\0';
		age++;

		while (isspace(*age)) {
			if (*age == '\0') {
				age = NULL;
				break;
			}
			age++;
		}

		if (age == NULL) {
			printf("ko: bad command get, expecting 'get file age'\n");
			continue;
		}

		mtime = strtonum(age, 0, LONG_MAX, &errstr);
		if (errstr) {
			printf("ko: bad number %s: %s\n", age, errstr);
			continue;
		}

#ifdef HAVE_CAPSICUM
		if (!cap_sandboxed() && restricted != NULL) {
#else
		if (restricted != NULL) {
#endif
			if (chdir(restricted)) {
				printf("ko: chdir failed (%s)\n", restricted);
				continue;
			}

			if (realpath(file, fpath) == NULL ||
			    realpath(restricted, rpath) == NULL ||
			    strncmp(fpath, rpath, strlen(rpath)) != 0) {
				printf("ko: file not found\n");
				continue;
			}
		}

		if (fstatat(fd, file, &st, 0) == -1) {
			pkg_debug(1, "SSH server> fstatat failed");
			printf("ko: file not found\n");
			continue;
		}

		if (!S_ISREG(st.st_mode)) {
			printf("ko: not a file\n");
			continue;
		}

		if (st.st_mtime <= mtime) {
			printf("ok: 0\n");
			continue;
		}

		if ((ffd = openat(fd, file, O_RDONLY)) == -1) {
			printf("ko: file not found\n");
			continue;
		}

		printf("ok: %" PRIdMAX "\n", (intmax_t)st.st_size);
		pkg_debug(1, "SSH server> sending ok: %" PRIdMAX "", (intmax_t)st.st_size);

		while ((r = read(ffd, buf, sizeof(buf))) > 0) {
			pkg_debug(1, "SSH server> sending data");
			fwrite(buf, 1, r, stdout);
		}

		pkg_debug(1, "SSH server> finished");

		close(ffd);
	}

	free(line);

	return (EPKG_OK);
}
Пример #26
0
static int
convert_from_old(const char *pkg_add_dbdir, bool dry_run)
{
	DIR		*d;
	struct dirent	*dp;
	struct pkg	*p = NULL;
	char		 path[MAXPATHLEN];
	struct pkgdb	*db = NULL;
	struct stat	 sb;
	int		lock_type = PKGDB_LOCK_EXCLUSIVE;
	int		ret;

	if (dry_run)
		ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL);
	else
		ret = pkgdb_access(PKGDB_MODE_READ|PKGDB_MODE_WRITE|
		    PKGDB_MODE_CREATE, PKGDB_DB_LOCAL);

	if (ret == EPKG_ENOACCESS) {
		warnx("Insufficient privileges to convert packages");
		return (EX_NOPERM);
	} else if (ret != EPKG_OK && ret != EPKG_ENODB) {
		warnx("Error accessing the package database");
		return (EX_SOFTWARE);
	}

	if ((d = opendir(pkg_add_dbdir)) == NULL)
		err(EX_NOINPUT, "%s", pkg_add_dbdir);

	if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
		return (EX_IOERR);
	}
	if (dry_run)
		lock_type = PKGDB_LOCK_READONLY;
	if (pkgdb_obtain_lock(db, lock_type) != EPKG_OK) {
		pkgdb_close(db);
		warnx("Cannot get an advisory lock on a database, it is locked"
		    " by another process");
		return (EX_TEMPFAIL);
	}
	while ((dp = readdir(d)) != NULL) {
		if (fstatat(dirfd(d), dp->d_name, &sb, 0) == 0 &&
		    S_ISDIR(sb.st_mode)) {
			if (strcmp(dp->d_name, ".") == 0 ||
			    strcmp(dp->d_name, "..") == 0)
				continue;
			if (p != NULL)
				pkg_free(p);
			if (pkg_new(&p, PKG_OLD_FILE) != EPKG_OK)
				err(EX_OSERR, "malloc");
			printf("Converting %s...\n", dp->d_name);
			snprintf(path, sizeof(path), "%s/%s", pkg_add_dbdir, dp->d_name);
			if (pkg_old_load_from_path(p, path) != EPKG_OK) {
				fprintf(stderr, "Skipping invalid package: %s\n", path);
				continue;
			}
			pkg_from_old(p);
			if (!dry_run)
				pkgdb_register_ports(db, p);
		}
	}

	pkg_free(p);
	pkgdb_release_lock(db, lock_type);
	pkgdb_close(db);
	return (EX_OK);
}
static gboolean
export_dir (int            source_parent_fd,
            const char    *source_name,
            const char    *source_relpath,
            int            destination_parent_fd,
            const char    *destination_name,
            const char    *required_prefix,
            GCancellable  *cancellable,
            GError       **error)
{
  gboolean ret = FALSE;
  int res;
  g_auto(GLnxDirFdIterator) source_iter = {0};
  glnx_fd_close int destination_dfd = -1;
  struct dirent *dent;

  if (!glnx_dirfd_iterator_init_at (source_parent_fd, source_name, FALSE, &source_iter, error))
    goto out;

  do
    res = mkdirat (destination_parent_fd, destination_name, 0777);
  while (G_UNLIKELY (res == -1 && errno == EINTR));
  if (res == -1)
    {
      if (errno != EEXIST)
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  if (!gs_file_open_dir_fd_at (destination_parent_fd, destination_name,
                               &destination_dfd,
                               cancellable, error))
    goto out;

  while (TRUE)
    {
      struct stat stbuf;
      g_autofree char *source_printable = NULL;

      if (!glnx_dirfd_iterator_next_dent (&source_iter, &dent, cancellable, error))
        goto out;

      if (dent == NULL)
        break;

      if (fstatat (source_iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) == -1)
        {
          if (errno == ENOENT)
            continue;
          else
            {
              glnx_set_error_from_errno (error);
              goto out;
            }
        }

      if (S_ISDIR (stbuf.st_mode))
        {
          g_autofree gchar *child_relpath = g_build_filename(source_relpath, dent->d_name, NULL);

          if (!export_dir (source_iter.fd, dent->d_name, child_relpath, destination_dfd, dent->d_name,
                           required_prefix, cancellable, error))
            goto out;
        }
      else if (S_ISREG (stbuf.st_mode))
        {
          source_printable = g_build_filename (source_relpath, dent->d_name, NULL);


          if (!xdg_app_has_name_prefix (dent->d_name, required_prefix))
            {
              g_print ("Not exporting %s, wrong prefix\n", source_printable);
              continue;
            }

          g_print ("Exporting %s\n", source_printable);

          if (!glnx_file_copy_at (source_iter.fd, dent->d_name, &stbuf,
                                  destination_dfd, dent->d_name,
                                  GLNX_FILE_COPY_NOXATTRS,
                                  cancellable,
                                  error))
            goto out;
        }
      else
        {
          source_printable = g_build_filename (source_relpath, dent->d_name, NULL);
          g_print ("Not exporting non-regular file %s\n", source_printable);
        }
    }

  ret = TRUE;
 out:

  return ret;
}
Пример #28
0
/**
 * Check if the list of links to a file is complete.
 * This function goes through all the names in the list of names an
 * checks if the name references the file given by the dev/inode pair.
 * It returns zero if all links are found and a negative error code
 * in case of errors.
 *
 * @param dev The device where the file resides.
 * @param ino The inode number of the file.
 * @param namearr a list of path names relative to the root of the given
 *     device. These name are searched for links the file with the given
 *     inode number.
 * @return Zero if all links to the file could be found. A negative
 *     error code if something went wrong. In particular:
 *     EXDEV: The given device is not mounted.
 *     ENOENT: None of the file names references the given inode.
 *     EBUSY: Some but not all links to the file were found in the
 *         list of file names.
 *     ENOMEM: Memory allocation failure.
 *     EEXIST: At least one of the target files exists and would have to
 *         be overwritten. Only returned if checkoverwrite is true.
 *     EMLINK: The target file has more than one hardlink and this
 *         hardlink will be broken by the commit. Only returned if
 *         checkoverwrite is true.
 */
int
pgfile_check(uint64_t dev, uint64_t ino, const char *namearr[],
    int checkoverwrite)
{
	struct pgmount		*mnt = pgmounts_find(dev);
	int			 totallinks = 0, foundlinks = 0;
	int			 i;
	struct pgfile_list	 list;
	struct stat		 statbuf;

	/* Device is currently not mounted. */
	if (!mnt)
		return -EXDEV;
	if (pgfile_normalize_file_list(&list, namearr) < 0)
		return -ENOMEM;
	for (i=0; i<list.listlen; ++i) {
		int		 nlinks, off;
		char		*targetname, *last, ch;

		nlinks = pgfile_validate_one_name(dev, ino, mnt->dirfd,
		    list.list[i]);
		if (nlinks == 0)
			continue;
		totallinks = nlinks;
		foundlinks++;
		if (!checkoverwrite)
			continue;
		off = 0;
		while(list.list[i][off] == '/')
			off++;
		targetname = strdup(list.list[i]+off);
		if (targetname == NULL) {
			pgfile_free_list(&list);
			return -ENOMEM;
		}
		last = strrchr(targetname, '/');
		if (last)
			last++;
		else
			last = targetname;
		if (sscanf(last, ".plgr.%*x%c%n", &ch, &off) < 1) {
			free(targetname);
			continue;
		}
		memmove(last, last+off, strlen(last+off)+1);
		nlinks = fstatat(mnt->dirfd, targetname, &statbuf,
		    AT_SYMLINK_NOFOLLOW);
		free(targetname);
		if (nlinks < 0)
			continue;
		/* The target file exists. This is alway an error. */
		pgfile_free_list(&list);
		if (S_ISDIR(statbuf.st_mode) || statbuf.st_nlink == 1)
			return -EEXIST;
		else
			return -EMLINK;
	}
	pgfile_free_list(&list);
	if (totallinks == 0)
		return -ENOENT;
	if (totallinks > foundlinks)
		return -EBUSY;
	return 0;
}
Пример #29
0
int main(void) {
    /* dummy variables to prevent null warnings */
    char path[] = "";
    char mode[] = "";
    char buf[1];
    struct stat st;
    struct statfs stfs;
    struct statvfs stvfs;
    fpos_t fpos;
    off_t off;
    struct rlimit rlim;
    glob_t glb;
    int result;
    DIR* dir;
    struct dirent direntry;
    struct dirent* pdirentry;
    struct dirent** ppdirentry;
    const struct dirent *pconstdirentry;
    dir = 0;
    result = alphasort(&pconstdirentry, &pconstdirentry);
    creat(path, 0);
    fgetpos(0, &fpos);
    fopen(path, mode);
    freopen(path, mode, 0);
    fseeko(0, 0, 0);
    fsetpos(0, &fpos);
    fstat(0, &st);
    fstatat(0, path, &st, 0);
    fstatfs(0, &stfs);
    fstatvfs(0, &stvfs);
    ftello(0);
    ftruncate(0, 0);
    ftw(path, ftw_stub, 0);
    getdirentries(0, buf, 0, &off);
    getrlimit(0, &rlim);
    glob(path, 0, glob_stub, &glb);
    lockf(0, 0, 0);
    lseek(0, 0, 0);
    lstat(path, &st);
    mkostemp(path, 0);
    mkstemp(path);
    mmap(buf, 0, 0, 0, 0, 0);
    nftw(path, nftw_stub, 0, 0);
    open(path, 0);
    open(path, 0, 0);
    openat(0, path, 0);
    openat(0, path, 0, 0);
    posix_fadvise(0, 0, 0, 0);
    posix_fallocate(0, 0, 0);
    pread(0, buf, 0, 0);
    pwrite(0, buf, 0, 0);
    readdir(dir);
    readdir_r(dir, &direntry, &pdirentry);
    scandir(path, &ppdirentry, scandir_filter_stub, scandir_compare_stub);
    sendfile(0, 0, &off, 0);
    setrlimit(0, &rlim);
    stat(path, &st);
    statfs(path, &stfs);
    statvfs(path, &stvfs);
    tmpfile();
    truncate(path, 0);
    result = versionsort(&pconstdirentry, &pconstdirentry);
    return result;
}
bool sc_cgroup_freezer_occupied(const char *snap_name)
{
	// Format the name of the cgroup hierarchy.
	char buf[PATH_MAX] = { 0 };
	sc_must_snprintf(buf, sizeof buf, "snap.%s", snap_name);

	// Open the freezer cgroup directory.
	int cgroup_fd SC_CLEANUP(sc_cleanup_close) = -1;
	cgroup_fd = open(freezer_cgroup_dir,
			 O_PATH | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
	if (cgroup_fd < 0) {
		die("cannot open freezer cgroup (%s)", freezer_cgroup_dir);
	}
	// Open the proc directory.
	int proc_fd SC_CLEANUP(sc_cleanup_close) = -1;
	proc_fd = open("/proc", O_PATH | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
	if (proc_fd < 0) {
		die("cannot open /proc");
	}
	// Open the hierarchy directory for the given snap.
	int hierarchy_fd SC_CLEANUP(sc_cleanup_close) = -1;
	hierarchy_fd = openat(cgroup_fd, buf,
			      O_PATH | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
	if (hierarchy_fd < 0) {
		if (errno == ENOENT) {
			return false;
		}
		die("cannot open freezer cgroup hierarchy for snap %s",
		    snap_name);
	}
	// Open the "cgroup.procs" file. Alternatively we could open the "tasks"
	// file and see per-thread data but we don't need that.
	int cgroup_procs_fd SC_CLEANUP(sc_cleanup_close) = -1;
	cgroup_procs_fd = openat(hierarchy_fd, "cgroup.procs",
				 O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
	if (cgroup_procs_fd < 0) {
		die("cannot open cgroup.procs file for freezer cgroup hierarchy for snap %s", snap_name);
	}

	FILE *cgroup_procs SC_CLEANUP(sc_cleanup_file) = NULL;
	cgroup_procs = fdopen(cgroup_procs_fd, "r");
	if (cgroup_procs == NULL) {
		die("cannot convert tasks file descriptor to FILE");
	}
	cgroup_procs_fd = -1;	// cgroup_procs_fd will now be closed by fclose.

	char *line_buf SC_CLEANUP(sc_cleanup_string) = NULL;
	size_t line_buf_size = 0;
	ssize_t num_read;
	struct stat statbuf;
	do {
		num_read = getline(&line_buf, &line_buf_size, cgroup_procs);
		if (num_read < 0 && errno != 0) {
			die("cannot read next PID belonging to snap %s",
			    snap_name);
		}
		if (num_read <= 0) {
			break;
		} else {
			if (line_buf[num_read - 1] == '\n') {
				line_buf[num_read - 1] = '\0';
			} else {
				die("could not find newline in cgroup.procs");
			}
		}
		debug("found process id: %s\n", line_buf);

		if (fstatat(proc_fd, line_buf, &statbuf, AT_SYMLINK_NOFOLLOW) <
		    0) {
			// The process may have died already.
			if (errno != ENOENT) {
				die("cannot stat /proc/%s", line_buf);
			}
		}
		debug("found process %s belonging to user %d",
		      line_buf, statbuf.st_uid);
		return true;
	} while (num_read > 0);

	return false;
}