drill_parse_T_code(gerb_file_t *fd, drill_state_t *state,
			gerbv_image_t *image, ssize_t file_line)
{
    int tool_num;
    gboolean done = FALSE;
    int temp;
    double size;
    gerbv_drill_stats_t *stats = image->drill_stats;
    gerbv_aperture_t *apert;
    gchar *tmps;
    gchar *string;

    dprintf("---> entering %s()...\n", __FUNCTION__);

    /* Sneak a peek at what's hiding after the 'T'. Ugly fix for
       broken headers from Orcad, which is crap */
    temp = gerb_fgetc(fd);
    dprintf("  Found a char '%s' (0x%02x) after the T\n",
	    gerbv_escape_char(temp), temp);

    /* might be a tool tool change stop switch on/off*/
    if((temp == 'C') && ((fd->ptr + 2) < fd->datalen)){
    	if(gerb_fgetc(fd) == 'S'){
    	    if (gerb_fgetc(fd) == 'T' ){
    	  	fd->ptr -= 4;
    	  	tmps = get_line(fd++);
    	  	gerbv_stats_printf(stats->error_list, GERBV_MESSAGE_NOTE, -1,
			_("Tool change stop switch found \"%s\" "
			    "at line %ld in file \"%s\""),
			tmps, file_line, fd->filename);
	  	g_free (tmps);

	  	return -1;
	    }
	    gerb_ungetc(fd);
	}
	gerb_ungetc(fd);
    }

    if( !(isdigit(temp) != 0 || temp == '+' || temp =='-') ) {
	if(temp != EOF) {
	    gerbv_stats_printf(stats->error_list, GERBV_MESSAGE_ERROR, -1,
		   _("OrCAD bug: Junk text found in place of tool definition"));
	    tmps = get_line(fd);
	    gerbv_stats_printf(stats->error_list, GERBV_MESSAGE_WARNING, -1,
		    _("Junk text \"%s\" "
			"at line %ld in file \"%s\""),
		    tmps, file_line, fd->filename);
	    g_free (tmps);
	    gerbv_stats_printf(stats->error_list, GERBV_MESSAGE_WARNING, -1,
				  _("Ignoring junk text"));
	}
	return -1;
    }
    gerb_ungetc(fd);

    tool_num = (int) gerb_fgetint(fd, NULL);
    dprintf ("  Handling tool T%d at line %ld\n", tool_num, file_line);

    if (tool_num == 0)
	return tool_num; /* T00 is a command to unload the drill */

    if (tool_num < TOOL_MIN || tool_num >= TOOL_MAX) {
	gerbv_stats_printf(stats->error_list, GERBV_MESSAGE_ERROR, -1,
		_("Out of bounds drill number %d "
		    "at line %ld in file \"%s\""),
		tool_num, file_line, fd->filename);
	return -1;
    }

    /* Set the current tool to the correct one */
    state->current_tool = tool_num;
    apert = image->aperture[tool_num];

    /* Check for a size definition */
    temp = gerb_fgetc(fd);

    /* This bit of code looks for a tool definition by scanning for strings
     * of form TxxC, TxxF, TxxS.  */
    while (!done) {
	switch((char)temp) {
	case 'C':
	    size = read_double(fd, state->header_number_format, GERBV_OMIT_ZEROS_TRAILING, state->decimals);
	    dprintf ("  Read a size of %g\n", size);

	    if (state->unit == GERBV_UNIT_MM) {
		size /= 25.4;
	    } else if(size >= 4.0) {
		/* If the drill size is >= 4 inches, assume that this
		   must be wrong and that the units are mils.
		   The limit being 4 inches is because the smallest drill
		   I've ever seen used is 0,3mm(about 12mil). Half of that
		   seemed a bit too small a margin, so a third it is */

		gerbv_stats_printf(stats->error_list, GERBV_MESSAGE_ERROR, -1,
			_("Read a drill of diameter %g inches "
			    "at line %ld in file \"%s\""),
			    size, file_line, fd->filename);
		gerbv_stats_printf(stats->error_list, GERBV_MESSAGE_WARNING, -1,
			_("Assuming units are mils"));
		size /= 1000.0;
	    }

	    if (size <= 0. || size >= 10000.) {
		gerbv_stats_printf(stats->error_list, GERBV_MESSAGE_ERROR, -1,
			_("Unreasonable drill size %g found for drill %d "
			    "at line %ld in file \"%s\""),
			    size, tool_num, file_line, fd->filename);
	    } else {
		if (apert != NULL) {
		    /* allow a redefine of a tool only if the new definition is exactly the same.
		     * This avoid lots of spurious complaints with the output of some cad
		     * tools while keeping complaints if there is a true problem
		     */
		    if (apert->parameter[0] != size
		    ||  apert->type != GERBV_APTYPE_CIRCLE
		    ||  apert->nuf_parameters != 1
		    ||  apert->unit != GERBV_UNIT_INCH) {

			gerbv_stats_printf(stats->error_list,
				GERBV_MESSAGE_ERROR, -1,
				_("Found redefinition of drill %d "
				"at line %ld in file \"%s\""),
				tool_num, file_line, fd->filename);
		    }
		} else {
		    apert = image->aperture[tool_num] =
						g_new0(gerbv_aperture_t, 1);
		    if (apert == NULL)
			GERB_FATAL_ERROR("malloc tool failed in %s()",
					__FUNCTION__);

		    /* There's really no way of knowing what unit the tools
		       are defined in without sneaking a peek in the rest of
		       the file first. That's done in drill_guess_format() */
		    apert->parameter[0] = size;
		    apert->type = GERBV_APTYPE_CIRCLE;
		    apert->nuf_parameters = 1;
		    apert->unit = GERBV_UNIT_INCH;
		}
	    }

	    /* Add the tool whose definition we just found into the list
	     * of tools for this layer used to generate statistics. */
	    stats = image->drill_stats;
	    string = g_strdup_printf("%s", (state->unit == GERBV_UNIT_MM ? _("mm") : _("inch")));
	    drill_stats_add_to_drill_list(stats->drill_list,
					  tool_num,
					  state->unit == GERBV_UNIT_MM ? size*25.4 : size,
					  string);
	    g_free(string);
	    break;

	case 'F':
	case 'S' :
	    /* Silently ignored. They're not important. */
	    gerb_fgetint(fd, NULL);
	    break;

	default:
	    /* Stop when finding anything but what's expected
	       (and put it back) */
	    gerb_ungetc(fd);
	    done = TRUE;
	    break;
	}  /* switch((char)temp) */

	temp = gerb_fgetc(fd);
	if (EOF == temp) {
	    gerbv_stats_printf(stats->error_list, GERBV_MESSAGE_ERROR, -1,
		    _("Unexpected EOF encountered in header of "
			"drill file \"%s\""), fd->filename);

	/* Restore new line character for processing */
	if ('\n' == temp || '\r' == temp)
	    gerb_ungetc(fd);
	}
    }   /* while(!done) */  /* Done looking at tool definitions */

    /* Catch the tools that aren't defined.
       This isn't strictly a good thing, but at least something is shown */
    if (apert == NULL) {
        double dia;

	apert = image->aperture[tool_num] = g_new0(gerbv_aperture_t, 1);
	if (apert == NULL)
	    GERB_FATAL_ERROR("malloc tool failed in %s()", __FUNCTION__);

        /* See if we have the tool table */
        dia = gerbv_get_tool_diameter(tool_num);
        if (dia <= 0) {
            /*
             * There is no tool. So go out and make some.
             * This size calculation is, of course, totally bogus.
             */
            dia = (double)(16 + 8 * tool_num) / 1000;
            /*
             * Oooh, this is sooo ugly. But some CAD systems seem to always
             * use T00 at the end of the file while others that don't have
             * tool definitions inside the file never seem to use T00 at all.
             */
            if (tool_num != 0) {
		gerbv_stats_printf(stats->error_list, GERBV_MESSAGE_ERROR, -1,
			_("Tool %02d used without being defined "
			    "at line %ld in file \"%s\""),
			tool_num, file_line, fd->filename);
		gerbv_stats_printf(stats->error_list, GERBV_MESSAGE_WARNING, -1,
			_("Setting a default size of %g\""), dia);
            }
	}

	apert->type = GERBV_APTYPE_CIRCLE;
	apert->nuf_parameters = 1;
	apert->parameter[0] = dia;

	/* Add the tool whose definition we just found into the list
	 * of tools for this layer used to generate statistics. */
	if (tool_num != 0) {  /* Only add non-zero tool nums.
			       * Zero = unload command. */
	    stats = image->drill_stats;
	    string = g_strdup_printf("%s",
				     (state->unit == GERBV_UNIT_MM ? _("mm") : _("inch")));
	    drill_stats_add_to_drill_list(stats->drill_list,
					  tool_num,
					  state->unit == GERBV_UNIT_MM ? dia*25.4 : dia,
					  string);
	    g_free(string);
	}
    } /* if(image->aperture[tool_num] == NULL) */

    dprintf("<----  ...leaving %s()\n", __FUNCTION__);

    return tool_num;
} /* drill_parse_T_code() */


unsigned char * InstanceKlass::get_cached_class_file_bytes() {
  return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file);
}


void InstanceKlass::set_initialization_state_and_notify(ClassState state, TRAPS) {
  Handle h_init_lock(THREAD, init_lock());
  if (h_init_lock() != NULL) {
    ObjectLocker ol(h_init_lock, THREAD);
    set_init_thread(NULL); // reset _init_thread before changing _init_state
    set_init_state(state);
    fence_and_clear_init_lock();
    ol.notify_all(CHECK);
  } else {
    assert(h_init_lock() != NULL, "The initialization state should never be set twice");
    set_init_thread(NULL); // reset _init_thread before changing _init_state
    set_init_state(state);
  }
}


static bool method_matches(const Method* m,
                           const Symbol* signature,
                           bool skipping_overpass,
                           bool skipping_static,
                           bool skipping_private) {
  return ((m->signature() == signature) &&
    (!skipping_overpass || !m->is_overpass()) &&
    (!skipping_static || !m->is_static()) &&
    (!skipping_private || !m->is_private()));
}


Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, bool is_static, fieldDescriptor* fd) const {
  // search order according to newest JVM spec (5.4.3.2, p.167).
  // 1) search for field in current klass
  if (find_local_field(name, sig, fd)) {
    if (fd->is_static() == is_static) return const_cast<InstanceKlass*>(this);
  }
  // 2) search for field recursively in direct superinterfaces
  if (is_static) {
    Klass* intf = find_interface_field(name, sig, fd);
    if (intf != NULL) return intf;
  }
  // 3) apply field lookup recursively if superclass exists
  { Klass* supr = super();
    if (supr != NULL) return InstanceKlass::cast(supr)->find_field(name, sig, is_static, fd);
  }
  // 4) otherwise field lookup fails
  return NULL;
}


Method* InstanceKlass::find_method_impl(const Array<Method*>* methods,
                                        const Symbol* name,
                                        const Symbol* signature,
                                        OverpassLookupMode overpass_mode,
                                        StaticLookupMode static_mode,
                                        PrivateLookupMode private_mode) {
  int hit = find_method_index(methods, name, signature, overpass_mode, static_mode, private_mode);
  return hit >= 0 ? methods->at(hit): NULL;
}


void InstanceKlass::link_class(TRAPS) {
  assert(is_loaded(), "must be loaded");
  if (!is_linked()) {
    link_class_impl(CHECK);
  }
}


void InstanceKlass::link_methods(TRAPS) {
  int len = methods()->length();
  for (int i = len-1; i >= 0; i--) {
    methodHandle m(THREAD, methods()->at(i));

    // Set up method entry points for compiler and interpreter    .
    m->link_method(m, CHECK);
  }
}


void InstanceKlass::remove_java_mirror() {
  Klass::remove_java_mirror();

  // do array classes also.
  if (array_klasses() != NULL) {
    array_klasses()->remove_java_mirror();
  }
}


nmethod* InstanceKlass::lookup_osr_nmethod(const Method* m, int bci, int comp_level, bool match_level) const {
  MutexLocker ml(CompiledMethod_lock->owned_by_self() ? NULL : CompiledMethod_lock,
                 Mutex::_no_safepoint_check_flag);
  nmethod* osr = osr_nmethods_head();
  nmethod* best = NULL;
  while (osr != NULL) {
    assert(osr->is_osr_method(), "wrong kind of nmethod found in chain");
    // There can be a time when a c1 osr method exists but we are waiting
    // for a c2 version. When c2 completes its osr nmethod we will trash
    // the c1 version and only be able to find the c2 version. However
    // while we overflow in the c1 code at back branches we don't want to
    // try and switch to the same code as we are already running

    if (osr->method() == m &&
        (bci == InvocationEntryBci || osr->osr_entry_bci() == bci)) {
      if (match_level) {
        if (osr->comp_level() == comp_level) {
          // Found a match - return it.
          return osr;
        }
      } else {
        if (best == NULL || (osr->comp_level() > best->comp_level())) {
          if (osr->comp_level() == CompilationPolicy::highest_compile_level()) {
            // Found the best possible - return it.
            return osr;
          }
          best = osr;
        }
      }
    }
    osr = osr->osr_link();
  }

  assert(match_level == false || best == NULL, "shouldn't pick up anything if match_level is set");
  if (best != NULL && best->comp_level() >= comp_level) {
    return best;
  }
  return NULL;
}


