rem: *cwd_state = XMALLOC (struct saved_cwd, 1); if (save_cwd (*cwd_state)) return RM_ERROR; AD_push_initial (ds, *cwd_state);
add: *cwd_state = xmalloc (sizeof **cwd_state);  if (save_cwd (&(*cwd_state)->saved_cwd) != 0) { (*cwd_state)->saved_errno = errno; assert (errno != 0);   (*cwd_state)->saved_cwd.name = xstrdup ("/"); } else (*cwd_state)->saved_errno = 0;  AD_push_initial (ds);
context: remove_dir (Dirstack_state *ds, char const *dir, struct saved_cwd **cwd_state,	    struct rm_options const *x){  enum RM_status status;  struct stat dir_sb;  /* Save any errno (from caller's failed remove_entry call), in case DIR     is not a directory, so that we can give a reasonable diagnostic.  */  int saved_errno = errno;  if (*cwd_state == NULL)    {      *cwd_state = XMALLOC (struct saved_cwd, 1);      if (save_cwd (*cwd_state))	return RM_ERROR;      AD_push_initial (ds, *cwd_state);      AD_INIT_OTHER_MEMBERS ();    }  /* There is a race condition in that an attacker could replace the nonempty     directory, DIR, with a symlink between the preceding call to rmdir     (in our caller) and the chdir below.  However, the following lstat,     along with the `stat (".",...' and dev/ino comparison in AD_push     ensure that we detect it and fail.  */  if (lstat (dir, &dir_sb))    {      error (0, errno,	     _("cannot lstat %s"), quote (full_filename (dir)));      return RM_ERROR;    }  if (chdir (dir))    {      if (! S_ISDIR (dir_sb.st_mode))	{	  /* This happens on Linux-2.4.18 when a non-privileged user tries	     to delete a file that is owned by another user in a directory	     like /tmp that has the S_ISVTX flag set.  */	  assert (saved_errno == EPERM);	  error (0, saved_errno,		 _("cannot remove %s"), quote (full_filename (dir)));	}      else	{	  error (0, errno,		 _("cannot chdir from %s to %s"),		 quote_n (0, full_filename (".")), quote_n (1, dir));	}      return RM_ERROR;    }  AD_push (ds, dir, &dir_sb);  AD_INIT_OTHER_MEMBERS ();  status = RM_OK;  while (1)    {      char *subdir = NULL;      struct stat subdir_sb;      enum RM_status tmp_status = remove_cwd_entries (ds,						      &subdir, &subdir_sb, x);      if (tmp_status != RM_OK)	{	  UPDATE_STATUS (status, tmp_status);	  AD_mark_current_as_unremovable (ds);	}      if (subdir)	{	  AD_push (ds, subdir, &subdir_sb);	  AD_INIT_OTHER_MEMBERS ();	  free (subdir);	  continue;	}      /* Execution reaches this point when we've removed the last	 removable entry from the current directory.  */      {	char *d = AD_pop_and_chdir (ds);	/* Try to remove D only if remove_cwd_entries succeeded.  */	if (tmp_status == RM_OK)	  {	    /* This does a little more work than necessary when it actually	       prompts the user.  E.g., we already know that D is a directory	       and that it's almost certainly empty, yet we lstat it.	       But that's no big deal since we're interactive.  */	    Ternary is_dir;	    Ternary is_empty;	    enum RM_status s = prompt (ds, d, x, PA_REMOVE_DIR,				       &is_dir, &is_empty);	    if (s != RM_OK)	      {		free (d);		return s;	      }	    if (rmdir (d) == 0)	      {		if (x->verbose)		  printf (_("removed directory: %s\n"),			  quote (full_filename (d)));	      }	    else	      {		error (0, errno, _("cannot remove directory %s"),		       quote (full_filename (d)));		AD_mark_as_unremovable (ds, d);		status = RM_ERROR;		UPDATE_STATUS (AD_stack_top(ds)->status, status);	      }	  }	free (d);	if (AD_stack_height (ds) == 1)	  break;      }    }  return status;}