code: protected void checkInodeList(String user, List<String> groups, Mode.Bits bits, String path,
        List<InodeView> inodeList, boolean checkIsOwner) throws AccessControlException {
      int size = inodeList.size();
      Preconditions.checkArgument(size > 0,
          PreconditionMessage.EMPTY_FILE_INFO_LIST_FOR_PERMISSION_CHECK);
  
      // bypass checking permission for super user or super group of Alluxio file system.
      if (isPrivilegedUser(user, groups)) {
        return;
      }
  
      // traverses from root to the parent dir to all inodes included by this path are executable
      for (int i = 0; i < size - 1; i++) {
        checkInode(user, groups, inodeList.get(i), Mode.Bits.EXECUTE, path);
      }
  
      InodeView inode = inodeList.get(inodeList.size() - 1);
      if (checkIsOwner) {
        if (inode == null || user.equals(inode.getOwner())) {
          return;
        }
        throw new AccessControlException(ExceptionMessage.PERMISSION_DENIED
            .getMessage("user=" + user + " is not the owner of path=" + path));
      }
      checkInode(user, groups, inode, bits, path);
    }
docs: This method provides basic permission checking logic on a list of inodes. The input includes
  user and its group, requested action and inode list (by traversing the path). Then user,
  group, and the requested action will be evaluated on each of the inodes. It will return if
  check passed, and throw exception if check failed.
  
  @param user who requests access permission
  @param groups in which user belongs to
  @param bits bits that capture the action {@link Mode.Bits} by user
  @param path the path to check permission on
  @param inodeList file info list of all the inodes retrieved by traversing the path
  @param checkIsOwner indicates whether to check the user is the owner of the path
  @throws AccessControlException if permission checking fails