static inline bool is_class_loader(const Symbol* class_name,
                                   const ClassFileParser& parser) {
  assert(class_name != NULL, "invariant");

  if (class_name == vmSymbols::java_lang_ClassLoader()) {
    return true;
  }

  if (vmClasses::ClassLoader_klass_loaded()) {
    const Klass* const super_klass = parser.super_klass();
    if (super_klass != NULL) {
      if (super_klass->is_subtype_of(vmClasses::ClassLoader_klass())) {
        return true;
      }
    }
  }
  return false;
}


  template <class T> void do_oop_work(T* p) {
    oop obj = RawAccess<>::oop_load(p);
    if (!oopDesc::is_oop_or_null(obj)) {
      tty->print_cr("Failed: " PTR_FORMAT " -> " PTR_FORMAT, p2i(p), p2i(obj));
      Universe::print_on(tty);
      guarantee(false, "boom");
    }
  }


InstanceKlass* InstanceKlass::implementor() const {
  InstanceKlass* volatile* ik = adr_implementor();
  if (ik == NULL) {
    return NULL;
  } else {
    // This load races with inserts, and therefore needs acquire.
    InstanceKlass* ikls = Atomic::load_acquire(ik);
    if (ikls != NULL && !ikls->is_loader_alive()) {
      return NULL;  // don't return unloaded class
    } else {
      return ikls;
    }
  }
}


void ClassHierarchyIterator::next() {
  assert(_current != NULL, "required");
  if (_visit_subclasses && _current->subklass() != NULL) {
    _current = _current->subklass();
    return; // visit next subclass
  }
  _visit_subclasses = true; // reset
  while (_current->next_sibling() == NULL && _current != _root) {
    _current = _current->superklass(); // backtrack; no more sibling subclasses left
  }
  if (_current == _root) {
    // Iteration is over (back at root after backtracking). Invalidate the iterator.
    _current = NULL;
    return;
  }
  _current = _current->next_sibling();
  return; // visit next sibling subclass
}


void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data,
                                       Array<Method*>* methods) {
  if (methods != NULL && methods != Universe::the_empty_method_array() &&
      !methods->is_shared()) {
    for (int i = 0; i < methods->length(); i++) {
      Method* method = methods->at(i);
      if (method == NULL) continue;  // maybe null if error processing
      // Only want to delete methods that are not executing for RedefineClasses.
      // The previous version will point to them so they're not totally dangling
      assert (!method->on_stack(), "shouldn't be called with methods on stack");
      MetadataFactory::free_metadata(loader_data, method);
    }
    MetadataFactory::free_array<Method*>(loader_data, methods);
  }
}


bool InstanceKlass::is_same_class_package(oop other_class_loader,
                                          const Symbol* other_class_name) const {
  if (class_loader() != other_class_loader) {
    return false;
  }
  if (name()->fast_compare(other_class_name) == 0) {
     return true;
  }

  {
    ResourceMark rm;

    bool bad_class_name = false;
    TempNewSymbol other_pkg = ClassLoader::package_from_class_name(other_class_name, &bad_class_name);
    if (bad_class_name) {
      return false;
    }
    // Check that package_from_class_name() returns NULL, not "", if there is no package.
    assert(other_pkg == NULL || other_pkg->utf8_length() > 0, "package name is empty string");

    const Symbol* const this_package_name =
      this->package() != NULL ? this->package()->name() : NULL;

    if (this_package_name == NULL || other_pkg == NULL) {
      // One of the two doesn't have a package.  Only return true if the other
      // one also doesn't have a package.
      return this_package_name == other_pkg;
    }

    // Check if package is identical
    return this_package_name->fast_compare(other_pkg) == 0;
  }
}


void InstanceKlass::purge_previous_version_list() {
  assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
  assert(has_been_redefined(), "Should only be called for main class");

  // Quick exit.
  if (previous_versions() == NULL) {
    return;
  }

  // This klass has previous versions so see what we can cleanup
  // while it is safe to do so.

  int deleted_count = 0;    // leave debugging breadcrumbs
  int live_count = 0;
  ClassLoaderData* loader_data = class_loader_data();
  assert(loader_data != NULL, "should never be null");

  ResourceMark rm;
  log_trace(redefine, class, iklass, purge)("%s: previous versions", external_name());

  // previous versions are linked together through the InstanceKlass
  InstanceKlass* pv_node = previous_versions();
  InstanceKlass* last = this;
  int version = 0;

  // check the previous versions list
  for (; pv_node != NULL; ) {

    ConstantPool* pvcp = pv_node->constants();
    assert(pvcp != NULL, "cp ref was unexpectedly cleared");

    if (!pvcp->on_stack()) {
      // If the constant pool isn't on stack, none of the methods
      // are executing.  Unlink this previous_version.
      // The previous version InstanceKlass is on the ClassLoaderData deallocate list
      // so will be deallocated during the next phase of class unloading.
      log_trace(redefine, class, iklass, purge)
        ("previous version " INTPTR_FORMAT " is dead.", p2i(pv_node));
      // For debugging purposes.
      pv_node->set_is_scratch_class();
      // Unlink from previous version list.
      assert(pv_node->class_loader_data() == loader_data, "wrong loader_data");
      InstanceKlass* next = pv_node->previous_versions();
      pv_node->link_previous_versions(NULL);   // point next to NULL
      last->link_previous_versions(next);
      // Add to the deallocate list after unlinking
      loader_data->add_to_deallocate_list(pv_node);
      pv_node = next;
      deleted_count++;
      version++;
      continue;
    } else {
      log_trace(redefine, class, iklass, purge)("previous version " INTPTR_FORMAT " is alive", p2i(pv_node));
      assert(pvcp->pool_holder() != NULL, "Constant pool with no holder");
      guarantee (!loader_data->is_unloading(), "unloaded classes can't be on the stack");
      live_count++;
      // found a previous version for next time we do class unloading
      _has_previous_versions = true;
    }

    // At least one method is live in this previous version.
    // Reset dead EMCP methods not to get breakpoints.
    // All methods are deallocated when all of the methods for this class are no
    // longer running.
    Array<Method*>* method_refs = pv_node->methods();
    if (method_refs != NULL) {
      log_trace(redefine, class, iklass, purge)("previous methods length=%d", method_refs->length());
      for (int j = 0; j < method_refs->length(); j++) {
        Method* method = method_refs->at(j);

        if (!method->on_stack()) {
          // no breakpoints for non-running methods
          if (method->is_running_emcp()) {
            method->set_running_emcp(false);
          }
        } else {
          assert (method->is_obsolete() || method->is_running_emcp(),
                  "emcp method cannot run after emcp bit is cleared");
          log_trace(redefine, class, iklass, purge)
            ("purge: %s(%s): prev method @%d in version @%d is alive",
             method->name()->as_C_string(), method->signature()->as_C_string(), j, version);
        }
      }
    }
    // next previous version
    last = pv_node;
    pv_node = pv_node->previous_versions();
    version++;
  }
  log_trace(redefine, class, iklass, purge)
    ("previous version stats: live=%d, deleted=%d", live_count, deleted_count);
}


void InstanceKlass::initialize_impl(TRAPS) {
  HandleMark hm(THREAD);

  // Make sure klass is linked (verified) before initialization
  // A class could already be verified, since it has been reflected upon.
  link_class(CHECK);

  DTRACE_CLASSINIT_PROBE(required, -1);

  bool wait = false;

  // refer to the JVM book page 47 for description of steps
  // Step 1
  {
    Handle h_init_lock(THREAD, init_lock());
    ObjectLocker ol(h_init_lock, THREAD, h_init_lock() != NULL);

    Thread *self = THREAD; // it's passed the current thread

    // Step 2
    // If we were to use wait() instead of waitInterruptibly() then
    // we might end up throwing IE from link/symbol resolution sites
    // that aren't expected to throw.  This would wreak havoc.  See 6320309.
    while(is_being_initialized() && !is_reentrant_initialization(self)) {
        wait = true;
      ol.waitUninterruptibly(CHECK);
    }

    // Step 3
    if (is_being_initialized() && is_reentrant_initialization(self)) {
      DTRACE_CLASSINIT_PROBE_WAIT(recursive, -1, wait);
      return;
    }

    // Step 4
    if (is_initialized()) {
      DTRACE_CLASSINIT_PROBE_WAIT(concurrent, -1, wait);
      return;
    }

    // Step 5
    if (is_in_error_state()) {
      DTRACE_CLASSINIT_PROBE_WAIT(erroneous, -1, wait);
      ResourceMark rm(THREAD);
      const char* desc = "Could not initialize class ";
      const char* className = external_name();
      size_t msglen = strlen(desc) + strlen(className) + 1;
      char* message = NEW_RESOURCE_ARRAY(char, msglen);
      if (NULL == message) {
        // Out of memory: can't create detailed error message
          THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className);
      } else {
        jio_snprintf(message, msglen, "%s%s", desc, className);
          THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), message);
      }
    }

    // Step 6
    set_init_state(being_initialized);
    set_init_thread(self);
  }

  // Step 7
  // Next, if C is a class rather than an interface, initialize it's super class and super
  // interfaces.
  if (!is_interface()) {
    Klass* super_klass = super();
    if (super_klass != NULL && super_klass->should_be_initialized()) {
      super_klass->initialize(THREAD);
    }
    // If C implements any interface that declares a non-static, concrete method,
    // the initialization of C triggers initialization of its super interfaces.
    // Only need to recurse if has_nonstatic_concrete_methods which includes declaring and
    // having a superinterface that declares, non-static, concrete methods
    if (!HAS_PENDING_EXCEPTION && has_nonstatic_concrete_methods()) {
      initialize_super_interfaces(THREAD);
    }

    // If any exceptions, complete abruptly, throwing the same exception as above.
    if (HAS_PENDING_EXCEPTION) {
      Handle e(THREAD, PENDING_EXCEPTION);
      CLEAR_PENDING_EXCEPTION;
      {
        EXCEPTION_MARK;
        // Locks object, set state, and notify all waiting threads
        set_initialization_state_and_notify(initialization_error, THREAD);
        CLEAR_PENDING_EXCEPTION;
      }
      DTRACE_CLASSINIT_PROBE_WAIT(super__failed, -1, wait);
      THROW_OOP(e());
    }
  }

  // Look for aot compiled methods for this klass, including class initializer.
  AOTLoader::load_for_klass(this, THREAD);

  // Step 8
  {
    assert(THREAD->is_Java_thread(), "non-JavaThread in initialize_impl");
    JavaThread* jt = (JavaThread*)THREAD;
    DTRACE_CLASSINIT_PROBE_WAIT(clinit, -1, wait);
    // Timer includes any side effects of class initialization (resolution,
    // etc), but not recursive entry into call_class_initializer().
    PerfClassTraceTime timer(ClassLoader::perf_class_init_time(),
                             ClassLoader::perf_class_init_selftime(),
                             ClassLoader::perf_classes_inited(),
                             jt->get_thread_stat()->perf_recursion_counts_addr(),
                             jt->get_thread_stat()->perf_timers_addr(),
                             PerfClassTraceTime::CLASS_CLINIT);
    call_class_initializer(THREAD);
  }

  // Step 9
  if (!HAS_PENDING_EXCEPTION) {
    set_initialization_state_and_notify(fully_initialized, CHECK);
    {
      debug_only(vtable().verify(tty, true);)
    }
  }
  else {
    // Step 10 and 11
    Handle e(THREAD, PENDING_EXCEPTION);
    CLEAR_PENDING_EXCEPTION;
    // JVMTI has already reported the pending exception
    // JVMTI internal flag reset is needed in order to report ExceptionInInitializerError
    JvmtiExport::clear_detected_exception((JavaThread*)THREAD);
    {
      EXCEPTION_MARK;
      set_initialization_state_and_notify(initialization_error, THREAD);
      CLEAR_PENDING_EXCEPTION;   // ignore any exception thrown, class initialization error is thrown below
      // JVMTI has already reported the pending exception
      // JVMTI internal flag reset is needed in order to report ExceptionInInitializerError
      JvmtiExport::clear_detected_exception((JavaThread*)THREAD);
    }
    DTRACE_CLASSINIT_PROBE_WAIT(error, -1, wait);
    if (e->is_a(SystemDictionary::Error_klass())) {
      THROW_OOP(e());
    } else {
      JavaCallArguments args(e);
      THROW_ARG(vmSymbols::java_lang_ExceptionInInitializerError(),
                vmSymbols::throwable_void_signature(),
                &args);
    }
  }
  DTRACE_CLASSINIT_PROBE_WAIT(end, -1, wait);
}


bool InstanceKlass::remove_osr_nmethod(nmethod* n) {
  // This is a short non-blocking critical region, so the no safepoint check is ok.
  MutexLockerEx ml(OsrList_lock, Mutex::_no_safepoint_check_flag);
  assert(n->is_osr_method(), "wrong kind of nmethod");
  nmethod* last = NULL;
  nmethod* cur  = osr_nmethods_head();
  int max_level = CompLevel_none;  // Find the max comp level excluding n
  Method* m = n->method();
  // Search for match
  bool found = false;
  while(cur != NULL && cur != n) {
    if (TieredCompilation && m == cur->method()) {
      // Find max level before n
      max_level = MAX2(max_level, cur->comp_level());
    }
    last = cur;
    cur = cur->osr_link();
  }
  nmethod* next = NULL;
  if (cur == n) {
    found = true;
    next = cur->osr_link();
    if (last == NULL) {
      // Remove first element
      set_osr_nmethods_head(next);
    } else {
      last->set_osr_link(next);
    }
  }
  n->set_osr_link(NULL);
  if (TieredCompilation) {
    cur = next;
    while (cur != NULL) {
      // Find max level after n
      if (m == cur->method()) {
        max_level = MAX2(max_level, cur->comp_level());
      }
      cur = cur->osr_link();
    }
    m->set_highest_osr_comp_level(max_level);
  }
  return found;
}


void InstanceKlass::add_previous_version(InstanceKlass* scratch_class,
                                         int emcp_method_count) {
  assert(Thread::current()->is_VM_thread(),
         "only VMThread can add previous versions");

  ResourceMark rm;
  log_trace(redefine, class, iklass, add)
    ("adding previous version ref for %s, EMCP_cnt=%d", scratch_class->external_name(), emcp_method_count);

  // Clean out old previous versions for this class
  purge_previous_version_list();

  // Mark newly obsolete methods in remaining previous versions.  An EMCP method from
  // a previous redefinition may be made obsolete by this redefinition.
  Array<Method*>* old_methods = scratch_class->methods();
  mark_newly_obsolete_methods(old_methods, emcp_method_count);

  // If the constant pool for this previous version of the class
  // is not marked as being on the stack, then none of the methods
  // in this previous version of the class are on the stack so
  // we don't need to add this as a previous version.
  ConstantPool* cp_ref = scratch_class->constants();
  if (!cp_ref->on_stack()) {
    log_trace(redefine, class, iklass, add)("scratch class not added; no methods are running");
    // For debugging purposes.
    scratch_class->set_is_scratch_class();
    scratch_class->class_loader_data()->add_to_deallocate_list(scratch_class);
    return;
  }

  if (emcp_method_count != 0) {
    // At least one method is still running, check for EMCP methods
    for (int i = 0; i < old_methods->length(); i++) {
      Method* old_method = old_methods->at(i);
      if (!old_method->is_obsolete() && old_method->on_stack()) {
        // if EMCP method (not obsolete) is on the stack, mark as EMCP so that
        // we can add breakpoints for it.

        // We set the method->on_stack bit during safepoints for class redefinition
        // and use this bit to set the is_running_emcp bit.
        // After the safepoint, the on_stack bit is cleared and the running emcp
        // method may exit.   If so, we would set a breakpoint in a method that
        // is never reached, but this won't be noticeable to the programmer.
        old_method->set_running_emcp(true);
        log_trace(redefine, class, iklass, add)
          ("EMCP method %s is on_stack " INTPTR_FORMAT, old_method->name_and_sig_as_C_string(), p2i(old_method));
      } else if (!old_method->is_obsolete()) {
        log_trace(redefine, class, iklass, add)
          ("EMCP method %s is NOT on_stack " INTPTR_FORMAT, old_method->name_and_sig_as_C_string(), p2i(old_method));
      }
    }
  }

  // Add previous version if any methods are still running.
  // Set has_previous_version flag for processing during class unloading.
  _has_previous_versions = true;
  log_trace(redefine, class, iklass, add) ("scratch class added; one of its methods is on_stack.");
  assert(scratch_class->previous_versions() == NULL, "shouldn't have a previous version");
  scratch_class->link_previous_versions(previous_versions());
  link_previous_versions(scratch_class);
} // end add_previous_version()


bool InstanceKlass::has_nestmate_access_to(InstanceKlass* k, TRAPS) {

  assert(this != k, "this should be handled by higher-level code");

  // Per JVMS 5.4.4 we first resolve and validate the current class, then
  // the target class k. Resolution exceptions will be passed on by upper
  // layers. IncompatibleClassChangeErrors from membership validation failures
  // will also be passed through.

  Symbol* icce = vmSymbols::java_lang_IncompatibleClassChangeError();
  InstanceKlass* cur_host = nest_host(icce, CHECK_false);
  if (cur_host == NULL) {
    return false;
  }

  Klass* k_nest_host = k->nest_host(icce, CHECK_false);
  if (k_nest_host == NULL) {
    return false;
  }

  bool access = (cur_host == k_nest_host);

  if (log_is_enabled(Trace, class, nestmates)) {
    ResourceMark rm(THREAD);
    log_trace(class, nestmates)("Class %s does %shave nestmate access to %s",
                                this->external_name(),
                                access ? "" : "NOT ",
                                k->external_name());
  }

  return access;
}


oop InstanceKlass::init_lock() const {
  // return the init lock from the mirror
  oop lock = java_lang_Class::init_lock(java_mirror());
  // Prevent reordering with any access of initialization state
  OrderAccess::loadload();
  assert((oop)lock != NULL || !is_not_initialized(), // initialized or in_error state
         "only fully initialized state can have a null lock");
  return lock;
}


void InstanceKlass::array_klasses_do(void f(Klass* k, TRAPS), TRAPS) {
  if (array_klasses() != NULL)
    ArrayKlass::cast(array_klasses())->array_klasses_do(f, THREAD);
}


void InstanceKlass::release_C_heap_structures(InstanceKlass* ik) {
  // Clean up C heap
  ik->release_C_heap_structures();
  ik->constants()->release_C_heap_structures();
}


void InstanceKlass::remove_unshareable_info() {
  Klass::remove_unshareable_info();

  if (is_in_error_state()) {
    // Classes are attempted to link during dumping and may fail,
    // but these classes are still in the dictionary and class list in CLD.
    // Check in_error state first because in_error is > linked state, so
    // is_linked() is true.
    // If there's a linking error, there is nothing else to remove.
    return;
  }

  // Reset to the 'allocated' state to prevent any premature accessing to
  // a shared class at runtime while the class is still being loaded and
  // restored. A class' init_state is set to 'loaded' at runtime when it's
  // being added to class hierarchy (see SystemDictionary:::add_to_hierarchy()).
  _init_state = allocated;

  {
    MutexLocker ml(Compile_lock);
    init_implementor();
  }

  constants()->remove_unshareable_info();

  for (int i = 0; i < methods()->length(); i++) {
    Method* m = methods()->at(i);
    m->remove_unshareable_info();
  }

  // do array classes also.
  if (array_klasses() != NULL) {
    array_klasses()->remove_unshareable_info();
  }

  // These are not allocated from metaspace, but they should should all be empty
  // during dump time, so we don't need to worry about them in InstanceKlass::iterate().
  guarantee(_source_debug_extension == NULL, "must be");
  guarantee(_dep_context == DependencyContext::EMPTY, "must be");
  guarantee(_osr_nmethods_head == NULL, "must be");

#if INCLUDE_JVMTI
  guarantee(_breakpoints == NULL, "must be");
  guarantee(_previous_versions == NULL, "must be");
#endif

  _init_thread = NULL;
  _methods_jmethod_ids = NULL;
  _jni_ids = NULL;
  _oop_map_cache = NULL;
  // clear _nest_host to ensure re-load at runtime
  _nest_host = NULL;
}


void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) {
  Klass::metaspace_pointers_do(it);

  if (log_is_enabled(Trace, cds)) {
    ResourceMark rm;
    log_trace(cds)("Iter(InstanceKlass): %p (%s)", this, external_name());
  }

  it->push(&_annotations);
  it->push((Klass**)&_array_klasses);
  it->push(&_constants);
  it->push(&_inner_classes);
  it->push(&_array_name);
#if INCLUDE_JVMTI
  it->push(&_previous_versions);
#endif
  it->push(&_methods);
  it->push(&_default_methods);
  it->push(&_local_interfaces);
  it->push(&_transitive_interfaces);
  it->push(&_method_ordering);
  it->push(&_default_vtable_indices);

  // _fields might be written into by Rewriter::scan_method() -> fd.set_has_initialized_final_update()
  it->push(&_fields, MetaspaceClosure::_writable);

  if (itable_length() > 0) {
    itableOffsetEntry* ioe = (itableOffsetEntry*)start_of_itable();
    int method_table_offset_in_words = ioe->offset()/wordSize;
    int nof_interfaces = (method_table_offset_in_words - itable_offset_in_words())
                         / itableOffsetEntry::size();

    for (int i = 0; i < nof_interfaces; i ++, ioe ++) {
      if (ioe->interface_klass() != NULL) {
        it->push(ioe->interface_klass_addr());
        itableMethodEntry* ime = ioe->first_method_entry(this);
        int n = klassItable::method_count_for_interface(ioe->interface_klass());
        for (int index = 0; index < n; index ++) {
          it->push(ime[index].method_addr());
        }
      }
    }
  }

  it->push(&_nest_members);
}


LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) {
  LIR_Opr r = NULL;
  if (type == T_LONG) {
    r = LIR_OprFact::longConst(x);
  } else if (type == T_INT) {
    r = LIR_OprFact::intConst(x);
  } else {
    ShouldNotReachHere();
  }
  return r;
}


void LIRGenerator::do_Convert(Convert* x) {
#ifdef _LP64
  LIRItem value(x->value(), this);
  value.load_item();
  LIR_Opr input = value.result();
  LIR_Opr result = rlock(x);
  __ convert(x->op(), input, result);
  assert(result->is_virtual(), "result must be virtual register");
  set_result(x, result);
#else
  // flags that vary for the different operations and different SSE-settings
  bool fixed_input = false, fixed_result = false, round_result = false, needs_stub = false;

  switch (x->op()) {
    case Bytecodes::_i2l: // fall through
    case Bytecodes::_l2i: // fall through
    case Bytecodes::_i2b: // fall through
    case Bytecodes::_i2c: // fall through
    case Bytecodes::_i2s: fixed_input = false;       fixed_result = false;       round_result = false;      needs_stub = false; break;

    case Bytecodes::_f2d: fixed_input = UseSSE == 1; fixed_result = false;       round_result = false;      needs_stub = false; break;
    case Bytecodes::_d2f: fixed_input = false;       fixed_result = UseSSE == 1; round_result = UseSSE < 1; needs_stub = false; break;
    case Bytecodes::_i2f: fixed_input = false;       fixed_result = false;       round_result = UseSSE < 1; needs_stub = false; break;
    case Bytecodes::_i2d: fixed_input = false;       fixed_result = false;       round_result = false;      needs_stub = false; break;
    case Bytecodes::_f2i: fixed_input = false;       fixed_result = false;       round_result = false;      needs_stub = true;  break;
    case Bytecodes::_d2i: fixed_input = false;       fixed_result = false;       round_result = false;      needs_stub = true;  break;
    case Bytecodes::_l2f: fixed_input = false;       fixed_result = UseSSE >= 1; round_result = UseSSE < 1; needs_stub = false; break;
    case Bytecodes::_l2d: fixed_input = false;       fixed_result = UseSSE >= 2; round_result = UseSSE < 2; needs_stub = false; break;
    case Bytecodes::_f2l: fixed_input = true;        fixed_result = true;        round_result = false;      needs_stub = false; break;
    case Bytecodes::_d2l: fixed_input = true;        fixed_result = true;        round_result = false;      needs_stub = false; break;
    default: ShouldNotReachHere();
  }

  LIRItem value(x->value(), this);
  value.load_item();
  LIR_Opr input = value.result();
  LIR_Opr result = rlock(x);

  // arguments of lir_convert
  LIR_Opr conv_input = input;
  LIR_Opr conv_result = result;
  ConversionStub* stub = NULL;

  if (fixed_input) {
    conv_input = fixed_register_for(input->type());
    __ move(input, conv_input);
  }

  assert(fixed_result == false || round_result == false, "cannot set both");
  if (fixed_result) {
    conv_result = fixed_register_for(result->type());
  } else if (round_result) {
    result = new_register(result->type());
    set_vreg_flag(result, must_start_in_memory);
  }

  if (needs_stub) {
    stub = new ConversionStub(x->op(), conv_input, conv_result);
  }

  __ convert(x->op(), conv_input, conv_result, stub);

  if (result != conv_result) {
    __ move(conv_result, result);
  }

  assert(result->is_virtual(), "result must be virtual register");
  set_result(x, result);
#endif // _LP64
}


void LIRGenerator::do_MonitorExit(MonitorExit* x) {
  assert(x->is_pinned(),"");

  LIRItem obj(x->obj(), this);
  obj.dont_load_item();

  LIR_Opr lock = new_register(T_INT);
  LIR_Opr obj_temp = new_register(T_INT);
  set_no_result(x);
  monitor_exit(obj_temp, lock, syncTempOpr(), LIR_OprFact::illegalOpr, x->monitor_no());
}


void LIRGenerator::do_ArithmeticOp(ArithmeticOp* x) {
  // when an operand with use count 1 is the left operand, then it is
  // likely that no move for 2-operand-LIR-form is necessary
  if (x->is_commutative() && x->y()->as_Constant() == NULL && x->x()->use_count() > x->y()->use_count()) {
    x->swap_operands();
  }

  ValueTag tag = x->type()->tag();
  assert(x->x()->type()->tag() == tag && x->y()->type()->tag() == tag, "wrong parameters");
  switch (tag) {
    case floatTag:
    case doubleTag:  do_ArithmeticOp_FPU(x);  return;
    case longTag:    do_ArithmeticOp_Long(x); return;
    case intTag:     do_ArithmeticOp_Int(x);  return;
    default:         ShouldNotReachHere();    return;
  }
}


LIR_Opr LIRGenerator::exceptionOopOpr() { return FrameMap::rax_oop_opr; }


bool LIRGenerator::can_inline_as_constant(LIR_Const* c) const {
  if (c->type() == T_LONG) return false;
  return c->type() != T_OBJECT || c->as_jobject() == NULL;
}


LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) {
  bool is_oop = is_reference_type(type);
  LIR_Opr result = new_register(type);
  value.load_item();
  // Because we want a 2-arg form of xchg and xadd
  __ move(value.result(), result);
  assert(type == T_INT || is_oop LP64_ONLY( || type == T_LONG ), "unexpected type");
  __ xchg(addr, result, result, LIR_OprFact::illegalOpr);
  return result;
}


void LIRGenerator::do_NewObjectArray(NewObjectArray* x) {
  LIRItem length(x->length(), this);
  // in case of patching (i.e., object class is not yet loaded), we need to reexecute the instruction
  // and therefore provide the state before the parameters have been consumed
  CodeEmitInfo* patching_info = NULL;
  if (!x->klass()->is_loaded() || PatchALot) {
    patching_info =  state_for(x, x->state_before());
  }

  CodeEmitInfo* info = state_for(x, x->state());

  const LIR_Opr reg = result_register_for(x->type());
  LIR_Opr tmp1 = FrameMap::rcx_oop_opr;
  LIR_Opr tmp2 = FrameMap::rsi_oop_opr;
  LIR_Opr tmp3 = FrameMap::rdi_oop_opr;
  LIR_Opr tmp4 = reg;
  LIR_Opr klass_reg = FrameMap::rdx_metadata_opr;

  length.load_item_force(FrameMap::rbx_opr);
  LIR_Opr len = length.result();

  CodeStub* slow_path = new NewObjectArrayStub(klass_reg, len, reg, info);
  ciKlass* obj = (ciKlass*) ciObjArrayKlass::make(x->klass());
  if (obj == ciEnv::unloaded_ciobjarrayklass()) {
    BAILOUT("encountered unloaded_ciobjarrayklass due to out of memory error");
  }
  klass2reg_with_patching(klass_reg, obj, patching_info);
  __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, T_OBJECT, klass_reg, slow_path);

  LIR_Opr result = rlock_result(x);
  __ move(reg, result);
}


void LIRGenerator::do_Convert(Convert* x) {
  // flags that vary for the different operations and different SSE-settings
  bool fixed_input = false, fixed_result = false, round_result = false, needs_stub = false;

  switch (x->op()) {
    case Bytecodes::_i2l: // fall through
    case Bytecodes::_l2i: // fall through
    case Bytecodes::_i2b: // fall through
    case Bytecodes::_i2c: // fall through
    case Bytecodes::_i2s: fixed_input = false;       fixed_result = false;       round_result = false;      needs_stub = false; break;

    case Bytecodes::_f2d: fixed_input = UseSSE == 1; fixed_result = false;       round_result = false;      needs_stub = false; break;
    case Bytecodes::_d2f: fixed_input = false;       fixed_result = UseSSE == 1; round_result = UseSSE < 1; needs_stub = false; break;
    case Bytecodes::_i2f: fixed_input = false;       fixed_result = false;       round_result = UseSSE < 1; needs_stub = false; break;
    case Bytecodes::_i2d: fixed_input = false;       fixed_result = false;       round_result = false;      needs_stub = false; break;
    case Bytecodes::_f2i: fixed_input = false;       fixed_result = false;       round_result = false;      needs_stub = true;  break;
    case Bytecodes::_d2i: fixed_input = false;       fixed_result = false;       round_result = false;      needs_stub = true;  break;
    case Bytecodes::_l2f: fixed_input = false;       fixed_result = UseSSE >= 1; round_result = UseSSE < 1; needs_stub = false; break;
    case Bytecodes::_l2d: fixed_input = false;       fixed_result = UseSSE >= 2; round_result = UseSSE < 2; needs_stub = false; break;
    case Bytecodes::_f2l: fixed_input = true;        fixed_result = true;        round_result = false;      needs_stub = false; break;
    case Bytecodes::_d2l: fixed_input = true;        fixed_result = true;        round_result = false;      needs_stub = false; break;
    default: ShouldNotReachHere();
  }

  LIRItem value(x->value(), this);
  value.load_item();
  LIR_Opr input = value.result();
  LIR_Opr result = rlock(x);

  // arguments of lir_convert
  LIR_Opr conv_input = input;
  LIR_Opr conv_result = result;
  ConversionStub* stub = NULL;

  if (fixed_input) {
    conv_input = fixed_register_for(input->type());
    __ move(input, conv_input);
  }

  assert(fixed_result == false || round_result == false, "cannot set both");
  if (fixed_result) {
    conv_result = fixed_register_for(result->type());
  } else if (round_result) {
    result = new_register(result->type());
    set_vreg_flag(result, must_start_in_memory);
  }

  if (needs_stub) {
    stub = new ConversionStub(x->op(), conv_input, conv_result);
  }

  __ convert(x->op(), conv_input, conv_result, stub);

  if (result != conv_result) {
    __ move(conv_result, result);
  }

  assert(result->is_virtual(), "result must be virtual register");
  set_result(x, result);
}


bool sctp_verify_asconf(const struct sctp_association *asoc,
			struct sctp_chunk *chunk, bool addr_param_needed,
			struct sctp_paramhdr **errp)
{
	struct sctp_addip_chunk *addip;
	bool addr_param_seen = false;
	union sctp_params param;

	addip = (struct sctp_addip_chunk *)chunk->chunk_hdr;
	sctp_walk_params(param, addip, addip_hdr.params) {
		size_t length = ntohs(param.p->length);

		*errp = param.p;
		switch (param.p->type) {
		case SCTP_PARAM_ERR_CAUSE:
			break;
		case SCTP_PARAM_IPV4_ADDRESS:
			if (length != sizeof(struct sctp_ipv4addr_param))
				return false;
			/* ensure there is only one addr param and it's in the
			 * beginning of addip_hdr params, or we reject it.
			 */
			if (param.v != addip->addip_hdr.params)
				return false;
			addr_param_seen = true;
			break;
		case SCTP_PARAM_IPV6_ADDRESS:
			if (length != sizeof(struct sctp_ipv6addr_param))
				return false;
			if (param.v != addip->addip_hdr.params)
				return false;
			addr_param_seen = true;
			break;
		case SCTP_PARAM_ADD_IP:
		case SCTP_PARAM_DEL_IP:
		case SCTP_PARAM_SET_PRIMARY:
			/* In ASCONF chunks, these need to be first. */
			if (addr_param_needed && !addr_param_seen)
				return false;
			length = ntohs(param.addip->param_hdr.length);
			if (length < sizeof(struct sctp_addip_param) +
				     sizeof(**errp))
				return false;
			break;
		case SCTP_PARAM_SUCCESS_REPORT:
		case SCTP_PARAM_ADAPTATION_LAYER_IND:
			if (length != sizeof(struct sctp_addip_param))
				return false;
			break;
		default:
			/* This is unknown to us, reject! */
			return false;
		}
	}

	/* Remaining sanity checks. */
	if (addr_param_needed && !addr_param_seen)
		return false;
	if (!addr_param_needed && addr_param_seen)
		return false;
	if (param.v != chunk->chunk_end)
		return false;

	return true;
}


struct sctp_chunk *sctp_make_violation_max_retrans(
					const struct sctp_association *asoc,
					const struct sctp_chunk *chunk)
{
	static const char error[] = "Association exceeded its max_retrans count";
	size_t payload_len = sizeof(error) + sizeof(struct sctp_errhdr);
	struct sctp_chunk *retval;

	retval = sctp_make_abort(asoc, chunk, payload_len);
	if (!retval)
		goto nodata;

	sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, sizeof(error));
	sctp_addto_chunk(retval, sizeof(error), error);

nodata:
	return retval;
}


static void *wrap_nettle_mac_copy(const void *_ctx)
{
	const struct nettle_mac_ctx *ctx = _ctx;
	struct nettle_mac_ctx *new_ctx;
	ptrdiff_t off = (uint8_t *)ctx->ctx_ptr - (uint8_t *)(&ctx->ctx);

	new_ctx = gnutls_calloc(1, sizeof(struct nettle_mac_ctx));
	if (new_ctx == NULL)
		return NULL;

	memcpy(new_ctx, ctx, sizeof(*ctx));
	new_ctx->ctx_ptr = (uint8_t *)&new_ctx->ctx + off;

	return new_ctx;
}


static int wrap_nettle_hash_exists(gnutls_digest_algorithm_t algo)
{
	switch (algo) {
	case GNUTLS_DIG_MD5:
	case GNUTLS_DIG_SHA1:
	case GNUTLS_DIG_MD5_SHA1:

	case GNUTLS_DIG_SHA224:
	case GNUTLS_DIG_SHA256:
	case GNUTLS_DIG_SHA384:
	case GNUTLS_DIG_SHA512:

#ifdef NETTLE_SHA3_FIPS202
	case GNUTLS_DIG_SHA3_224:
	case GNUTLS_DIG_SHA3_256:
	case GNUTLS_DIG_SHA3_384:
	case GNUTLS_DIG_SHA3_512:
#endif

	case GNUTLS_DIG_SHAKE_128:
	case GNUTLS_DIG_SHAKE_256:

	case GNUTLS_DIG_MD2:
	case GNUTLS_DIG_RMD160:

#if ENABLE_GOST
	case GNUTLS_DIG_GOSTR_94:
	case GNUTLS_DIG_STREEBOG_256:
	case GNUTLS_DIG_STREEBOG_512:
#endif
		return 1;
	default:
		return 0;
	}
}


static void _wrap_gmac_update(void *_ctx, size_t length, const uint8_t *data)
{
	struct gmac_ctx *ctx = _ctx;

	if (ctx->pos + length < GCM_BLOCK_SIZE) {
		memcpy(&ctx->buffer[ctx->pos], data, length);
		ctx->pos += length;
		return;
	}

	if (ctx->pos) {
		memcpy(&ctx->buffer[ctx->pos], data, GCM_BLOCK_SIZE - ctx->pos);
		gcm_update(&ctx->ctx, &ctx->key, GCM_BLOCK_SIZE, ctx->buffer);
		data += GCM_BLOCK_SIZE - ctx->pos;
		length -= GCM_BLOCK_SIZE - ctx->pos;
	}

	if (length >= GCM_BLOCK_SIZE) {
		gcm_update(&ctx->ctx, &ctx->key,
			   length / GCM_BLOCK_SIZE * GCM_BLOCK_SIZE,
			   data);
		data += length / GCM_BLOCK_SIZE * GCM_BLOCK_SIZE;
		length %= GCM_BLOCK_SIZE;
	}

	memcpy(ctx->buffer, data, length);
	ctx->pos = length;
}


static void _wrap_gmac_set_nonce(void *_ctx, size_t nonce_length, const uint8_t *nonce)
{
	struct gmac_ctx *ctx = _ctx;

	gcm_set_iv(&ctx->ctx, &ctx->key, nonce_length, nonce);
}


static int rtsx_usb_ms_issue_cmd(struct rtsx_usb_ms *host)
{
	struct memstick_request *req = host->req;
	int err = 0;
	u8 cfg = 0, int_reg;

	dev_dbg(ms_dev(host), "%s\n", __func__);

	if (req->need_card_int) {
		if (host->ifmode != MEMSTICK_SERIAL)
			cfg = WAIT_INT;
	}

	if (req->long_data) {
		err = ms_transfer_data(host, req->data_dir,
				req->tpc, cfg, &(req->sg));
	} else {
		if (req->data_dir == READ)
			err = ms_read_bytes(host, req->tpc, cfg,
					req->data_len, req->data, &int_reg);
		else
			err = ms_write_bytes(host, req->tpc, cfg,
					req->data_len, req->data, &int_reg);
	}
	if (err < 0)
		return err;

	if (req->need_card_int) {
		if (host->ifmode == MEMSTICK_SERIAL) {
			err = ms_read_bytes(host, MS_TPC_GET_INT,
					NO_WAIT_INT, 1, &req->int_reg, NULL);
			if (err < 0)
				return err;
		} else {

			if (int_reg & MS_INT_CMDNK)
				req->int_reg |= MEMSTICK_INT_CMDNAK;
			if (int_reg & MS_INT_BREQ)
				req->int_reg |= MEMSTICK_INT_BREQ;
			if (int_reg & MS_INT_ERR)
				req->int_reg |= MEMSTICK_INT_ERR;
			if (int_reg & MS_INT_CED)
				req->int_reg |= MEMSTICK_INT_CED;
		}
		dev_dbg(ms_dev(host), "int_reg: 0x%02x\n", req->int_reg);
	}

	return 0;
}


static int rtsx_usb_ms_runtime_resume(struct device *dev)
{
	struct rtsx_usb_ms *host = dev_get_drvdata(dev);

	if (host->system_suspending)
		return 0;

	memstick_detect_change(host->msh);

	return 0;
}


static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
{
	struct rtsx_usb_ms *host = platform_get_drvdata(pdev);
	struct memstick_host *msh = host->msh;
	int err;

	host->eject = true;
	cancel_work_sync(&host->handle_req);

	mutex_lock(&host->host_mutex);
	if (host->req) {
		dev_dbg(ms_dev(host),
			"%s: Controller removed during transfer\n",
			dev_name(&msh->dev));
		host->req->error = -ENOMEDIUM;
		do {
			err = memstick_next_req(msh, &host->req);
			if (!err)
				host->req->error = -ENOMEDIUM;
		} while (!err);
	}
	mutex_unlock(&host->host_mutex);

	/* Balance possible unbalanced usage count
	 * e.g. unconditional module removal
	 */
	if (pm_runtime_active(ms_dev(host)))
		pm_runtime_put(ms_dev(host));

	pm_runtime_disable(ms_dev(host));
	memstick_remove_host(msh);
	dev_dbg(ms_dev(host),
		": Realtek USB Memstick controller has been removed\n");
	memstick_free_host(msh);
	platform_set_drvdata(pdev, NULL);

	return 0;
}


static int ms_pull_ctl_disable_lqfp48(struct rtsx_ucr *ucr)
{
	rtsx_usb_init_cmd(ucr);

	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55);
	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
	rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);

	return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}


static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name,
                        const char *value, size_t size, int flags,
                        uint32_t extra_flags)
{
    char procname[64];
    const char *name;
    char *mapped_name;
    struct lo_data *lo = lo_data(req);
    struct lo_inode *inode;
    ssize_t ret;
    int saverr;
    int fd = -1;
    bool switched_creds = false;
    bool cap_fsetid_dropped = false;
    struct lo_cred old = {};

    if (block_xattr(lo, in_name)) {
        fuse_reply_err(req, EOPNOTSUPP);
        return;
    }

    mapped_name = NULL;
    name = in_name;
    if (lo->xattrmap) {
        ret = xattr_map_client(lo, in_name, &mapped_name);
        if (ret < 0) {
            fuse_reply_err(req, -ret);
            return;
        }
        if (mapped_name) {
            name = mapped_name;
        }
    }

    inode = lo_inode(req, ino);
    if (!inode) {
        fuse_reply_err(req, EBADF);
        g_free(mapped_name);
        return;
    }

    saverr = ENOSYS;
    if (!lo_data(req)->xattr) {
        goto out;
    }

    fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64
             ", name=%s value=%s size=%zd)\n", ino, name, value, size);

    sprintf(procname, "%i", inode->fd);
    /*
     * If we are setting posix access acl and if SGID needs to be
     * cleared, then switch to caller's gid and drop CAP_FSETID
     * and that should make sure host kernel clears SGID.
     *
     * This probably will not work when we support idmapped mounts.
     * In that case we will need to find a non-root gid and switch
     * to it. (Instead of gid in request). Fix it when we support
     * idmapped mounts.
     */
    if (lo->posix_acl && !strcmp(name, "system.posix_acl_access")
        && (extra_flags & FUSE_SETXATTR_ACL_KILL_SGID)) {
        ret = lo_drop_cap_change_cred(req, &old, false, "FSETID",
                                      &cap_fsetid_dropped);
        if (ret) {
            saverr = ret;
            goto out;
        }
        switched_creds = true;
    }
    if (S_ISREG(inode->filetype) || S_ISDIR(inode->filetype)) {
        fd = openat(lo->proc_self_fd, procname, O_RDONLY);
        if (fd < 0) {
            saverr = errno;
            goto out;
        }
        ret = fsetxattr(fd, name, value, size, flags);
        saverr = ret == -1 ? errno : 0;
    } else {
        /* fchdir should not fail here */
        FCHDIR_NOFAIL(lo->proc_self_fd);
        ret = setxattr(procname, name, value, size, flags);
        saverr = ret == -1 ? errno : 0;
        FCHDIR_NOFAIL(lo->root.fd);
    }
    if (switched_creds) {
        if (cap_fsetid_dropped)
            lo_restore_cred_gain_cap(&old, false, "FSETID");
        else
            lo_restore_cred(&old, false);
    }

out:
    if (fd >= 0) {
        close(fd);
    }

    lo_inode_put(lo, &inode);
    g_free(mapped_name);
    fuse_reply_err(req, saverr);
}


static bool is_dot_or_dotdot(const char *name)
{
    return name[0] == '.' &&
           (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
}


static void lo_setlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
                     struct flock *lock, int sleep)
{
    struct lo_data *lo = lo_data(req);
    struct lo_inode *inode;
    struct lo_inode_plock *plock;
    int ret, saverr = 0;

    fuse_log(FUSE_LOG_DEBUG,
             "lo_setlk(ino=%" PRIu64 ", flags=%d)"
             " cmd=%d pid=%d owner=0x%" PRIx64 " sleep=%d l_whence=%d"
             " l_start=0x%" PRIx64 " l_len=0x%" PRIx64 "\n",
             ino, fi->flags, lock->l_type, lock->l_pid, fi->lock_owner, sleep,
             lock->l_whence, (uint64_t)lock->l_start, (uint64_t)lock->l_len);

    if (!lo->posix_lock) {
        fuse_reply_err(req, ENOSYS);
        return;
    }

    if (sleep) {
        fuse_reply_err(req, EOPNOTSUPP);
        return;
    }

    inode = lo_inode(req, ino);
    if (!inode) {
        fuse_reply_err(req, EBADF);
        return;
    }

    pthread_mutex_lock(&inode->plock_mutex);
    plock =
        lookup_create_plock_ctx(lo, inode, fi->lock_owner, lock->l_pid, &ret);

    if (!plock) {
        saverr = ret;
        goto out;
    }

    /* TODO: Is it alright to modify flock? */
    lock->l_pid = 0;
    ret = fcntl(plock->fd, F_OFD_SETLK, lock);
    if (ret == -1) {
        saverr = errno;
    }

out:
    pthread_mutex_unlock(&inode->plock_mutex);
    lo_inode_put(lo, &inode);

    fuse_reply_err(req, saverr);
}


static void parse_xattrmap(struct lo_data *lo)
{
    const char *map = lo->xattrmap;
    const char *tmp;
    int ret;

    lo->xattr_map_nentries = 0;
    while (*map) {
        XattrMapEntry tmp_entry;
        char sep;

        if (isspace(*map)) {
            map++;
            continue;
        }
        /* The separator is the first non-space of the rule */
        sep = *map++;
        if (!sep) {
            break;
        }

        tmp_entry.flags = 0;
        /* Start of 'type' */
        if (strstart(map, "prefix", &map)) {
            tmp_entry.flags |= XATTR_MAP_FLAG_PREFIX;
        } else if (strstart(map, "ok", &map)) {
            tmp_entry.flags |= XATTR_MAP_FLAG_OK;
        } else if (strstart(map, "bad", &map)) {
            tmp_entry.flags |= XATTR_MAP_FLAG_BAD;
        } else if (strstart(map, "unsupported", &map)) {
            tmp_entry.flags |= XATTR_MAP_FLAG_UNSUPPORTED;
        } else if (strstart(map, "map", &map)) {
            /*
             * map is sugar that adds a number of rules, and must be
             * the last entry.
             */
            parse_xattrmap_map(lo, map, sep);
            break;
        } else {
            fuse_log(FUSE_LOG_ERR,
                     "%s: Unexpected type;"
                     "Expecting 'prefix', 'ok', 'bad', 'unsupported' or 'map'"
                     " in rule %zu\n", __func__, lo->xattr_map_nentries);
            exit(1);
        }

        if (*map++ != sep) {
            fuse_log(FUSE_LOG_ERR,
                     "%s: Missing '%c' at end of type field of rule %zu\n",
                     __func__, sep, lo->xattr_map_nentries);
            exit(1);
        }

        /* Start of 'scope' */
        if (strstart(map, "client", &map)) {
            tmp_entry.flags |= XATTR_MAP_FLAG_CLIENT;
        } else if (strstart(map, "server", &map)) {
            tmp_entry.flags |= XATTR_MAP_FLAG_SERVER;
        } else if (strstart(map, "all", &map)) {
            tmp_entry.flags |= XATTR_MAP_FLAG_ALL;
        } else {
            fuse_log(FUSE_LOG_ERR,
                     "%s: Unexpected scope;"
                     " Expecting 'client', 'server', or 'all', in rule %zu\n",
                     __func__, lo->xattr_map_nentries);
            exit(1);
        }

        if (*map++ != sep) {
            fuse_log(FUSE_LOG_ERR,
                     "%s: Expecting '%c' found '%c'"
                     " after scope in rule %zu\n",
                     __func__, sep, *map, lo->xattr_map_nentries);
            exit(1);
        }

        /* At start of 'key' field */
        tmp = strchr(map, sep);
        if (!tmp) {
            fuse_log(FUSE_LOG_ERR,
                     "%s: Missing '%c' at end of key field of rule %zu",
                     __func__, sep, lo->xattr_map_nentries);
            exit(1);
        }
        tmp_entry.key = g_strndup(map, tmp - map);
        map = tmp + 1;

        /* At start of 'prepend' field */
        tmp = strchr(map, sep);
        if (!tmp) {
            fuse_log(FUSE_LOG_ERR,
                     "%s: Missing '%c' at end of prepend field of rule %zu",
                     __func__, sep, lo->xattr_map_nentries);
            exit(1);
        }
        tmp_entry.prepend = g_strndup(map, tmp - map);
        map = tmp + 1;

        add_xattrmap_entry(lo, &tmp_entry);
        /* End of rule - go around again for another rule */
    }

    if (!lo->xattr_map_nentries) {
        fuse_log(FUSE_LOG_ERR, "Empty xattr map\n");
        exit(1);
    }

    ret = xattr_map_client(lo, "security.capability",
                           &lo->xattr_security_capability);
    if (ret) {
        fuse_log(FUSE_LOG_ERR, "Failed to map security.capability: %s\n",
                strerror(ret));
        exit(1);
    }
    if (!lo->xattr_security_capability ||
        !strcmp(lo->xattr_security_capability, "security.capability")) {
        /* 1-1 mapping, don't need to do anything */
        free(lo->xattr_security_capability);
        lo->xattr_security_capability = NULL;
    }
}


static void lo_map_destroy(struct lo_map *map)
{
    g_free(map->elems);
}


static bool is_safe_path_component(const char *path)
{
    if (strchr(path, '/')) {
        return false;
    }

    return !is_dot_or_dotdot(path);
}


static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image,
  ExceptionInfo *exception)
{
#define MaxCixels  92

  static const char
    Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
                         "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";

  char
    buffer[MagickPathExtent],
    basename[MagickPathExtent],
    name[MagickPathExtent],
    symbol[MagickPathExtent];

  MagickBooleanType
    status;

  PixelInfo
    pixel;

  const Quantum
    *p;

  ssize_t
    i,
    x;

  size_t
    characters_per_pixel;

  ssize_t
    j,
    k,
    opacity,
    y;

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
  if (status == MagickFalse)
    return(status);
  if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
      (void) TransformImageColorspace(image,sRGBColorspace,exception);
  opacity=(-1);
  if (image->alpha_trait == UndefinedPixelTrait)
    {
      if ((image->storage_class == DirectClass) || (image->colors > 256))
        (void) SetImageType(image,PaletteType,exception);
    }
  else
    {
      double
        alpha,
        beta;

      /*
        Identify transparent colormap index.
      */
      if ((image->storage_class == DirectClass) || (image->colors > 256))
        (void) SetImageType(image,PaletteBilevelAlphaType,exception);
      for (i=0; i < (ssize_t) image->colors; i++)
        if (image->colormap[i].alpha != OpaqueAlpha)
          {
            if (opacity < 0)
              {
                opacity=i;
                continue;
              }
            alpha=(double) TransparentAlpha-(double)
              image->colormap[i].alpha;
            beta=(double) TransparentAlpha-(double)
              image->colormap[opacity].alpha;
            if (alpha < beta)
              opacity=i;
          }
      if (opacity == -1)
        {
          (void) SetImageType(image,PaletteBilevelAlphaType,exception);
          for (i=0; i < (ssize_t) image->colors; i++)
            if (image->colormap[i].alpha != OpaqueAlpha)
              {
                if (opacity < 0)
                  {
                    opacity=i;
                    continue;
                  }
                alpha=(Quantum) TransparentAlpha-(double)
                  image->colormap[i].alpha;
                beta=(Quantum) TransparentAlpha-(double)
                  image->colormap[opacity].alpha;
                if (alpha < beta)
                  opacity=i;
              }
        }
      if (opacity >= 0)
        {
          image->colormap[opacity].red=image->transparent_color.red;
          image->colormap[opacity].green=image->transparent_color.green;
          image->colormap[opacity].blue=image->transparent_color.blue;
        }
    }
  /*
    Compute the character per pixel.
  */
  characters_per_pixel=1;
  for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
    characters_per_pixel++;
  /*
    XPM header.
  */
  (void) WriteBlobString(image,"/* XPM */\n");
  GetPathComponent(image->filename,BasePath,basename);
  if (isalnum((int) ((unsigned char) *basename)) == 0)
    {
      (void) FormatLocaleString(buffer,MagickPathExtent,"xpm_%.1024s",basename);
      (void) CopyMagickString(basename,buffer,MagickPathExtent);
    }
  if (isalpha((int) ((unsigned char) basename[0])) == 0)
    basename[0]='_';
  for (i=1; basename[i] != '\0'; i++)
    if (isalnum((int) ((unsigned char) basename[i])) == 0)
      basename[i]='_';
  (void) FormatLocaleString(buffer,MagickPathExtent,
    "static char *%.1024s[] = {\n",basename);
  (void) WriteBlobString(image,buffer);
  (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
  (void) FormatLocaleString(buffer,MagickPathExtent,
    "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
    image->rows,(double) image->colors,(double) characters_per_pixel);
  (void) WriteBlobString(image,buffer);
  GetPixelInfo(image,&pixel);
  for (i=0; i < (ssize_t) image->colors; i++)
  {
    const char
      *symbolic;

    /*
      Define XPM color.
    */
    pixel=image->colormap[i];
    pixel.colorspace=sRGBColorspace;
    pixel.depth=8;
    pixel.alpha=(double) OpaqueAlpha;
    (void) QueryColorname(image,&pixel,XPMCompliance,name,exception);
    if (i == opacity)
      (void) CopyMagickString(name,"None",MagickPathExtent);
    /*
      Write XPM color.
    */
    k=i % MaxCixels;
    symbol[0]=Cixel[k];
    for (j=1; j < (ssize_t) characters_per_pixel; j++)
    {
      k=((i-k)/MaxCixels) % MaxCixels;
      symbol[j]=Cixel[k];
    }
    symbol[j]='\0';
    symbolic=(const char *) GetValueFromSplayTree(xpm_symbolic,name);
    if (symbolic == (const char *) NULL)
      (void) FormatLocaleString(buffer,MagickPathExtent,
        "\"%.1024s c %.1024s\",\n",symbol,name);
    else
      (void) FormatLocaleString(buffer,MagickPathExtent,
        "\"%.1024s c %.1024s %.1024s\",\n",symbol,name,symbolic);
    (void) WriteBlobString(image,buffer);
  }
  /*
    Define XPM pixels.
  */
  (void) WriteBlobString(image,"/* pixels */\n");
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    if (p == (const Quantum *) NULL)
      break;
    (void) WriteBlobString(image,"\"");
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      k=((ssize_t) GetPixelIndex(image,p) % MaxCixels);
      symbol[0]=Cixel[k];
      for (j=1; j < (ssize_t) characters_per_pixel; j++)
      {
        k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) % MaxCixels;
        symbol[j]=Cixel[k];
      }
      symbol[j]='\0';
      (void) CopyMagickString(buffer,symbol,MagickPathExtent);
      (void) WriteBlobString(image,buffer);
      p+=GetPixelChannels(image);
    }
    (void) FormatLocaleString(buffer,MagickPathExtent,"\"%.1024s\n",
      (y == (ssize_t) (image->rows-1) ? "" : ","));
    (void) WriteBlobString(image,buffer);
    if (image->previous == (Image *) NULL)
      {
        status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
          image->rows);
        if (status == MagickFalse)
          break;
      }
  }
  (void) WriteBlobString(image,"};\n");
  (void) CloseBlob(image);
  return(MagickTrue);
}


static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
{
	struct sk_buff *skb = NULL;
	struct net_device *dev;
	struct virtio_net_hdr *vnet_hdr = NULL;
	struct sockcm_cookie sockc;
	__be16 proto;
	int err, reserve = 0;
	void *ph;
	DECLARE_SOCKADDR(struct sockaddr_ll *, saddr, msg->msg_name);
	bool need_wait = !(msg->msg_flags & MSG_DONTWAIT);
	unsigned char *addr = NULL;
	int tp_len, size_max;
	void *data;
	int len_sum = 0;
	int status = TP_STATUS_AVAILABLE;
	int hlen, tlen, copylen = 0;
	long timeo = 0;

	mutex_lock(&po->pg_vec_lock);

	/* packet_sendmsg() check on tx_ring.pg_vec was lockless,
	 * we need to confirm it under protection of pg_vec_lock.
	 */
	if (unlikely(!po->tx_ring.pg_vec)) {
		err = -EBUSY;
		goto out;
	}
	if (likely(saddr == NULL)) {
		dev	= packet_cached_dev_get(po);
		proto	= READ_ONCE(po->num);
	} else {
		err = -EINVAL;
		if (msg->msg_namelen < sizeof(struct sockaddr_ll))
			goto out;
		if (msg->msg_namelen < (saddr->sll_halen
					+ offsetof(struct sockaddr_ll,
						sll_addr)))
			goto out;
		proto	= saddr->sll_protocol;
		dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex);
		if (po->sk.sk_socket->type == SOCK_DGRAM) {
			if (dev && msg->msg_namelen < dev->addr_len +
				   offsetof(struct sockaddr_ll, sll_addr))
				goto out_put;
			addr = saddr->sll_addr;
		}
	}

	err = -ENXIO;
	if (unlikely(dev == NULL))
		goto out;
	err = -ENETDOWN;
	if (unlikely(!(dev->flags & IFF_UP)))
		goto out_put;

	sockcm_init(&sockc, &po->sk);
	if (msg->msg_controllen) {
		err = sock_cmsg_send(&po->sk, msg, &sockc);
		if (unlikely(err))
			goto out_put;
	}

	if (po->sk.sk_socket->type == SOCK_RAW)
		reserve = dev->hard_header_len;
	size_max = po->tx_ring.frame_size
		- (po->tp_hdrlen - sizeof(struct sockaddr_ll));

	if ((size_max > dev->mtu + reserve + VLAN_HLEN) && !po->has_vnet_hdr)
		size_max = dev->mtu + reserve + VLAN_HLEN;

	reinit_completion(&po->skb_completion);

	do {
		ph = packet_current_frame(po, &po->tx_ring,
					  TP_STATUS_SEND_REQUEST);
		if (unlikely(ph == NULL)) {
			if (need_wait && skb) {
				timeo = sock_sndtimeo(&po->sk, msg->msg_flags & MSG_DONTWAIT);
				timeo = wait_for_completion_interruptible_timeout(&po->skb_completion, timeo);
				if (timeo <= 0) {
					err = !timeo ? -ETIMEDOUT : -ERESTARTSYS;
					goto out_put;
				}
			}
			/* check for additional frames */
			continue;
		}

		skb = NULL;
		tp_len = tpacket_parse_header(po, ph, size_max, &data);
		if (tp_len < 0)
			goto tpacket_error;

		status = TP_STATUS_SEND_REQUEST;
		hlen = LL_RESERVED_SPACE(dev);
		tlen = dev->needed_tailroom;
		if (po->has_vnet_hdr) {
			vnet_hdr = data;
			data += sizeof(*vnet_hdr);
			tp_len -= sizeof(*vnet_hdr);
			if (tp_len < 0 ||
			    __packet_snd_vnet_parse(vnet_hdr, tp_len)) {
				tp_len = -EINVAL;
				goto tpacket_error;
			}
			copylen = __virtio16_to_cpu(vio_le(),
						    vnet_hdr->hdr_len);
		}
		copylen = max_t(int, copylen, dev->hard_header_len);
		skb = sock_alloc_send_skb(&po->sk,
				hlen + tlen + sizeof(struct sockaddr_ll) +
				(copylen - dev->hard_header_len),
				!need_wait, &err);

		if (unlikely(skb == NULL)) {
			/* we assume the socket was initially writeable ... */
			if (likely(len_sum > 0))
				err = len_sum;
			goto out_status;
		}
		tp_len = tpacket_fill_skb(po, skb, ph, dev, data, tp_len, proto,
					  addr, hlen, copylen, &sockc);
		if (likely(tp_len >= 0) &&
		    tp_len > dev->mtu + reserve &&
		    !po->has_vnet_hdr &&
		    !packet_extra_vlan_len_allowed(dev, skb))
			tp_len = -EMSGSIZE;

		if (unlikely(tp_len < 0)) {
tpacket_error:
			if (po->tp_loss) {
				__packet_set_status(po, ph,
						TP_STATUS_AVAILABLE);
				packet_increment_head(&po->tx_ring);
				kfree_skb(skb);
				continue;
			} else {
				status = TP_STATUS_WRONG_FORMAT;
				err = tp_len;
				goto out_status;
			}
		}

		if (po->has_vnet_hdr) {
			if (virtio_net_hdr_to_skb(skb, vnet_hdr, vio_le())) {
				tp_len = -EINVAL;
				goto tpacket_error;
			}
			virtio_net_hdr_set_proto(skb, vnet_hdr);
		}

		skb->destructor = tpacket_destruct_skb;
		__packet_set_status(po, ph, TP_STATUS_SENDING);
		packet_inc_pending(&po->tx_ring);

		status = TP_STATUS_SEND_REQUEST;
		err = po->xmit(skb);
		if (unlikely(err > 0)) {
			err = net_xmit_errno(err);
			if (err && __packet_get_status(po, ph) ==
				   TP_STATUS_AVAILABLE) {
				/* skb was destructed already */
				skb = NULL;
				goto out_status;
			}
			/*
			 * skb was dropped but not destructed yet;
			 * let's treat it like congestion or err < 0
			 */
			err = 0;
		}
		packet_increment_head(&po->tx_ring);
		len_sum += tp_len;
	} while (likely((ph != NULL) ||
		/* Note: packet_read_pending() might be slow if we have
		 * to call it as it's per_cpu variable, but in fast-path
		 * we already short-circuit the loop with the first
		 * condition, and luckily don't have to go that path
		 * anyway.
		 */
		 (need_wait && packet_read_pending(&po->tx_ring))));

	err = len_sum;
	goto out_put;

out_status:
	__packet_set_status(po, ph, status);
	kfree_skb(skb);
out_put:
	dev_put(dev);
out:
	mutex_unlock(&po->pg_vec_lock);
	return err;
}


page_was_cached (struct rw_file *rwf, uint64_t offset)
{
  uint64_t page = offset / page_size;
  assert (page < rwf->cached_pages.len);

  return (rwf->cached_pages.ptr[page] & 1) != 0;
}


file_can_multi_conn (struct rw *rw)
{
  return true;
}


file_truncate (struct rw *rw, int64_t size)
{
  struct rw_file *rwf = (struct rw_file *) rw;

  /* If the destination is an ordinary file then the original file
   * size doesn't matter.  Truncate it to the source size.  But
   * truncate it to zero first so the file is completely empty and
   * sparse.
   */
  if (rwf->is_block)
    return;

  if (ftruncate (rwf->fd, 0) == -1 ||
      ftruncate (rwf->fd, size) == -1) {
    fprintf (stderr, "%s: truncate: %m\n", rw->name);
    exit (EXIT_FAILURE);
  }
  rwf->rw.size = size;

  /* We can assume the destination is zero. */
  destination_is_zero = true;
}


null_asynch_read (struct rw *rw,
                  struct command *command,
                  nbd_completion_callback cb)
{
  abort ();
}


file_punch_hole (int fd, uint64_t offset, uint64_t count)
{
#ifdef FALLOC_FL_PUNCH_HOLE
  int r;

  r = fallocate (fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
                 offset, count);
  if (r == -1) {
    if (is_not_supported (errno))
      return false;

    perror ("fallocate: FALLOC_FL_PUNCH_HOLE");
    exit (EXIT_FAILURE);
  }
  return true;
#endif
  return false;
}


null_synch_write (struct rw *rw,
                  const void *data, size_t len, uint64_t offset)
{
  /* nothing */
}


fill_dst_range_with_zeroes (struct command *command)
{
  char *data;
  size_t data_size;
  int dummy = 0;

  if (destination_is_zero)
    goto free_and_return;

  /* Try efficient zeroing. */
  if (dst->ops->asynch_zero (dst, command,
                             (nbd_completion_callback) {
                               .callback = free_command,
                               .user_data = command,
                             },
                             allocated))
    return;

  /* Fall back to loop writing zeroes.  This is going to be slow
   * anyway, so do it synchronously. XXX
   */
  data_size = MIN (request_size, command->slice.len);
  data = calloc (1, data_size);
  if (!data) {
    perror ("calloc");
    exit (EXIT_FAILURE);
  }
  while (command->slice.len > 0) {
    size_t len = command->slice.len;

    if (len > data_size)
      len = data_size;

    dst->ops->synch_write (dst, data, len, command->offset);
    command->slice.len -= len;
    command->offset += len;
  }
  free (data);

 free_and_return:
  free_command (command, &dummy);
}


null_is_read_only (struct rw *rw)
{
  return false;
}


null_can_multi_conn (struct rw *rw)
{
  return true;
}


null_asynch_zero (struct rw *rw, struct command *command,
                  nbd_completion_callback cb, bool allocate)
{
  int dummy = 0;

  cb.callback (cb.user_data, &dummy);
  return true;
}


file_close (struct rw *rw)
{
  struct rw_file *rwf = (struct rw_file *)rw;

  if (close (rwf->fd) == -1) {
    fprintf (stderr, "%s: close: %m\n", rw->name);
    exit (EXIT_FAILURE);
  }

#ifdef PAGE_CACHE_MAPPING
  byte_vector_reset (&rwf->cached_pages);
#endif

  free (rw);
}


static void __attribute__((__noreturn__)) usage(void)
{
	FILE *fp = stdout;
	fputs(USAGE_HEADER, fp);
	fprintf(fp, _(" %s [options] [<username>]\n"), program_invocation_short_name);

	fputs(USAGE_SEPARATOR, fp);
	fputs(_("Change your finger information.\n"), fp);

	fputs(USAGE_OPTIONS, fp);
	fputs(_(" -f, --full-name <full-name>  real name\n"), fp);
	fputs(_(" -o, --office <office>        office number\n"), fp);
	fputs(_(" -p, --office-phone <phone>   office phone number\n"), fp);
	fputs(_(" -h, --home-phone <phone>     home phone number\n"), fp);
	fputs(USAGE_SEPARATOR, fp);
	printf( " -u, --help                   %s\n", USAGE_OPTSTR_HELP);
	printf( " -v, --version                %s\n", USAGE_OPTSTR_VERSION);
	printf(USAGE_MAN_TAIL("chfn(1)"));
	exit(EXIT_SUCCESS);
}


static void JS_IsFoxxApiDisabled(
    v8::FunctionCallbackInfo<v8::Value> const& args) {
  TRI_V8_TRY_CATCH_BEGIN(isolate)
  v8::HandleScope scope(isolate);

  TRI_GET_GLOBALS();
  ServerSecurityFeature& security =
      v8g->_server.getFeature<ServerSecurityFeature>();
  TRI_V8_RETURN_BOOL(security.isFoxxApiDisabled());

  TRI_V8_TRY_CATCH_END
}


static void JS_DefineAction(v8::FunctionCallbackInfo<v8::Value> const& args) {
  TRI_V8_TRY_CATCH_BEGIN(isolate);
  v8::HandleScope scope(isolate);
  TRI_GET_GLOBALS();

  if (args.Length() != 3) {
    TRI_V8_THROW_EXCEPTION_USAGE(
        "defineAction(<name>, <callback>, <parameter>)");
  }

  V8SecurityFeature& v8security = v8g->_server.getFeature<V8SecurityFeature>();

  if (!v8security.isAllowedToDefineHttpAction(isolate)) {
    TRI_V8_THROW_EXCEPTION_MESSAGE(
        TRI_ERROR_FORBIDDEN, "operation only allowed for internal scripts");
  }

  // extract the action name
  TRI_Utf8ValueNFC utf8name(isolate, args[0]);

  if (*utf8name == nullptr) {
    TRI_V8_THROW_TYPE_ERROR("<name> must be an UTF-8 string");
  }

  std::string name = *utf8name;

  // extract the action callback
  if (!args[1]->IsFunction()) {
    TRI_V8_THROW_TYPE_ERROR("<callback> must be a function");
  }

  v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(args[1]);

  // extract the options
  v8::Handle<v8::Object> options;

  if (args[2]->IsObject()) {
    options = args[2]->ToObject(TRI_IGETC).FromMaybe(v8::Local<v8::Object>());
  } else {
    options = v8::Object::New(isolate);
  }

  // create an action with the given options
  auto action =
      std::make_shared<v8_action_t>(v8g->_server.getFeature<ActionFeature>());
  ParseActionOptions(isolate, v8g, action.get(), options);

  // store an action with the given name
  // note: this may return a previous action for the same name
  std::shared_ptr<TRI_action_t> actionForName =
      TRI_DefineActionVocBase(name, action);

  v8_action_t* v8ActionForName =
      dynamic_cast<v8_action_t*>(actionForName.get());

  if (v8ActionForName != nullptr) {
    v8ActionForName->createCallback(isolate, callback);
  } else {
    LOG_TOPIC("43be9", WARN, arangodb::Logger::FIXME)
        << "cannot create callback for V8 action";
  }

  TRI_V8_RETURN_UNDEFINED();
  TRI_V8_TRY_CATCH_END
}


void TRI_InitV8Actions(v8::Isolate* isolate) {
  v8::HandleScope scope(isolate);

  // .............................................................................
  // create the global functions
  // .............................................................................

  TRI_AddGlobalFunctionVocbase(
      isolate, TRI_V8_ASCII_STRING(isolate, "SYS_DEFINE_ACTION"),
      JS_DefineAction);
  TRI_AddGlobalFunctionVocbase(
      isolate,
      TRI_V8_ASCII_STRING(isolate, "SYS_EXECUTE_GLOBAL_CONTEXT_FUNCTION"),
      JS_ExecuteGlobalContextFunction, true);
  TRI_AddGlobalFunctionVocbase(
      isolate, TRI_V8_ASCII_STRING(isolate, "SYS_GET_CURRENT_REQUEST"),
      JS_GetCurrentRequest);
  TRI_AddGlobalFunctionVocbase(
      isolate, TRI_V8_ASCII_STRING(isolate, "SYS_GET_CURRENT_RESPONSE"),
      JS_GetCurrentResponse);
  TRI_AddGlobalFunctionVocbase(
      isolate, TRI_V8_ASCII_STRING(isolate, "SYS_RAW_REQUEST_BODY"),
      JS_RawRequestBody, true);
  TRI_AddGlobalFunctionVocbase(
      isolate, TRI_V8_ASCII_STRING(isolate, "SYS_REQUEST_PARTS"),
      JS_RequestParts, true);
}


v8::Handle<v8::Object> TRI_RequestCppToV8(v8::Isolate* isolate,
                                          TRI_v8_global_t const* v8g,
                                          arangodb::GeneralRequest* request,
                                          TRI_action_t const* action) {
  // setup the request
  v8::Handle<v8::Object> req = v8::Object::New(isolate);
  auto context = TRI_IGETC;
  // Example:
  //      {
  //        path : "/full/path/suffix1/suffix2",
  //
  //        prefix : "/full/path",
  //
  //        "suffix" : [
  //          "suffix1",
  //          "suffix2"
  //        ],
  //
  //        "parameters" : {
  //          "init" : "true"
  //        },
  //
  //        "headers" : {
  //          "accept" : "text/html",
  //          "accept-encoding" : "gzip, deflate",
  //          "accept-language" : "de-de,en-us;q=0.7,en;q=0.3",
  //          "user-agent" : "Mozilla/5.0"
  //        },
  //
  //        "cookies" : {
  //          "ARANGODB_SESSION_ID" : "0cwuzusd23nw3qiwui84uwqwqw23e"
  //        },
  //
  //        "requestType" : "GET",
  //        "requestBody" : "... only for PUT and POST ...",
  //        "user" : "authenticatedUser"
  //      }

  TRI_GET_GLOBAL_STRING(AuthorizedKey);
  if (request->authenticated()) {
    req->Set(context, AuthorizedKey, v8::True(isolate)).FromMaybe(false);
  } else {
    req->Set(context, AuthorizedKey, v8::False(isolate)).FromMaybe(false);
  }

  // create user or null
  std::string const& user = request->user();

  TRI_GET_GLOBAL_STRING(UserKey);
  if (user.empty()) {
    req->Set(context, UserKey, v8::Null(isolate)).FromMaybe(false);
  } else {
    req->Set(context, UserKey, TRI_V8_STD_STRING(isolate, user))
        .FromMaybe(false);
  }

  TRI_GET_GLOBAL_STRING(IsAdminUser);
  if (request->authenticated()) {
    if (user.empty() || ExecContext::current().isAdminUser()) {
      req->Set(context, IsAdminUser, v8::True(isolate)).FromMaybe(false);
    } else {
      req->Set(context, IsAdminUser, v8::False(isolate)).FromMaybe(false);
    }
  } else {
    req->Set(context, IsAdminUser,
             ExecContext::isAuthEnabled() ? v8::False(isolate)
                                          : v8::True(isolate))
        .FromMaybe(false);
    ;
  }

  // create database attribute
  std::string const& database = request->databaseName();
  TRI_ASSERT(!database.empty());

  TRI_GET_GLOBAL_STRING(DatabaseKey);
  req->Set(context, DatabaseKey, TRI_V8_STD_STRING(isolate, database))
      .FromMaybe(false);

  // set the full url
  std::string const& fullUrl = request->fullUrl();
  TRI_GET_GLOBAL_STRING(UrlKey);
  req->Set(context, UrlKey, TRI_V8_STD_STRING(isolate, fullUrl))
      .FromMaybe(false);

  // set the protocol
  TRI_GET_GLOBAL_STRING(ProtocolKey);
  if (request->transportType() == Endpoint::TransportType::HTTP) {
    req->Set(context, ProtocolKey, TRI_V8_ASCII_STRING(isolate, "http"))
        .FromMaybe(false);
  } else if (request->transportType() == Endpoint::TransportType::VST) {
    req->Set(context, ProtocolKey, TRI_V8_ASCII_STRING(isolate, "vst"))
        .FromMaybe(false);
  }

  // set the connection info
  ConnectionInfo const& info = request->connectionInfo();

  v8::Handle<v8::Object> serverArray = v8::Object::New(isolate);
  TRI_GET_GLOBAL_STRING(AddressKey);
  serverArray
      ->Set(context, AddressKey, TRI_V8_STD_STRING(isolate, info.serverAddress))
      .FromMaybe(false);
  TRI_GET_GLOBAL_STRING(PortKey);
  serverArray->Set(context, PortKey, v8::Number::New(isolate, info.serverPort))
      .FromMaybe(false);
  TRI_GET_GLOBAL_STRING(EndpointKey);
  serverArray
      ->Set(context, EndpointKey,
            TRI_V8_STD_STRING(isolate, Endpoint::uriForm(info.endpoint)))
      .FromMaybe(false);
  TRI_GET_GLOBAL_STRING(ServerKey);
  req->Set(context, ServerKey, serverArray).FromMaybe(false);

  TRI_GET_GLOBAL_STRING(PortTypeKey);
  req->DefineOwnProperty(TRI_IGETC, PortTypeKey,
                         TRI_V8_STD_STRING(isolate, info.portType()),
                         static_cast<v8::PropertyAttribute>(v8::ReadOnly))
      .FromMaybe(false);  // ignoring return value

  v8::Handle<v8::Object> clientArray = v8::Object::New(isolate);
  clientArray
      ->Set(context, AddressKey, TRI_V8_STD_STRING(isolate, info.clientAddress))
      .FromMaybe(false);
  clientArray->Set(context, PortKey, v8::Number::New(isolate, info.clientPort))
      .FromMaybe(false);
  TRI_GET_GLOBAL_STRING(IdKey);
  clientArray->Set(context, IdKey, TRI_V8_STD_STRING(isolate, std::string("0")))
      .FromMaybe(false);
  TRI_GET_GLOBAL_STRING(ClientKey);
  req->Set(context, ClientKey, clientArray).FromMaybe(false);

  req->Set(context, TRI_V8_ASCII_STRING(isolate, "internals"),
           v8::External::New(isolate, request))
      .FromMaybe(false);

  // copy prefix
  std::string path = request->prefix();
  TRI_GET_GLOBAL_STRING(PrefixKey);
  req->Set(context, PrefixKey, TRI_V8_STD_STRING(isolate, path))
      .FromMaybe(false);

  // copy header fields
  v8::Handle<v8::Object> headerFields = v8::Object::New(isolate);
  // intentional copy, as we will modify the headers later
  auto headers = request->headers();

  std::string const& acceptPlain = request->contentTypeResponsePlain();

  if (!acceptPlain.empty()) {
    headers.emplace(StaticStrings::Accept, acceptPlain);
  } else {
    switch (request->contentTypeResponse()) {
      case ContentType::UNSET:
      case ContentType::CUSTOM:  // use Content-Type from _headers
        break;
      case ContentType::JSON:  // application/json
        headers.emplace(StaticStrings::Accept, StaticStrings::MimeTypeJson);
        break;
      case ContentType::VPACK:  // application/x-velocypack
        headers.emplace(StaticStrings::Accept, StaticStrings::MimeTypeVPack);
        break;
      case ContentType::TEXT:  // text/plain
        headers.emplace(StaticStrings::Accept, StaticStrings::MimeTypeText);
        break;
      case ContentType::HTML:  // text/html
        headers.emplace(StaticStrings::Accept, StaticStrings::MimeTypeHtml);
        break;
      case ContentType::DUMP:  // application/x-arango-dump
        headers.emplace(StaticStrings::Accept, StaticStrings::MimeTypeDump);
        break;
    }
  }

  switch (request->contentType()) {
    case ContentType::UNSET:
    case ContentType::CUSTOM:  // use Content-Type from _headers
      break;
    case ContentType::JSON:  // application/json
      headers.emplace(StaticStrings::ContentTypeHeader,
                      StaticStrings::MimeTypeJson);
      break;
    case ContentType::VPACK:  // application/x-velocypack
      headers.emplace(StaticStrings::ContentTypeHeader,
                      StaticStrings::MimeTypeVPack);
      break;
    case ContentType::TEXT:  // text/plain
      headers.emplace(StaticStrings::ContentTypeHeader,
                      StaticStrings::MimeTypeText);
      break;
    case ContentType::HTML:  // text/html
      headers.emplace(StaticStrings::ContentTypeHeader,
                      StaticStrings::MimeTypeHtml);
      break;
    case ContentType::DUMP:  // application/x-arango-dump
      headers.emplace(StaticStrings::ContentTypeHeader,
                      StaticStrings::MimeTypeDump);
      break;
  }

  TRI_GET_GLOBAL_STRING(HeadersKey);
  req->Set(context, HeadersKey, headerFields).FromMaybe(false);
  TRI_GET_GLOBAL_STRING(RequestTypeKey);
  TRI_GET_GLOBAL_STRING(RequestBodyKey);

  auto setRequestBodyJsonOrVPack = [&]() {
    if (rest::ContentType::UNSET == request->contentType()) {
      bool digestable = false;
      try {
        auto parsed = request->payload(true);
        if (parsed.isObject() || parsed.isArray()) {
          request->setDefaultContentType();
          digestable = true;
        }
      } catch (...) {
      }
      // ok, no json/vpack after all ;-)
      auto raw = request->rawPayload();
      headers[StaticStrings::ContentLength] = StringUtils::itoa(raw.size());
      V8Buffer* buffer = V8Buffer::New(isolate, raw.data(), raw.size());
      auto bufObj = v8::Local<v8::Object>::New(isolate, buffer->_handle);
      TRI_GET_GLOBAL_STRING(RawRequestBodyKey);
      req->Set(context, RawRequestBodyKey, bufObj).FromMaybe(false);
      req->Set(context, RequestBodyKey,
               TRI_V8_PAIR_STRING(isolate, raw.data(), raw.size()))
          .FromMaybe(false);
      if (!digestable) {
        return;
      }
    }

    if (rest::ContentType::JSON == request->contentType()) {
      VPackStringRef body = request->rawPayload();
      req->Set(context, RequestBodyKey,
               TRI_V8_PAIR_STRING(isolate, body.data(), body.size()))
          .FromMaybe(false);
      headers[StaticStrings::ContentLength] =
          StringUtils::itoa(request->contentLength());
    } else if (rest::ContentType::VPACK == request->contentType()) {
      // the VPACK is passed as it is to to JavaScript
      // FIXME not every VPack can be converted to JSON
      VPackSlice slice = request->payload(true);
      std::string jsonString = slice.toJson();

      LOG_TOPIC("8afce", DEBUG, Logger::COMMUNICATION)
          << "json handed into v8 request:\n"
          << jsonString;

      req->Set(context, RequestBodyKey, TRI_V8_STD_STRING(isolate, jsonString))
          .FromMaybe(false);
      headers[StaticStrings::ContentLength] =
          StringUtils::itoa(jsonString.size());
      headers[StaticStrings::ContentTypeHeader] = StaticStrings::MimeTypeJson;
    }
  };

  // copy request type
  switch (request->requestType()) {
    case rest::RequestType::POST: {
      TRI_GET_GLOBAL_STRING(PostConstant);
      req->Set(context, RequestTypeKey, PostConstant).FromMaybe(false);
      setRequestBodyJsonOrVPack();
      break;
    }

    case rest::RequestType::PUT: {
      TRI_GET_GLOBAL_STRING(PutConstant);
      req->Set(context, RequestTypeKey, PutConstant).FromMaybe(false);
      setRequestBodyJsonOrVPack();
      break;
    }

    case rest::RequestType::PATCH: {
      TRI_GET_GLOBAL_STRING(PatchConstant);
      req->Set(context, RequestTypeKey, PatchConstant).FromMaybe(false);
      setRequestBodyJsonOrVPack();
      break;
    }
    case rest::RequestType::OPTIONS: {
      TRI_GET_GLOBAL_STRING(OptionsConstant);
      req->Set(context, RequestTypeKey, OptionsConstant).FromMaybe(false);
      break;
    }
    case rest::RequestType::DELETE_REQ: {
      TRI_GET_GLOBAL_STRING(DeleteConstant);
      req->Set(context, RequestTypeKey, DeleteConstant).FromMaybe(false);
      setRequestBodyJsonOrVPack();
      break;
    }
    case rest::RequestType::HEAD: {
      TRI_GET_GLOBAL_STRING(HeadConstant);
      req->Set(context, RequestTypeKey, HeadConstant).FromMaybe(false);
      break;
    }
    case rest::RequestType::GET:
    default: {
      TRI_GET_GLOBAL_STRING(GetConstant);
      req->Set(context, RequestTypeKey, GetConstant).FromMaybe(false);
      break;
    }
  }

  for (auto const& it : headers) {
    headerFields
        ->Set(context, TRI_V8_STD_STRING(isolate, it.first),
              TRI_V8_STD_STRING(isolate, it.second))
        .FromMaybe(false);
  }

  // copy request parameter
  v8::Handle<v8::Object> valuesObject = v8::Object::New(isolate);

  for (auto& it : request->values()) {
    valuesObject
        ->Set(context, TRI_V8_STD_STRING(isolate, it.first),
              TRI_V8_STD_STRING(isolate, it.second))
        .FromMaybe(false);
  }

  // copy request array parameter (a[]=1&a[]=2&...)
  for (auto& arrayValue : request->arrayValues()) {
    std::string const& k = arrayValue.first;
    std::vector<std::string> const& v = arrayValue.second;

    v8::Handle<v8::Array> list =
        v8::Array::New(isolate, static_cast<int>(v.size()));

    for (size_t i = 0; i < v.size(); ++i) {
      list->Set(context, (uint32_t)i, TRI_V8_STD_STRING(isolate, v[i]))
          .FromMaybe(false);
    }

    valuesObject->Set(context, TRI_V8_STD_STRING(isolate, k), list)
        .FromMaybe(false);
  }

  TRI_GET_GLOBAL_STRING(ParametersKey);
  req->Set(context, ParametersKey, valuesObject).FromMaybe(false);

  // copy cookie -- only for http protocol
  if (request->transportType() == Endpoint::TransportType::HTTP) {  // FIXME
    v8::Handle<v8::Object> cookiesObject = v8::Object::New(isolate);

    HttpRequest* httpRequest = dynamic_cast<HttpRequest*>(request);
    if (httpRequest == nullptr) {
      // maybe we can just continue
      THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
                                     "invalid request type");
    } else {
      for (auto& it : httpRequest->cookieValues()) {
        cookiesObject
            ->Set(context, TRI_V8_STD_STRING(isolate, it.first),
                  TRI_V8_STD_STRING(isolate, it.second))
            .FromMaybe(false);
      }
    }
    TRI_GET_GLOBAL_STRING(CookiesKey);
    req->Set(context, CookiesKey, cookiesObject).FromMaybe(false);
  }

  // copy suffix, which comes from the action:
  std::vector<std::string> const& suffixes = request->decodedSuffixes();
  std::vector<std::string> const& rawSuffixes = request->suffixes();

  uint32_t index = 0;
  char const* sep = "";

  size_t const n = suffixes.size();
  v8::Handle<v8::Array> suffixArray =
      v8::Array::New(isolate, static_cast<int>(n - action->_urlParts));
  v8::Handle<v8::Array> rawSuffixArray =
      v8::Array::New(isolate, static_cast<int>(n - action->_urlParts));

  for (size_t s = action->_urlParts; s < n; ++s) {
    suffixArray->Set(context, index, TRI_V8_STD_STRING(isolate, suffixes[s]))
        .FromMaybe(false);
    rawSuffixArray
        ->Set(context, index, TRI_V8_STD_STRING(isolate, rawSuffixes[s]))
        .FromMaybe(false);
    ++index;

    path += sep + suffixes[s];
    sep = "/";
  }

  TRI_GET_GLOBAL_STRING(SuffixKey);
  req->Set(context, SuffixKey, suffixArray).FromMaybe(false);
  TRI_GET_GLOBAL_STRING(RawSuffixKey);
  req->Set(context, RawSuffixKey, rawSuffixArray).FromMaybe(false);

  // copy full path
  TRI_GET_GLOBAL_STRING(PathKey);
  req->Set(context, PathKey, TRI_V8_STD_STRING(isolate, path)).FromMaybe(false);

  return req;
}


static void udf_readahead(struct readahead_control *rac)
{
	mpage_readahead(rac, udf_get_block);
}


int udf_setsize(struct inode *inode, loff_t newsize)
{
	int err;
	struct udf_inode_info *iinfo;
	unsigned int bsize = i_blocksize(inode);

	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
	      S_ISLNK(inode->i_mode)))
		return -EINVAL;
	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
		return -EPERM;

	iinfo = UDF_I(inode);
	if (newsize > inode->i_size) {
		down_write(&iinfo->i_data_sem);
		if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
			if (bsize <
			    (udf_file_entry_alloc_offset(inode) + newsize)) {
				err = udf_expand_file_adinicb(inode);
				if (err)
					return err;
				down_write(&iinfo->i_data_sem);
			} else {
				iinfo->i_lenAlloc = newsize;
				goto set_size;
			}
		}
		err = udf_extend_file(inode, newsize);
		if (err) {
			up_write(&iinfo->i_data_sem);
			return err;
		}
set_size:
		up_write(&iinfo->i_data_sem);
		truncate_setsize(inode, newsize);
	} else {
		if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
			down_write(&iinfo->i_data_sem);
			udf_clear_extent_cache(inode);
			memset(iinfo->i_data + iinfo->i_lenEAttr + newsize,
			       0x00, bsize - newsize -
			       udf_file_entry_alloc_offset(inode));
			iinfo->i_lenAlloc = newsize;
			truncate_setsize(inode, newsize);
			up_write(&iinfo->i_data_sem);
			goto update_time;
		}
		err = block_truncate_page(inode->i_mapping, newsize,
					  udf_get_block);
		if (err)
			return err;
		truncate_setsize(inode, newsize);
		down_write(&iinfo->i_data_sem);
		udf_clear_extent_cache(inode);
		err = udf_truncate_extents(inode);
		up_write(&iinfo->i_data_sem);
		if (err)
			return err;
	}
update_time:
	inode->i_mtime = inode->i_ctime = current_time(inode);
	if (IS_SYNC(inode))
		udf_sync_inode(inode);
	else
		mark_inode_dirty(inode);
	return 0;
}


static struct buffer_head *udf_getblk(struct inode *inode, udf_pblk_t block,
				      int create, int *err)
{
	struct buffer_head *bh;
	struct buffer_head dummy;

	dummy.b_state = 0;
	dummy.b_blocknr = -1000;
	*err = udf_get_block(inode, block, &dummy, create);
	if (!*err && buffer_mapped(&dummy)) {
		bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
		if (buffer_new(&dummy)) {
			lock_buffer(bh);
			memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
			set_buffer_uptodate(bh);
			unlock_buffer(bh);
			mark_buffer_dirty_inode(bh, inode);
		}
		return bh;
	}

	return NULL;
}


parserCreate(const XML_Char *encodingName,
             const XML_Memory_Handling_Suite *memsuite, const XML_Char *nameSep,
             DTD *dtd) {
  XML_Parser parser;

  if (memsuite) {
    XML_Memory_Handling_Suite *mtemp;
    parser = memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
    if (parser != NULL) {
      mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
      mtemp->malloc_fcn = memsuite->malloc_fcn;
      mtemp->realloc_fcn = memsuite->realloc_fcn;
      mtemp->free_fcn = memsuite->free_fcn;
    }
  } else {
    XML_Memory_Handling_Suite *mtemp;
    parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct));
    if (parser != NULL) {
      mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
      mtemp->malloc_fcn = malloc;
      mtemp->realloc_fcn = realloc;
      mtemp->free_fcn = free;
    }
  }

  if (! parser)
    return parser;

  parser->m_buffer = NULL;
  parser->m_bufferLim = NULL;

  parser->m_attsSize = INIT_ATTS_SIZE;
  parser->m_atts
      = (ATTRIBUTE *)MALLOC(parser, parser->m_attsSize * sizeof(ATTRIBUTE));
  if (parser->m_atts == NULL) {
    FREE(parser, parser);
    return NULL;
  }
#ifdef XML_ATTR_INFO
  parser->m_attInfo = (XML_AttrInfo *)MALLOC(
      parser, parser->m_attsSize * sizeof(XML_AttrInfo));
  if (parser->m_attInfo == NULL) {
    FREE(parser, parser->m_atts);
    FREE(parser, parser);
    return NULL;
  }
#endif
  parser->m_dataBuf
      = (XML_Char *)MALLOC(parser, INIT_DATA_BUF_SIZE * sizeof(XML_Char));
  if (parser->m_dataBuf == NULL) {
    FREE(parser, parser->m_atts);
#ifdef XML_ATTR_INFO
    FREE(parser, parser->m_attInfo);
#endif
    FREE(parser, parser);
    return NULL;
  }
  parser->m_dataBufEnd = parser->m_dataBuf + INIT_DATA_BUF_SIZE;

  if (dtd)
    parser->m_dtd = dtd;
  else {
    parser->m_dtd = dtdCreate(&parser->m_mem);
    if (parser->m_dtd == NULL) {
      FREE(parser, parser->m_dataBuf);
      FREE(parser, parser->m_atts);
#ifdef XML_ATTR_INFO
      FREE(parser, parser->m_attInfo);
#endif
      FREE(parser, parser);
      return NULL;
    }
  }

  parser->m_freeBindingList = NULL;
  parser->m_freeTagList = NULL;
  parser->m_freeInternalEntities = NULL;

  parser->m_groupSize = 0;
  parser->m_groupConnector = NULL;

  parser->m_unknownEncodingHandler = NULL;
  parser->m_unknownEncodingHandlerData = NULL;

  parser->m_namespaceSeparator = ASCII_EXCL;
  parser->m_ns = XML_FALSE;
  parser->m_ns_triplets = XML_FALSE;

  parser->m_nsAtts = NULL;
  parser->m_nsAttsVersion = 0;
  parser->m_nsAttsPower = 0;

  parser->m_protocolEncodingName = NULL;

  poolInit(&parser->m_tempPool, &(parser->m_mem));
  poolInit(&parser->m_temp2Pool, &(parser->m_mem));
  parserInit(parser, encodingName);

  if (encodingName && ! parser->m_protocolEncodingName) {
    XML_ParserFree(parser);
    return NULL;
  }

  if (nameSep) {
    parser->m_ns = XML_TRUE;
    parser->m_internalEncoding = XmlGetInternalEncodingNS();
    parser->m_namespaceSeparator = *nameSep;
  } else {
    parser->m_internalEncoding = XmlGetInternalEncoding();
  }

  return parser;
}


initializeEncoding(XML_Parser parser) {
  const char *s;
#ifdef XML_UNICODE
  char encodingBuf[128];
  /* See comments about `protocolEncodingName` in parserInit() */
  if (! parser->m_protocolEncodingName)
    s = NULL;
  else {
    int i;
    for (i = 0; parser->m_protocolEncodingName[i]; i++) {
      if (i == sizeof(encodingBuf) - 1
          || (parser->m_protocolEncodingName[i] & ~0x7f) != 0) {
        encodingBuf[0] = '\0';
        break;
      }
      encodingBuf[i] = (char)parser->m_protocolEncodingName[i];
    }
    encodingBuf[i] = '\0';
    s = encodingBuf;
  }
#else
  s = parser->m_protocolEncodingName;
#endif
  if ((parser->m_ns ? XmlInitEncodingNS : XmlInitEncoding)(
          &parser->m_initEncoding, &parser->m_encoding, s))
    return XML_ERROR_NONE;
  return handleUnknownEncoding(parser, parser->m_protocolEncodingName);
}