GF_Err MergeFragment(GF_MovieFragmentBox *moof, GF_ISOFile *mov)
{
	GF_Err e;
	u32 i, j;
	u64 MaxDur;
	GF_TrackFragmentBox *traf;
	GF_TrackBox *trak;
	u64 base_data_offset;

	MaxDur = 0;

	//we shall have a MOOV and its MVEX BEFORE any MOOF
	if (!mov->moov || !mov->moov->mvex) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error: %s not received before merging fragment\n", mov->moov ? "mvex" : "moov" ));
		return GF_ISOM_INVALID_FILE;
	}
	//and all fragments should be continous but:
	//- dash with dependent representations may likely give R1(moofSN 1, 3, 5, 7) plus R2(moofSN 2, 4, 6, 8)
	//- smooth muxed in a single file may end up with V(1),A(1), V(2),A(2) ...
	//we do not throw an error if not as we may still want to be able to concatenate dependent representations in DASH and
	if (mov->NextMoofNumber && moof->mfhd && (mov->NextMoofNumber >= moof->mfhd->sequence_number)) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] wrong sequence number: got %d but last one was %d\n", moof->mfhd->sequence_number, mov->NextMoofNumber));
	}

	base_data_offset = mov->current_top_box_start;
	if (moof->compressed_diff)
		base_data_offset -= moof->compressed_diff;

	i=0;
	while ((traf = (GF_TrackFragmentBox*)gf_list_enum(moof->TrackList, &i))) {
		if (!traf->tfhd) {
			trak = NULL;
			traf->trex = NULL;
		} else if (mov->is_smooth) {
			trak = gf_list_get(mov->moov->trackList, 0);
			traf->trex = (GF_TrackExtendsBox*)gf_list_get(mov->moov->mvex->TrackExList, 0);
			assert(traf->trex);
			traf->trex->trackID = trak->Header->trackID = traf->tfhd->trackID;
		} else {
			trak = gf_isom_get_track_from_id(mov->moov, traf->tfhd->trackID);
			j=0;
			while ((traf->trex = (GF_TrackExtendsBox*)gf_list_enum(mov->moov->mvex->TrackExList, &j))) {
				if (traf->trex->trackID == traf->tfhd->trackID) break;
				traf->trex = NULL;
			}
		}

		if (!trak || !traf->trex) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error: Cannot find fragment track with ID %d\n", traf->tfhd ? traf->tfhd->trackID : 0));
			return GF_ISOM_INVALID_FILE;
		}

		e = MergeTrack(trak, traf, moof, mov->current_top_box_start, moof->compressed_diff, &base_data_offset, !trak->first_traf_merged);
		if (e) return e;

		trak->present_in_scalable_segment = 1;

		//update trak duration
		SetTrackDuration(trak);
		if (trak->Header->duration > MaxDur)
			MaxDur = trak->Header->duration;

		trak->first_traf_merged = GF_TRUE;
	}

	if (moof->child_boxes) {
		GF_Box *a;
		i = 0;
		while ((a = (GF_Box *)gf_list_enum(moof->child_boxes, &i))) {
			if (a->type == GF_ISOM_BOX_TYPE_PSSH) {
				GF_ProtectionSystemHeaderBox *pssh = (GF_ProtectionSystemHeaderBox *)gf_isom_box_new_parent(&mov->moov->child_boxes, GF_ISOM_BOX_TYPE_PSSH);
				if (!pssh) return GF_OUT_OF_MEM;
				memmove(pssh->SystemID, ((GF_ProtectionSystemHeaderBox *)a)->SystemID, 16);
				if (((GF_ProtectionSystemHeaderBox *)a)->KIDs && ((GF_ProtectionSystemHeaderBox *)a)->KID_count > 0) {
					pssh->KID_count = ((GF_ProtectionSystemHeaderBox *)a)->KID_count;
					pssh->KIDs = (bin128 *)gf_malloc(pssh->KID_count*sizeof(bin128));
					if (!pssh->KIDs) return GF_OUT_OF_MEM;

					memmove(pssh->KIDs, ((GF_ProtectionSystemHeaderBox *)a)->KIDs, pssh->KID_count*sizeof(bin128));
				}
				pssh->private_data_size = ((GF_ProtectionSystemHeaderBox *)a)->private_data_size;
				pssh->private_data = (u8 *)gf_malloc(pssh->private_data_size*sizeof(char));
				if (!pssh->private_data) return GF_OUT_OF_MEM;
				memmove(pssh->private_data, ((GF_ProtectionSystemHeaderBox *)a)->private_data, pssh->private_data_size);
			}
		}
	}

	mov->NextMoofNumber = moof->mfhd ? moof->mfhd->sequence_number : 0;
	//update movie duration
	if (mov->moov->mvhd->duration < MaxDur) mov->moov->mvhd->duration = MaxDur;
	return GF_OK;
}


Bool gf_isom_get_subsample_types(GF_ISOFile *movie, u32 track, u32 subs_index, u32 *flags)
{
	GF_SubSampleInformationBox *sub_samples=NULL;
	GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);

	if (!track || !subs_index) return GF_FALSE;
	if (!trak->Media || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->sub_samples) return GF_FALSE;
	sub_samples = gf_list_get(trak->Media->information->sampleTable->sub_samples, subs_index-1);
	if (!sub_samples) return GF_FALSE;
	*flags = sub_samples->flags;
	return GF_TRUE;
}


GF_Err GetPrevMediaTime(GF_TrackBox *trak, u64 movieTime, u64 *OutMovieTime)
{
	u32 i;
	u64 time;
	GF_EdtsEntry *ent;

	*OutMovieTime = 0;
	if (! trak->editBox || !trak->editBox->editList) return GF_BAD_PARAM;

	time = 0;
	ent = NULL;
	i=0;
	while ((ent = (GF_EdtsEntry *)gf_list_enum(trak->editBox->editList->entryList, &i))) {
		if (ent->mediaTime == -1) {
			if ( (time + ent->segmentDuration) * trak->Media->mediaHeader->timeScale >= movieTime * trak->moov->mvhd->timeScale) {
				*OutMovieTime = time * trak->Media->mediaHeader->timeScale / trak->moov->mvhd->timeScale;
				return GF_OK;
			}
			continue;
		}
		/*get the first entry whose end is greater than or equal to the desired time*/
		time += ent->segmentDuration;
		if ( time * trak->Media->mediaHeader->timeScale >= movieTime * trak->moov->mvhd->timeScale) {
			*OutMovieTime = time * trak->Media->mediaHeader->timeScale / trak->moov->mvhd->timeScale;
			return GF_OK;
		}
	}
	*OutMovieTime = 0;
	return GF_OK;
}


static void gf_isom_setup_traf_inheritance(GF_ISOFile *mov)
{
	u32 i, count;
	if (!mov->moov->mvex)
		return;
	count = gf_list_count(mov->moov->trackList);

	for (i=0; i<count; i++) {
		u32 refTrackNum=0;
		gf_isom_get_reference(mov, i+1, GF_ISOM_REF_TRIN, 1, &refTrackNum);
		if (refTrackNum) {
			GF_ISOTrackID tkid = gf_isom_get_track_id(mov, i+1);
			GF_ISOTrackID reftkid = gf_isom_get_track_id(mov, refTrackNum);
			GF_TrackExtendsBox *trex = GetTrex(mov->moov, tkid);
			if (trex) trex->inherit_from_traf_id = reftkid;
		}
	}
}


find_route_entry_by_dao_ack(uint8_t seq)
{
  uip_ds6_route_t *re;
  re = uip_ds6_route_head();
  while(re != NULL) {
    if(re->state.dao_seqno_out == seq && RPL_ROUTE_IS_DAO_PENDING(re)) {
      /* found it! */
      return re;
    }
    re = uip_ds6_route_next(re);
  }
  return NULL;
}


dao_ack_input(void)
{
#if RPL_WITH_DAO_ACK

  uint8_t *buffer;
  uint8_t instance_id;
  uint8_t sequence;
  uint8_t status;
  rpl_instance_t *instance;
  rpl_parent_t *parent;

  buffer = UIP_ICMP_PAYLOAD;

  instance_id = buffer[0];
  sequence = buffer[2];
  status = buffer[3];

  instance = rpl_get_instance(instance_id);
  if(instance == NULL) {
    uipbuf_clear();
    return;
  }

  if(RPL_IS_STORING(instance)) {
    parent = rpl_find_parent(instance->current_dag, &UIP_IP_BUF->srcipaddr);
    if(parent == NULL) {
      /* not a known instance - drop the packet and ignore */
      uipbuf_clear();
      return;
    }
  } else {
    parent = NULL;
  }

  if(instance->current_dag->rank == ROOT_RANK(instance)) {
    LOG_DBG("DODAG root received a DAO ACK, ignoring it\n");
    uipbuf_clear();
    return;
  }

  LOG_INFO("Received a DAO %s with sequence number %d (%d) and status %d from ",
         status < 128 ? "ACK" : "NACK",
         sequence, instance->my_dao_seqno, status);
  LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr);
  LOG_INFO_("\n");

  if(sequence == instance->my_dao_seqno) {
    instance->has_downward_route = status < 128;

    /* always stop the retransmit timer when the ACK arrived */
    ctimer_stop(&instance->dao_retransmit_timer);

    /* Inform objective function on status of the DAO ACK */
    if(RPL_IS_STORING(instance) && instance->of->dao_ack_callback) {
      instance->of->dao_ack_callback(parent, status);
    }

#if RPL_REPAIR_ON_DAO_NACK
    if(status >= RPL_DAO_ACK_UNABLE_TO_ACCEPT) {
      /*
       * Failed the DAO transmission - need to remove the default route.
       * Trigger a local repair since we can not get our DAO in.
       */
      rpl_local_repair(instance);
    }
#endif

  } else if(RPL_IS_STORING(instance)) {
    /* this DAO ACK should be forwarded to another recently registered route */
    uip_ds6_route_t *re;
    const uip_ipaddr_t *nexthop;
    if((re = find_route_entry_by_dao_ack(sequence)) != NULL) {
      /* pick the recorded seq no from that node and forward DAO ACK - and
         clear the pending flag*/
      RPL_ROUTE_CLEAR_DAO_PENDING(re);

      nexthop = uip_ds6_route_nexthop(re);
      if(nexthop == NULL) {
        LOG_WARN("No next hop to fwd DAO ACK to\n");
      } else {
        LOG_INFO("Fwd DAO ACK to:");
        LOG_INFO_6ADDR(nexthop);
        LOG_INFO_("\n");
        buffer[2] = re->state.dao_seqno_in;
        uip_icmp6_send(nexthop, ICMP6_RPL, RPL_CODE_DAO_ACK, 4);
      }

      if(status >= RPL_DAO_ACK_UNABLE_TO_ACCEPT) {
        /* this node did not get in to the routing tables above... - remove */
        uip_ds6_route_rm(re);
      }
    } else {
      LOG_WARN("No route entry found to forward DAO ACK (seqno %u)\n", sequence);
    }
  }
#endif /* RPL_WITH_DAO_ACK */
  uipbuf_clear();
}


dio_input(void)
{
  unsigned char *buffer;
  uint8_t buffer_length;
  rpl_dio_t dio;
  uint8_t subopt_type;
  int i;
  int len;
  uip_ipaddr_t from;

  memset(&dio, 0, sizeof(dio));

  /* Set default values in case the DIO configuration option is missing. */
  dio.dag_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
  dio.dag_intmin = RPL_DIO_INTERVAL_MIN;
  dio.dag_redund = RPL_DIO_REDUNDANCY;
  dio.dag_min_hoprankinc = RPL_MIN_HOPRANKINC;
  dio.dag_max_rankinc = RPL_MAX_RANKINC;
  dio.ocp = RPL_OF_OCP;
  dio.default_lifetime = RPL_DEFAULT_LIFETIME;
  dio.lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;

  uip_ipaddr_copy(&from, &UIP_IP_BUF->srcipaddr);

  /* DAG Information Object */
  LOG_INFO("Received a DIO from ");
  LOG_INFO_6ADDR(&from);
  LOG_INFO_("\n");

  buffer_length = uip_len - uip_l3_icmp_hdr_len;

  /* Process the DIO base option. */
  i = 0;
  buffer = UIP_ICMP_PAYLOAD;

  dio.instance_id = buffer[i++];
  dio.version = buffer[i++];
  dio.rank = get16(buffer, i);
  i += 2;

  LOG_DBG("Incoming DIO (id, ver, rank) = (%u,%u,%u)\n",
         (unsigned)dio.instance_id,
         (unsigned)dio.version,
         (unsigned)dio.rank);

  dio.grounded = buffer[i] & RPL_DIO_GROUNDED;
  dio.mop = (buffer[i]& RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT;
  dio.preference = buffer[i++] & RPL_DIO_PREFERENCE_MASK;

  dio.dtsn = buffer[i++];
  /* two reserved bytes */
  i += 2;

  memcpy(&dio.dag_id, buffer + i, sizeof(dio.dag_id));
  i += sizeof(dio.dag_id);

  LOG_DBG("Incoming DIO (dag_id, pref) = (");
  LOG_DBG_6ADDR(&dio.dag_id);
  LOG_DBG_(", %u)\n", dio.preference);

  /* Check if there are any DIO suboptions. */
  for(; i < buffer_length; i += len) {
    subopt_type = buffer[i];
    if(subopt_type == RPL_OPTION_PAD1) {
      len = 1;
    } else {
      /* Suboption with a two-byte header + payload */
      len = 2 + buffer[i + 1];
    }

    if(len + i > buffer_length) {
      LOG_WARN("Invalid DIO packet\n");
      RPL_STAT(rpl_stats.malformed_msgs++);
      goto discard;
    }

    LOG_DBG("Incoming DIO (option, length) = (%u, %u)\n", subopt_type, len - 2);

    switch(subopt_type) {
      case RPL_OPTION_DAG_METRIC_CONTAINER:
        if(len < 6) {
          LOG_WARN("Invalid DAG MC, len = %d\n", len);
          RPL_STAT(rpl_stats.malformed_msgs++);
          goto discard;
        }
        dio.mc.type = buffer[i + 2];
        dio.mc.flags = buffer[i + 3] << 1;
        dio.mc.flags |= buffer[i + 4] >> 7;
        dio.mc.aggr = (buffer[i + 4] >> 4) & 0x3;
        dio.mc.prec = buffer[i + 4] & 0xf;
        dio.mc.length = buffer[i + 5];

        if(dio.mc.type == RPL_DAG_MC_NONE) {
          /* No metric container: do nothing */
        } else if(dio.mc.type == RPL_DAG_MC_ETX) {
          dio.mc.obj.etx = get16(buffer, i + 6);

          LOG_DBG("DAG MC: type %u, flags %u, aggr %u, prec %u, length %u, ETX %u\n",
                 (unsigned)dio.mc.type,
                 (unsigned)dio.mc.flags,
                 (unsigned)dio.mc.aggr,
                 (unsigned)dio.mc.prec,
                 (unsigned)dio.mc.length,
                 (unsigned)dio.mc.obj.etx);
        } else if(dio.mc.type == RPL_DAG_MC_ENERGY) {
          dio.mc.obj.energy.flags = buffer[i + 6];
          dio.mc.obj.energy.energy_est = buffer[i + 7];
        } else {
          LOG_WARN("Unhandled DAG MC type: %u\n", (unsigned)dio.mc.type);
          goto discard;
        }
        break;
      case RPL_OPTION_ROUTE_INFO:
        if(len < 9) {
          LOG_WARN("Invalid destination prefix option, len = %d\n", len);
          RPL_STAT(rpl_stats.malformed_msgs++);
          goto discard;
        }

        /* The flags field includes the preference value. */
        dio.destination_prefix.length = buffer[i + 2];
        dio.destination_prefix.flags = buffer[i + 3];
        dio.destination_prefix.lifetime = get32(buffer, i + 4);

        if(((dio.destination_prefix.length + 7) / 8) + 8 <= len &&
           dio.destination_prefix.length <= 128) {
          LOG_INFO("Copying destination prefix\n");
          memcpy(&dio.destination_prefix.prefix, &buffer[i + 8],
                 (dio.destination_prefix.length + 7) / 8);
        } else {
          LOG_WARN("Invalid route info option, len = %d\n", len);
          RPL_STAT(rpl_stats.malformed_msgs++);
          goto discard;
        }

        break;
      case RPL_OPTION_DAG_CONF:
        if(len != 16) {
          LOG_WARN("Invalid DAG configuration option, len = %d\n", len);
          RPL_STAT(rpl_stats.malformed_msgs++);
          goto discard;
        }

        /* Path control field not yet implemented - at i + 2 */
        dio.dag_intdoubl = buffer[i + 3];
        dio.dag_intmin = buffer[i + 4];
        dio.dag_redund = buffer[i + 5];
        dio.dag_max_rankinc = get16(buffer, i + 6);
        dio.dag_min_hoprankinc = get16(buffer, i + 8);
        dio.ocp = get16(buffer, i + 10);
        /* buffer + 12 is reserved */
        dio.default_lifetime = buffer[i + 13];
        dio.lifetime_unit = get16(buffer, i + 14);
        LOG_INFO("DAG conf:dbl=%d, min=%d red=%d maxinc=%d mininc=%d ocp=%d d_l=%u l_u=%u\n",
               dio.dag_intdoubl, dio.dag_intmin, dio.dag_redund,
               dio.dag_max_rankinc, dio.dag_min_hoprankinc, dio.ocp,
               dio.default_lifetime, dio.lifetime_unit);
        break;
      case RPL_OPTION_PREFIX_INFO:
        if(len != 32) {
          LOG_WARN("Invalid DAG prefix info, len != 32\n");
          RPL_STAT(rpl_stats.malformed_msgs++);
          goto discard;
        }
        dio.prefix_info.length = buffer[i + 2];

        if(dio.prefix_info.length > sizeof(uip_ipaddr_t) * 8) {
          LOG_WARN("Invalid DAG prefix info, len %u > %u\n",
                   dio.prefix_info.length, (unsigned)(sizeof(uip_ipaddr_t) * 8));
          RPL_STAT(rpl_stats.malformed_msgs++);
          goto discard;
        }

        dio.prefix_info.flags = buffer[i + 3];
        /* valid lifetime is ingnored for now - at i + 4 */
        /* preferred lifetime stored in lifetime */
        dio.prefix_info.lifetime = get32(buffer, i + 8);
        /* 32-bit reserved at i + 12 */
        LOG_INFO("Copying prefix information\n");
        memcpy(&dio.prefix_info.prefix, &buffer[i + 16], 16);
        break;
      default:
        LOG_WARN("Unsupported suboption type in DIO: %u\n",
               (unsigned)subopt_type);
    }
  }

#ifdef RPL_DEBUG_DIO_INPUT
  RPL_DEBUG_DIO_INPUT(&from, &dio);
#endif

  rpl_process_dio(&from, &dio);

discard:
  uipbuf_clear();
}


  string DebugString() const override {
    std::unique_lock<std::mutex> lock(mu_);
    return strings::StrCat("Staging size: ", buf_.size());
  }


explicit UnstageOp(OpKernelConstruction* ctx) : OpKernel(ctx) {}


  Status Peek(std::size_t index, Tuple* tuple) {
    std::unique_lock<std::mutex> lock(mu_);

    // Wait if the requested index is not available
    non_empty_cond_var_.wait(
        lock, [index, this]() { return index < this->buf_.size(); });

    // Place tensors in the output tuple
    for (const auto& tensor : buf_[index]) {
      tuple->push_back(tensor);
    }

    return Status::OK();
  }


NO_INLINE JsVar *jspeStatementReturn() {
  JsVar *result = 0;
  JSP_ASSERT_MATCH(LEX_R_RETURN);
  if (lex->tk != ';' && lex->tk != '}') {
    // we only want the value, so skip the name if there was one
    result = jsvSkipNameAndUnLock(jspeExpression());
  }
  if (JSP_SHOULD_EXECUTE) {
    JsVar *resultVar = jspeiFindInScopes(JSPARSE_RETURN_VAR);
    if (resultVar) {
      jsvReplaceWith(resultVar, result);
      jsvUnLock(resultVar);
      execInfo.execute |= EXEC_RETURN; // Stop anything else in this function executing
    } else {
      jsExceptionHere(JSET_SYNTAXERROR, "RETURN statement, but not in a function.\n");
    }
  }
  jsvUnLock(result);
  return 0;
}


NO_INLINE JsVar *jspeStatementTry() {
  // execute the try block
  JSP_ASSERT_MATCH(LEX_R_TRY);
  bool shouldExecuteBefore = JSP_SHOULD_EXECUTE;
  jspeBlock();
  bool hadException = shouldExecuteBefore && ((execInfo.execute & EXEC_EXCEPTION)!=0);

  bool hadCatch = false;
  if (lex->tk == LEX_R_CATCH) {
    JSP_ASSERT_MATCH(LEX_R_CATCH);
    hadCatch = true;
    JSP_MATCH('(');
    JsVar *scope = 0;
    JsVar *exceptionVar = 0;
    if (hadException) {
      scope = jsvNewObject();
      if (scope)
        exceptionVar = jsvFindChildFromString(scope, jslGetTokenValueAsString(lex), true);
    }
    JSP_MATCH_WITH_CLEANUP_AND_RETURN(LEX_ID,jsvUnLock2(scope,exceptionVar),0);
    JSP_MATCH_WITH_CLEANUP_AND_RETURN(')',jsvUnLock2(scope,exceptionVar),0);
    if (exceptionVar) {
      // set the exception var up properly
      JsVar *exception = jspGetException();
      if (exception) {
        jsvSetValueOfName(exceptionVar, exception);
        jsvUnLock(exception);
      }
      // Now clear the exception flag (it's handled - we hope!)
      execInfo.execute = execInfo.execute & (JsExecFlags)~(EXEC_EXCEPTION|EXEC_ERROR_LINE_REPORTED);
      jsvUnLock(exceptionVar);
    }

    if (shouldExecuteBefore && !hadException) {
      JSP_SAVE_EXECUTE();
      jspSetNoExecute();
      jspeBlock();
      JSP_RESTORE_EXECUTE();
    } else {
      if (!scope || jspeiAddScope(scope)) {
        jspeBlock();
        if (scope) jspeiRemoveScope();
      }
    }
    jsvUnLock(scope);
  }
  if (lex->tk == LEX_R_FINALLY || (!hadCatch && ((execInfo.execute&(EXEC_ERROR|EXEC_INTERRUPTED))==0))) {
    JSP_MATCH(LEX_R_FINALLY);
    // clear the exception flag - but only momentarily!
    if (hadException) execInfo.execute = execInfo.execute & (JsExecFlags)~EXEC_EXCEPTION;
    jspeBlock();
    // put the flag back!
    if (hadException && !hadCatch) execInfo.execute = execInfo.execute | EXEC_EXCEPTION;
  }
  return 0;
}


NO_INLINE bool jspeFunctionDefinitionInternal(JsVar *funcVar, bool expressionOnly) {
  if (expressionOnly) {
    if (funcVar)
      funcVar->flags = (funcVar->flags & ~JSV_VARTYPEMASK) | JSV_FUNCTION_RETURN;
  } else {
    JSP_MATCH('{');

  #ifndef SAVE_ON_FLASH
    if (lex->tk==LEX_STR && !strcmp(jslGetTokenValueAsString(lex), "compiled")) {
      jsWarn("Function marked with \"compiled\" uploaded in source form");
    }
  #endif

    /* If the function starts with return, treat it specially -
     * we don't want to store the 'return' part of it
     */
    if (funcVar && lex->tk==LEX_R_RETURN) {
      funcVar->flags = (funcVar->flags & ~JSV_VARTYPEMASK) | JSV_FUNCTION_RETURN;
      JSP_ASSERT_MATCH(LEX_R_RETURN);
    }
  }
  // Get the line number (if needed)
  JsVarInt lineNumber = 0;
  if (funcVar && lex->lineNumberOffset) {
    // jslGetLineNumber is slow, so we only do it if we have debug info
    lineNumber = (JsVarInt)jslGetLineNumber(lex) + (JsVarInt)lex->lineNumberOffset - 1;
  }
  // Get the code - parse it and figure out where it stops
  JslCharPos funcBegin = jslCharPosClone(&lex->tokenStart);
  int lastTokenEnd = -1;
  if (!expressionOnly) {
    int brackets = 0;
    while (lex->tk && (brackets || lex->tk != '}')) {
      if (lex->tk == '{') brackets++;
      if (lex->tk == '}') brackets--;
      lastTokenEnd = (int)jsvStringIteratorGetIndex(&lex->it)-1;
      JSP_ASSERT_MATCH(lex->tk);
    }
  } else {
    JsExecFlags oldExec = execInfo.execute;
    execInfo.execute = EXEC_NO;
    jsvUnLock(jspeAssignmentExpression());
    execInfo.execute = oldExec;
    lastTokenEnd = (int)jsvStringIteratorGetIndex(&lex->tokenStart.it)-1;
  }
  // Then create var and set (if there was any code!)
  if (funcVar && lastTokenEnd>0) {
    // code var
    JsVar *funcCodeVar;
    if (jsvIsNativeString(lex->sourceVar)) {
      /* If we're parsing from a Native String (eg. E.memoryArea, E.setBootCode) then
      use another Native String to load function code straight from flash */
      int s = (int)jsvStringIteratorGetIndex(&funcBegin.it) - 1;
      funcCodeVar = jsvNewNativeString(lex->sourceVar->varData.nativeStr.ptr + s, (unsigned int)(lastTokenEnd - s));
    } else {
      if (jsfGetFlag(JSF_PRETOKENISE)) {
        funcCodeVar = jslNewTokenisedStringFromLexer(&funcBegin, (size_t)lastTokenEnd);
      } else {
        funcCodeVar = jslNewStringFromLexer(&funcBegin, (size_t)lastTokenEnd);
      }
    }
    jsvUnLock2(jsvAddNamedChild(funcVar, funcCodeVar, JSPARSE_FUNCTION_CODE_NAME), funcCodeVar);
    // scope var
    JsVar *funcScopeVar = jspeiGetScopesAsVar();
    if (funcScopeVar) {
      jsvUnLock2(jsvAddNamedChild(funcVar, funcScopeVar, JSPARSE_FUNCTION_SCOPE_NAME), funcScopeVar);
    }
    // If we've got a line number, add a var for it
    if (lineNumber) {
      JsVar *funcLineNumber = jsvNewFromInteger(lineNumber);
      if (funcLineNumber) {
        jsvUnLock2(jsvAddNamedChild(funcVar, funcLineNumber, JSPARSE_FUNCTION_LINENUMBER_NAME), funcLineNumber);
      }
    }
  }

  jslCharPosFree(&funcBegin);
  if (!expressionOnly) JSP_MATCH('}');
  return 0;
}


NO_INLINE JsVar *jspeFactorObject() {
  if (JSP_SHOULD_EXECUTE) {
    JsVar *contents = jsvNewObject();
    if (!contents) { // out of memory
      jspSetError(false);
      return 0;
    }
    /* JSON-style object definition */
    JSP_MATCH_WITH_RETURN('{', contents);
    while (!JSP_SHOULDNT_PARSE && lex->tk != '}') {
      JsVar *varName = 0;
      // we only allow strings or IDs on the left hand side of an initialisation
      if (jslIsIDOrReservedWord(lex)) {
        if (JSP_SHOULD_EXECUTE)
          varName = jslGetTokenValueAsVar(lex);
        jslGetNextToken(lex); // skip over current token
      } else if (
          lex->tk==LEX_STR ||
          lex->tk==LEX_TEMPLATE_LITERAL ||
          lex->tk==LEX_FLOAT ||
          lex->tk==LEX_INT ||
          lex->tk==LEX_R_TRUE ||
          lex->tk==LEX_R_FALSE ||
          lex->tk==LEX_R_NULL ||
          lex->tk==LEX_R_UNDEFINED) {
        varName = jspeFactor();
      } else {
        JSP_MATCH_WITH_RETURN(LEX_ID, contents);
      }
#ifndef SAVE_ON_FLASH
      bool isGetter, isSetter;
      if (lex->tk==LEX_ID && jsvIsString(varName)) {
        isGetter = jsvIsStringEqual(varName, "get");
        isSetter = jsvIsStringEqual(varName, "set");
        if (isGetter || isSetter) {
          jsvUnLock(varName);
          varName = jslGetTokenValueAsVar(lex);
          JSP_ASSERT_MATCH(LEX_ID);
          JsVar *method = jspeFunctionDefinition(false);
          jsvAddGetterOrSetter(contents, varName, isGetter, method);
          jsvUnLock(method);
        }
      } else
#endif
      {
        JSP_MATCH_WITH_CLEANUP_AND_RETURN(':', jsvUnLock(varName), contents);
        if (JSP_SHOULD_EXECUTE) {
          varName = jsvAsArrayIndexAndUnLock(varName);
          JsVar *contentsName = jsvFindChildFromVar(contents, varName, true);
          if (contentsName) {
            JsVar *value = jsvSkipNameAndUnLock(jspeAssignmentExpression()); // value can be 0 (could be undefined!)
            jsvUnLock2(jsvSetValueOfName(contentsName, value), value);
          }
        }
      }
      jsvUnLock(varName);
      // no need to clean here, as it will definitely be used
      if (lex->tk != '}') JSP_MATCH_WITH_RETURN(',', contents);
    }
    JSP_MATCH_WITH_RETURN('}', contents);
    return contents;
  } else {
    // Not executing so do fast skip
    jspeBlock();
    return 0;
  }
}


static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
			   struct futex_q *q, struct futex_hash_bucket **hb)
{
	u32 uval;
	int ret;

	/*
	 * Access the page AFTER the hash-bucket is locked.
	 * Order is important:
	 *
	 *   Userspace waiter: val = var; if (cond(val)) futex_wait(&var, val);
	 *   Userspace waker:  if (cond(var)) { var = new; futex_wake(&var); }
	 *
	 * The basic logical guarantee of a futex is that it blocks ONLY
	 * if cond(var) is known to be true at the time of blocking, for
	 * any cond.  If we locked the hash-bucket after testing *uaddr, that
	 * would open a race condition where we could block indefinitely with
	 * cond(var) false, which would violate the guarantee.
	 *
	 * On the other hand, we insert q and release the hash-bucket only
	 * after testing *uaddr.  This guarantees that futex_wait() will NOT
	 * absorb a wakeup if *uaddr does not match the desired values
	 * while the syscall executes.
	 */
retry:
	ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key, VERIFY_READ);
	if (unlikely(ret != 0))
		return ret;

retry_private:
	*hb = queue_lock(q);

	ret = get_futex_value_locked(&uval, uaddr);

	if (ret) {
		queue_unlock(q, *hb);

		ret = get_user(uval, uaddr);
		if (ret)
			goto out;

		if (!(flags & FLAGS_SHARED))
			goto retry_private;

		put_futex_key(&q->key);
		goto retry;
	}

	if (uval != val) {
		queue_unlock(q, *hb);
		ret = -EWOULDBLOCK;
	}

out:
	if (ret)
		put_futex_key(&q->key);
	return ret;
}


static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
			 u32 __user *uaddr2, int nr_wake, int nr_requeue,
			 u32 *cmpval, int requeue_pi)
{
	union futex_key key1 = FUTEX_KEY_INIT, key2 = FUTEX_KEY_INIT;
	int drop_count = 0, task_count = 0, ret;
	struct futex_pi_state *pi_state = NULL;
	struct futex_hash_bucket *hb1, *hb2;
	struct plist_head *head1;
	struct futex_q *this, *next;
	u32 curval2;

	if (requeue_pi) {
		/*
		 * requeue_pi requires a pi_state, try to allocate it now
		 * without any locks in case it fails.
		 */
		if (refill_pi_state_cache())
			return -ENOMEM;
		/*
		 * requeue_pi must wake as many tasks as it can, up to nr_wake
		 * + nr_requeue, since it acquires the rt_mutex prior to
		 * returning to userspace, so as to not leave the rt_mutex with
		 * waiters and no owner.  However, second and third wake-ups
		 * cannot be predicted as they involve race conditions with the
		 * first wake and a fault while looking up the pi_state.  Both
		 * pthread_cond_signal() and pthread_cond_broadcast() should
		 * use nr_wake=1.
		 */
		if (nr_wake != 1)
			return -EINVAL;
	}

retry:
	if (pi_state != NULL) {
		/*
		 * We will have to lookup the pi_state again, so free this one
		 * to keep the accounting correct.
		 */
		free_pi_state(pi_state);
		pi_state = NULL;
	}

	ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ);
	if (unlikely(ret != 0))
		goto out;
	ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2,
			    requeue_pi ? VERIFY_WRITE : VERIFY_READ);
	if (unlikely(ret != 0))
		goto out_put_key1;

	hb1 = hash_futex(&key1);
	hb2 = hash_futex(&key2);

retry_private:
	double_lock_hb(hb1, hb2);

	if (likely(cmpval != NULL)) {
		u32 curval;

		ret = get_futex_value_locked(&curval, uaddr1);

		if (unlikely(ret)) {
			double_unlock_hb(hb1, hb2);

			ret = get_user(curval, uaddr1);
			if (ret)
				goto out_put_keys;

			if (!(flags & FLAGS_SHARED))
				goto retry_private;

			put_futex_key(&key2);
			put_futex_key(&key1);
			goto retry;
		}
		if (curval != *cmpval) {
			ret = -EAGAIN;
			goto out_unlock;
		}
	}

	if (requeue_pi && (task_count - nr_wake < nr_requeue)) {
		/*
		 * Attempt to acquire uaddr2 and wake the top waiter. If we
		 * intend to requeue waiters, force setting the FUTEX_WAITERS
		 * bit.  We force this here where we are able to easily handle
		 * faults rather in the requeue loop below.
		 */
		ret = futex_proxy_trylock_atomic(uaddr2, hb1, hb2, &key1,
						 &key2, &pi_state, nr_requeue);

		/*
		 * At this point the top_waiter has either taken uaddr2 or is
		 * waiting on it.  If the former, then the pi_state will not
		 * exist yet, look it up one more time to ensure we have a
		 * reference to it.
		 */
		if (ret == 1) {
			WARN_ON(pi_state);
			drop_count++;
			task_count++;
			ret = get_futex_value_locked(&curval2, uaddr2);
			if (!ret)
				ret = lookup_pi_state(curval2, hb2, &key2,
						      &pi_state);
		}

		switch (ret) {
		case 0:
			break;
		case -EFAULT:
			double_unlock_hb(hb1, hb2);
			put_futex_key(&key2);
			put_futex_key(&key1);
			ret = fault_in_user_writeable(uaddr2);
			if (!ret)
				goto retry;
			goto out;
		case -EAGAIN:
			/* The owner was exiting, try again. */
			double_unlock_hb(hb1, hb2);
			put_futex_key(&key2);
			put_futex_key(&key1);
			cond_resched();
			goto retry;
		default:
			goto out_unlock;
		}
	}

	head1 = &hb1->chain;
	plist_for_each_entry_safe(this, next, head1, list) {
		if (task_count - nr_wake >= nr_requeue)
			break;

		if (!match_futex(&this->key, &key1))
			continue;

		/*
		 * FUTEX_WAIT_REQEUE_PI and FUTEX_CMP_REQUEUE_PI should always
		 * be paired with each other and no other futex ops.
		 */
		if ((requeue_pi && !this->rt_waiter) ||
		    (!requeue_pi && this->rt_waiter)) {
			ret = -EINVAL;
			break;
		}

		/*
		 * Wake nr_wake waiters.  For requeue_pi, if we acquired the
		 * lock, we already woke the top_waiter.  If not, it will be
		 * woken by futex_unlock_pi().
		 */
		if (++task_count <= nr_wake && !requeue_pi) {
			wake_futex(this);
			continue;
		}

		/* Ensure we requeue to the expected futex for requeue_pi. */
		if (requeue_pi && !match_futex(this->requeue_pi_key, &key2)) {
			ret = -EINVAL;
			break;
		}

		/*
		 * Requeue nr_requeue waiters and possibly one more in the case
		 * of requeue_pi if we couldn't acquire the lock atomically.
		 */
		if (requeue_pi) {
			/* Prepare the waiter to take the rt_mutex. */
			atomic_inc(&pi_state->refcount);
			this->pi_state = pi_state;
			ret = rt_mutex_start_proxy_lock(&pi_state->pi_mutex,
							this->rt_waiter,
							this->task, 1);
			if (ret == 1) {
				/* We got the lock. */
				requeue_pi_wake_futex(this, &key2, hb2);
				drop_count++;
				continue;
			} else if (ret) {
				/* -EDEADLK */
				this->pi_state = NULL;
				free_pi_state(pi_state);
				goto out_unlock;
			}
		}
		requeue_futex(this, hb1, hb2, &key2);
		drop_count++;
	}

out_unlock:
	double_unlock_hb(hb1, hb2);

	/*
	 * drop_futex_key_refs() must be called outside the spinlocks. During
	 * the requeue we moved futex_q's from the hash bucket at key1 to the
	 * one at key2 and updated their key pointer.  We no longer need to
	 * hold the references to key1.
	 */
	while (--drop_count >= 0)
		drop_futex_key_refs(&key1);

out_put_keys:
	put_futex_key(&key2);
out_put_key1:
	put_futex_key(&key1);
out:
	if (pi_state != NULL)
		free_pi_state(pi_state);
	return ret ? ret : task_count;
}


static void get_futex_key_refs(union futex_key *key)
{
	if (!key->both.ptr)
		return;

	switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
	case FUT_OFF_INODE:
		ihold(key->shared.inode);
		break;
	case FUT_OFF_MMSHARED:
		atomic_inc(&key->private.mm->mm_count);
		break;
	}
}


lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
                                bool must_be_identifier) /**< only identifiers are accepted */
{
  skip_spaces (context_p);

  context_p->token.line = context_p->line;
  context_p->token.column = context_p->column;

  if (context_p->source_p < context_p->source_end_p)
  {
    bool create_literal_object = false;

    if (lit_char_is_identifier_start (context_p->source_p) || context_p->source_p[0] == LIT_CHAR_BACKSLASH)
    {
      lexer_parse_identifier (context_p, false);

      if (!must_be_identifier
          && context_p->token.lit_location.length == 3)
      {
        skip_spaces (context_p);

        if (context_p->source_p < context_p->source_end_p
            && context_p->source_p[0] != LIT_CHAR_COLON)
        {
          if (lexer_compare_identifier_to_current (context_p, &lexer_get_literal))
          {
            context_p->token.type = LEXER_PROPERTY_GETTER;
            return;
          }
          else if (lexer_compare_identifier_to_current (context_p, &lexer_set_literal))
          {
            context_p->token.type = LEXER_PROPERTY_SETTER;
            return;
          }
        }
      }

      create_literal_object = true;
    }
    else if (context_p->source_p[0] == LIT_CHAR_DOUBLE_QUOTE
             || context_p->source_p[0] == LIT_CHAR_SINGLE_QUOTE)
    {
      lexer_parse_string (context_p);
      create_literal_object = true;
    }
    else if (!must_be_identifier && context_p->source_p[0] == LIT_CHAR_RIGHT_BRACE)
    {
      context_p->token.type = LEXER_RIGHT_BRACE;
      context_p->source_p += 1;
      context_p->column++;
      return;
    }
    else
    {
      const uint8_t *char_p = context_p->source_p;

      if (char_p[0] == LIT_CHAR_DOT)
      {
        char_p++;
      }

      if (char_p < context_p->source_end_p
          && char_p[0] >= LIT_CHAR_0
          && char_p[0] <= LIT_CHAR_9)
      {
        lexer_parse_number (context_p);
        lexer_construct_number_object (context_p, false, false);
        return;
      }
    }

    if (create_literal_object)
    {
      lexer_construct_literal_object (context_p,
                                      &context_p->token.lit_location,
                                      LEXER_STRING_LITERAL);
      return;
    }
  }

  parser_raise_error (context_p, PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED);
} /* lexer_expect_object_literal_id */


xfs_ioc_swapext(
	xfs_swapext_t	*sxp)
{
	xfs_inode_t     *ip, *tip;
	struct fd	f, tmp;
	int		error = 0;

	/* Pull information for the target fd */
	f = fdget((int)sxp->sx_fdtarget);
	if (!f.file) {
		error = XFS_ERROR(EINVAL);
		goto out;
	}

	if (!(f.file->f_mode & FMODE_WRITE) ||
	    !(f.file->f_mode & FMODE_READ) ||
	    (f.file->f_flags & O_APPEND)) {
		error = XFS_ERROR(EBADF);
		goto out_put_file;
	}

	tmp = fdget((int)sxp->sx_fdtmp);
	if (!tmp.file) {
		error = XFS_ERROR(EINVAL);
		goto out_put_file;
	}

	if (!(tmp.file->f_mode & FMODE_WRITE) ||
	    !(tmp.file->f_mode & FMODE_READ) ||
	    (tmp.file->f_flags & O_APPEND)) {
		error = XFS_ERROR(EBADF);
		goto out_put_tmp_file;
	}

	if (IS_SWAPFILE(file_inode(f.file)) ||
	    IS_SWAPFILE(file_inode(tmp.file))) {
		error = XFS_ERROR(EINVAL);
		goto out_put_tmp_file;
	}

	ip = XFS_I(file_inode(f.file));
	tip = XFS_I(file_inode(tmp.file));

	if (ip->i_mount != tip->i_mount) {
		error = XFS_ERROR(EINVAL);
		goto out_put_tmp_file;
	}

	if (ip->i_ino == tip->i_ino) {
		error = XFS_ERROR(EINVAL);
		goto out_put_tmp_file;
	}

	if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
		error = XFS_ERROR(EIO);
		goto out_put_tmp_file;
	}

	error = xfs_swap_extents(ip, tip, sxp);

 out_put_tmp_file:
	fdput(tmp);
 out_put_file:
	fdput(f);
 out:
	return error;
}


xfs_ioc_setxflags(
	xfs_inode_t		*ip,
	struct file		*filp,
	void			__user *arg)
{
	struct fsxattr		fa;
	unsigned int		flags;
	unsigned int		mask;
	int error;

	if (copy_from_user(&flags, arg, sizeof(flags)))
		return -EFAULT;

	if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
		      FS_NOATIME_FL | FS_NODUMP_FL | \
		      FS_SYNC_FL))
		return -EOPNOTSUPP;

	mask = FSX_XFLAGS;
	if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
		mask |= FSX_NONBLOCK;
	fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));

	error = mnt_want_write_file(filp);
	if (error)
		return error;
	error = xfs_ioctl_setattr(ip, &fa, mask);
	mnt_drop_write_file(filp);
	return -error;
}


struct inode *iget_locked(struct super_block *sb, unsigned long ino)
{
	struct hlist_head *head = inode_hashtable + hash(sb, ino);
	struct inode *inode;

	spin_lock(&inode_hash_lock);
	inode = find_inode_fast(sb, head, ino);
	spin_unlock(&inode_hash_lock);
	if (inode) {
		wait_on_inode(inode);
		return inode;
	}

	inode = alloc_inode(sb);
	if (inode) {
		struct inode *old;

		spin_lock(&inode_hash_lock);
		/* We released the lock, so.. */
		old = find_inode_fast(sb, head, ino);
		if (!old) {
			inode->i_ino = ino;
			spin_lock(&inode->i_lock);
			inode->i_state = I_NEW;
			hlist_add_head(&inode->i_hash, head);
			spin_unlock(&inode->i_lock);
			inode_sb_list_add(inode);
			spin_unlock(&inode_hash_lock);

			/* Return the locked inode with I_NEW set, the
			 * caller is responsible for filling in the contents
			 */
			return inode;
		}

		/*
		 * Uhhuh, somebody else created the same inode under
		 * us. Use the old inode instead of the one we just
		 * allocated.
		 */
		spin_unlock(&inode_hash_lock);
		destroy_inode(inode);
		inode = old;
		wait_on_inode(inode);
	}
	return inode;
}


xfs_attrmulti_attr_get(
	struct inode		*inode,
	unsigned char		*name,
	unsigned char		__user *ubuf,
	__uint32_t		*len,
	__uint32_t		flags)
{
	unsigned char		*kbuf;
	int			error = EFAULT;

	if (*len > XATTR_SIZE_MAX)
		return EINVAL;
	kbuf = kmem_zalloc_large(*len, KM_SLEEP);
	if (!kbuf)
		return ENOMEM;

	error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags);
	if (error)
		goto out_kfree;

	if (copy_to_user(ubuf, kbuf, *len))
		error = EFAULT;

out_kfree:
	kmem_free(kbuf);
	return error;
}


int file_update_time(struct file *file)
{
	struct inode *inode = file_inode(file);
	struct timespec now;
	int sync_it = 0;
	int ret;

	/* First try to exhaust all avenues to not sync */
	if (IS_NOCMTIME(inode))
		return 0;

	now = current_fs_time(inode->i_sb);
	if (!timespec_equal(&inode->i_mtime, &now))
		sync_it = S_MTIME;

	if (!timespec_equal(&inode->i_ctime, &now))
		sync_it |= S_CTIME;

	if (IS_I_VERSION(inode))
		sync_it |= S_VERSION;

	if (!sync_it)
		return 0;

	/* Finally allowed to write? Takes lock. */
	if (__mnt_want_write_file(file))
		return 0;

	ret = update_time(inode, &now, sync_it);
	__mnt_drop_write_file(file);

	return ret;
}


void touch_atime(const struct path *path)
{
	struct vfsmount *mnt = path->mnt;
	struct inode *inode = path->dentry->d_inode;
	struct timespec now;

	if (inode->i_flags & S_NOATIME)
		return;
	if (IS_NOATIME(inode))
		return;
	if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
		return;

	if (mnt->mnt_flags & MNT_NOATIME)
		return;
	if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
		return;

	now = current_fs_time(inode->i_sb);

	if (!relatime_need_update(mnt, inode, now))
		return;

	if (timespec_equal(&inode->i_atime, &now))
		return;

	if (!sb_start_write_trylock(inode->i_sb))
		return;

	if (__mnt_want_write(mnt))
		goto skip_update;
	/*
	 * File systems can error out when updating inodes if they need to
	 * allocate new space to modify an inode (such is the case for
	 * Btrfs), but since we touch atime while walking down the path we
	 * really don't care if we failed to update the atime of the file,
	 * so just ignore the return value.
	 * We may also fail on filesystems that have the ability to make parts
	 * of the fs read only, e.g. subvolumes in Btrfs.
	 */
	update_time(inode, &now, S_ATIME);
	__mnt_drop_write(mnt);
skip_update:
	sb_end_write(inode->i_sb);
}


path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags)
{
	struct file *base = NULL;
	struct nameidata nd;
	int err;

	err = path_init(dfd, name, flags | LOOKUP_PARENT, &nd, &base);
	if (unlikely(err))
		return err;

	current->total_link_count = 0;
	err = link_path_walk(name, &nd);
	if (err)
		goto out;

	err = mountpoint_last(&nd, path);
	while (err > 0) {
		void *cookie;
		struct path link = *path;
		err = may_follow_link(&link, &nd);
		if (unlikely(err))
			break;
		nd.flags |= LOOKUP_PARENT;
		err = follow_link(&link, &nd, &cookie);
		if (err)
			break;
		err = mountpoint_last(&nd, path);
		put_link(&nd, &link, cookie);
	}
out:
	if (base)
		fput(base);

	if (nd.root.mnt && !(nd.flags & LOOKUP_ROOT))
		path_put(&nd.root);

	return err;
}


kern_path_mountpoint(int dfd, const char *name, struct path *path,
			unsigned int flags)
{
	struct filename s = {.name = name};
	return filename_mountpoint(dfd, &s, path, flags);
}


void unlock_two_nondirectories(struct inode *inode1, struct inode *inode2)
{
	if (inode1 && !S_ISDIR(inode1->i_mode))
		mutex_unlock(&inode1->i_mutex);
	if (inode2 && !S_ISDIR(inode2->i_mode) && inode2 != inode1)
		mutex_unlock(&inode2->i_mutex);
}


static int hci_sock_release(struct socket *sock)
{
	struct sock *sk = sock->sk;
	struct hci_dev *hdev;

	BT_DBG("sock %p sk %p", sock, sk);

	if (!sk)
		return 0;

	hdev = hci_pi(sk)->hdev;

	if (hci_pi(sk)->channel == HCI_CHANNEL_MONITOR)
		atomic_dec(&monitor_promisc);

	bt_sock_unlink(&hci_sk_list, sk);

	if (hdev) {
		atomic_dec(&hdev->promisc);
		hci_dev_put(hdev);
	}

	sock_orphan(sk);

	skb_queue_purge(&sk->sk_receive_queue);
	skb_queue_purge(&sk->sk_write_queue);

	sock_put(sk);
	return 0;
}


file_info_start (NautilusDirectory *directory,
                 NautilusFile      *file,
                 gboolean          *doing_io)
{
    GFile *location;
    GetInfoState *state;

    file_info_stop (directory);

    if (directory->details->get_info_in_progress != NULL)
    {
        *doing_io = TRUE;
        return;
    }

    if (!is_needy (file, lacks_info, REQUEST_FILE_INFO))
    {
        return;
    }
    *doing_io = TRUE;

    if (!async_job_start (directory, "file info"))
    {
        return;
    }

    directory->details->get_info_file = file;
    file->details->get_info_failed = FALSE;
    if (file->details->get_info_error)
    {
        g_error_free (file->details->get_info_error);
        file->details->get_info_error = NULL;
    }

    state = g_new (GetInfoState, 1);
    state->directory = directory;
    state->cancellable = g_cancellable_new ();

    directory->details->get_info_in_progress = state;

    location = nautilus_file_get_location (file);
    g_file_query_info_async (location,
                             NAUTILUS_FILE_DEFAULT_ATTRIBUTES,
                             0,
                             G_PRIORITY_DEFAULT,
                             state->cancellable, query_info_callback, state);
    g_object_unref (location);
}


custom_time_skip (va_list *va)
{
    (void) va_arg (*va, int);
}


nautilus_directory_verify_request_counts (NautilusDirectory *directory)
{
    GList *l;
    RequestCounter counters;
    int i;
    gboolean fail;

    fail = FALSE;
    for (i = 0; i < REQUEST_TYPE_LAST; i++)
    {
        counters[i] = 0;
    }
    for (l = directory->details->monitor_list; l != NULL; l = l->next)
    {
        Monitor *monitor = l->data;
        request_counter_add_request (counters, monitor->request);
    }
    for (i = 0; i < REQUEST_TYPE_LAST; i++)
    {
        if (counters[i] != directory->details->monitor_counters[i])
        {
            g_warning ("monitor counter for %i is wrong, expecting %d but found %d",
                       i, counters[i], directory->details->monitor_counters[i]);
            fail = TRUE;
        }
    }
    for (i = 0; i < REQUEST_TYPE_LAST; i++)
    {
        counters[i] = 0;
    }
    for (l = directory->details->call_when_ready_list; l != NULL; l = l->next)
    {
        ReadyCallback *callback = l->data;
        request_counter_add_request (counters, callback->request);
    }
    for (i = 0; i < REQUEST_TYPE_LAST; i++)
    {
        if (counters[i] != directory->details->call_when_ready_counters[i])
        {
            g_warning ("call when ready counter for %i is wrong, expecting %d but found %d",
                       i, counters[i], directory->details->call_when_ready_counters[i]);
            fail = TRUE;
        }
    }
    g_assert (!fail);
}


get_application_no_mime_type_handler_message (NautilusFile *file,
                                              char         *uri)
{
    char *uri_for_display;
    char *name;
    char *error_message;

    name = nautilus_file_get_display_name (file);

    /* Truncate the URI so it doesn't get insanely wide. Note that even
     * though the dialog uses wrapped text, if the URI doesn't contain
     * white space then the text-wrapping code is too stupid to wrap it.
     */
    uri_for_display = eel_str_middle_truncate (name, MAX_URI_IN_DIALOG_LENGTH);
    error_message = g_strdup_printf (_("Could not display “%s”."), uri_for_display);
    g_free (uri_for_display);
    g_free (name);

    return error_message;
}


add_all_files_to_work_queue (NautilusDirectory *directory)
{
    GList *node;
    NautilusFile *file;

    for (node = directory->details->file_list; node != NULL; node = node->next)
    {
        file = NAUTILUS_FILE (node->data);

        nautilus_directory_add_file_to_work_queue (directory, file);
    }
}


find_monitor (NautilusDirectory *directory,
              NautilusFile      *file,
              gconstpointer      client)
{
    Monitor monitor;

    monitor.client = client;
    monitor.file = file;

    return g_list_find_custom (directory->details->monitor_list,
                               &monitor,
                               monitor_key_compare);
}


run_question (CommonJob  *job,
              char       *primary_text,
              char       *secondary_text,
              const char *details_text,
              gboolean    show_all,
              ...)
{
    va_list varargs;
    int res;

    va_start (varargs, show_all);
    res = run_simple_dialog_va (job,
                                FALSE,
                                GTK_MESSAGE_QUESTION,
                                primary_text,
                                secondary_text,
                                details_text,
                                show_all,
                                varargs);
    va_end (varargs);
    return res;
}


nautilus_directory_schedule_dequeue_pending (NautilusDirectory *directory)
{
    if (directory->details->dequeue_pending_idle_id == 0)
    {
        directory->details->dequeue_pending_idle_id
            = g_idle_add (dequeue_pending_idle_callback, directory);
    }
}


nautilus_file_operations_delete (GList                  *files,
                                 GtkWindow              *parent_window,
                                 NautilusDeleteCallback  done_callback,
                                 gpointer                done_callback_data)
{
    trash_or_delete_internal (files, parent_window,
                              FALSE,
                              done_callback, done_callback_data);
}


link_info_nautilus_link_read_callback (GObject      *source_object,
                                       GAsyncResult *res,
                                       gpointer      user_data)
{
    LinkInfoReadState *state;
    gsize file_size;
    char *file_contents;
    gboolean result;
    NautilusDirectory *directory;

    state = user_data;

    if (state->directory == NULL)
    {
        /* Operation was cancelled. Bail out */
        link_info_read_state_free (state);
        return;
    }

    directory = nautilus_directory_ref (state->directory);

    result = g_file_load_contents_finish (G_FILE (source_object),
                                          res,
                                          &file_contents, &file_size,
                                          NULL, NULL);

    state->directory->details->link_info_read_state = NULL;
    async_job_end (state->directory, "link info");

    link_info_got_data (state->directory, state->file, result, file_size, file_contents);

    if (result)
    {
        g_free (file_contents);
    }

    link_info_read_state_free (state);

    nautilus_directory_unref (directory);
}


fat_str_replace (char *str,
                 char  replacement)
{
    gboolean success;
    int i;

    success = FALSE;
    for (i = 0; str[i] != '\0'; i++)
    {
        if (strchr (FAT_FORBIDDEN_CHARACTERS, str[i]) ||
            str[i] < 32)
        {
            success = TRUE;
            str[i] = replacement;
        }
    }

    return success;
}


nautilus_directory_remove_file_from_work_queue (NautilusDirectory *directory,
                                                NautilusFile      *file)
{
    nautilus_file_queue_remove (directory->details->high_priority_queue,
                                file);
    nautilus_file_queue_remove (directory->details->low_priority_queue,
                                file);
    nautilus_file_queue_remove (directory->details->extension_queue,
                                file);
}


nautilus_directory_stop_monitoring_file_list (NautilusDirectory *directory)
{
    if (!directory->details->file_list_monitored)
    {
        g_assert (directory->details->directory_load_in_progress == NULL);
        return;
    }

    directory->details->file_list_monitored = FALSE;
    file_list_cancel (directory);
    nautilus_file_list_unref (directory->details->file_list);
    directory->details->directory_loaded = FALSE;
}


activation_get_activation_uris (ActivateParameters *parameters)
{
    GList *l, *files;
    NautilusFile *file;
    LaunchLocation *location;

    /* link target info might be stale, re-read it */
    for (l = parameters->locations; l != NULL; l = l->next)
    {
        location = l->data;
        file = location->file;

        if (file_was_cancelled (file))
        {
            launch_location_free (location);
            parameters->locations = g_list_delete_link (parameters->locations, l);
            continue;
        }
    }

    if (parameters->locations == NULL)
    {
        activation_parameters_free (parameters);
        return;
    }

    files = get_file_list_for_launch_locations (parameters->locations);
    nautilus_file_list_call_when_ready
        (files, nautilus_mime_actions_get_required_file_attributes (),
        &parameters->files_handle,
        activate_activation_uris_ready_callback, parameters);
    nautilus_file_list_free (files);
}


list_mime_enum_callback (GObject      *source_object,
                         GAsyncResult *res,
                         gpointer      user_data)
{
    MimeListState *state;
    GFileEnumerator *enumerator;
    NautilusDirectory *directory;
    GError *error;

    state = user_data;

    if (g_cancellable_is_cancelled (state->cancellable))
    {
        /* Operation was cancelled. Bail out */
        directory = state->directory;
        directory->details->mime_list_in_progress = NULL;

        async_job_end (directory, "MIME list");
        nautilus_directory_async_state_changed (directory);

        mime_list_state_free (state);

        return;
    }

    error = NULL;
    enumerator = g_file_enumerate_children_finish (G_FILE (source_object),
                                                   res, &error);

    if (enumerator == NULL)
    {
        mime_list_done (state, FALSE);
        g_error_free (error);
        mime_list_state_free (state);
        return;
    }
    else
    {
        state->enumerator = enumerator;
        g_file_enumerator_next_files_async (state->enumerator,
                                            DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
                                            G_PRIORITY_DEFAULT,
                                            state->cancellable,
                                            mime_list_callback,
                                            state);
    }
}


confirm_multiple_windows (GtkWindow *parent_window,
                          int        count,
                          gboolean   use_tabs)
{
    GtkDialog *dialog;
    char *prompt;
    char *detail;
    int response;

    if (count <= SILENT_WINDOW_OPEN_LIMIT)
    {
        return TRUE;
    }

    prompt = _("Are you sure you want to open all files?");
    if (use_tabs)
    {
        detail = g_strdup_printf (ngettext ("This will open %d separate tab.",
                                            "This will open %d separate tabs.", count), count);
    }
    else
    {
        detail = g_strdup_printf (ngettext ("This will open %d separate window.",
                                            "This will open %d separate windows.", count), count);
    }
    dialog = eel_show_yes_no_dialog (prompt, detail,
                                     _("_OK"), _("_Cancel"),
                                     parent_window);
    g_free (detail);

    response = gtk_dialog_run (dialog);
    gtk_widget_destroy (GTK_WIDGET (dialog));

    return response == GTK_RESPONSE_YES;
}


run_warning (CommonJob  *job,
             char       *primary_text,
             char       *secondary_text,
             const char *details_text,
             gboolean    show_all,
             ...)
{
    va_list varargs;
    int res;

    va_start (varargs, show_all);
    res = run_simple_dialog_va (job,
                                FALSE,
                                GTK_MESSAGE_WARNING,
                                primary_text,
                                secondary_text,
                                details_text,
                                show_all,
                                varargs);
    va_end (varargs);
    return res;
}


link_info_stop (NautilusDirectory *directory)
{
    NautilusFile *file;

    if (directory->details->link_info_read_state != NULL)
    {
        file = directory->details->link_info_read_state->file;

        if (file != NULL)
        {
            g_assert (NAUTILUS_IS_FILE (file));
            g_assert (file->details->directory == directory);
            if (is_needy (file,
                          lacks_link_info,
                          REQUEST_LINK_INFO))
            {
                return;
            }
        }

        /* The link info is not wanted, so stop it. */
        link_info_cancel (directory);
    }
}


start_or_stop_io (NautilusDirectory *directory)
{
    NautilusFile *file;
    gboolean doing_io;

    /* Start or stop reading files. */
    file_list_start_or_stop (directory);

    /* Stop any no longer wanted attribute fetches. */
    file_info_stop (directory);
    directory_count_stop (directory);
    deep_count_stop (directory);
    mime_list_stop (directory);
    link_info_stop (directory);
    extension_info_stop (directory);
    mount_stop (directory);
    thumbnail_stop (directory);
    filesystem_info_stop (directory);

    doing_io = FALSE;
    /* Take files that are all done off the queue. */
    while (!nautilus_file_queue_is_empty (directory->details->high_priority_queue))
    {
        file = nautilus_file_queue_head (directory->details->high_priority_queue);

        /* Start getting attributes if possible */
        file_info_start (directory, file, &doing_io);
        link_info_start (directory, file, &doing_io);

        if (doing_io)
        {
            return;
        }

        move_file_to_low_priority_queue (directory, file);
    }

    /* High priority queue must be empty */
    while (!nautilus_file_queue_is_empty (directory->details->low_priority_queue))
    {
        file = nautilus_file_queue_head (directory->details->low_priority_queue);

        /* Start getting attributes if possible */
        mount_start (directory, file, &doing_io);
        directory_count_start (directory, file, &doing_io);
        deep_count_start (directory, file, &doing_io);
        mime_list_start (directory, file, &doing_io);
        thumbnail_start (directory, file, &doing_io);
        filesystem_info_start (directory, file, &doing_io);

        if (doing_io)
        {
            return;
        }

        move_file_to_extension_queue (directory, file);
    }

    /* Low priority queue must be empty */
    while (!nautilus_file_queue_is_empty (directory->details->extension_queue))
    {
        file = nautilus_file_queue_head (directory->details->extension_queue);

        /* Start getting attributes if possible */
        extension_info_start (directory, file, &doing_io);
        if (doing_io)
        {
            return;
        }

        nautilus_directory_remove_file_from_work_queue (directory, file);
    }
}


inhibit_power_manager (CommonJob  *job,
                       const char *message)
{
    job->inhibit_cookie = gtk_application_inhibit (GTK_APPLICATION (g_application_get_default ()),
                                                   GTK_WINDOW (job->parent_window),
                                                   GTK_APPLICATION_INHIBIT_LOGOUT |
                                                   GTK_APPLICATION_INHIBIT_SUSPEND,
                                                   message);
}


set_permissions_file (SetPermissionsJob *job,
                      GFile             *file,
                      GFileInfo         *info)
{
    CommonJob *common;
    GFileInfo *child_info;
    gboolean free_info;
    guint32 current;
    guint32 value;
    guint32 mask;
    GFileEnumerator *enumerator;
    GFile *child;

    common = (CommonJob *) job;

    nautilus_progress_info_pulse_progress (common->progress);

    free_info = FALSE;
    if (info == NULL)
    {
        free_info = TRUE;
        info = g_file_query_info (file,
                                  G_FILE_ATTRIBUTE_STANDARD_TYPE ","
                                  G_FILE_ATTRIBUTE_UNIX_MODE,
                                  G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                  common->cancellable,
                                  NULL);
        /* Ignore errors */
        if (info == NULL)
        {
            return;
        }
    }

    if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
    {
        value = job->dir_permissions;
        mask = job->dir_mask;
    }
    else
    {
        value = job->file_permissions;
        mask = job->file_mask;
    }

    if (!job_aborted (common) &&
        g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE))
    {
        current = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);

        if (common->undo_info != NULL)
        {
            nautilus_file_undo_info_rec_permissions_add_file (NAUTILUS_FILE_UNDO_INFO_REC_PERMISSIONS (common->undo_info),
                                                              file, current);
        }

        current = (current & ~mask) | value;

        g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_MODE,
                                     current, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                     common->cancellable, NULL);
    }

    if (!job_aborted (common) &&
        g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
    {
        enumerator = g_file_enumerate_children (file,
                                                G_FILE_ATTRIBUTE_STANDARD_NAME ","
                                                G_FILE_ATTRIBUTE_STANDARD_TYPE ","
                                                G_FILE_ATTRIBUTE_UNIX_MODE,
                                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                                common->cancellable,
                                                NULL);
        if (enumerator)
        {
            while (!job_aborted (common) &&
                   (child_info = g_file_enumerator_next_file (enumerator, common->cancellable, NULL)) != NULL)
            {
                child = g_file_get_child (file,
                                          g_file_info_get_name (child_info));
                set_permissions_file (job, child, child_info);
                g_object_unref (child);
                g_object_unref (child_info);
            }
            g_file_enumerator_close (enumerator, common->cancellable, NULL);
            g_object_unref (enumerator);
        }
    }
    if (free_info)
    {
        g_object_unref (info);
    }
}


nautilus_file_operations_new_folder (GtkWidget              *parent_view,
                                     GdkPoint               *target_point,
                                     const char             *parent_dir,
                                     const char             *folder_name,
                                     NautilusCreateCallback  done_callback,
                                     gpointer                done_callback_data)
{
    GTask *task;
    CreateJob *job;
    GtkWindow *parent_window;

    parent_window = NULL;
    if (parent_view)
    {
        parent_window = (GtkWindow *) gtk_widget_get_ancestor (parent_view, GTK_TYPE_WINDOW);
    }

    job = op_job_new (CreateJob, parent_window);
    job->done_callback = done_callback;
    job->done_callback_data = done_callback_data;
    job->dest_dir = g_file_new_for_uri (parent_dir);
    job->filename = g_strdup (folder_name);
    job->make_dir = TRUE;
    if (target_point != NULL)
    {
        job->position = *target_point;
        job->has_position = TRUE;
    }

    if (!nautilus_file_undo_manager_is_operating ())
    {
        job->common.undo_info = nautilus_file_undo_info_create_new (NAUTILUS_FILE_UNDO_OP_CREATE_FOLDER);
    }

    task = g_task_new (NULL, job->common.cancellable, create_task_done, job);
    g_task_set_task_data (task, job, NULL);
    g_task_run_in_thread (task, create_task_thread_func);
    g_object_unref (task);
}


move_file_to_extension_queue (NautilusDirectory *directory,
                              NautilusFile      *file)
{
    /* Must add before removing to avoid ref underflow */
    nautilus_file_queue_enqueue (directory->details->extension_queue,
                                 file);
    nautilus_file_queue_remove (directory->details->low_priority_queue,
                                file);
}


new_files_callback (GObject      *source_object,
                    GAsyncResult *res,
                    gpointer      user_data)
{
    NautilusDirectory *directory;
    GFileInfo *info;
    NewFilesState *state;

    state = user_data;

    if (state->directory == NULL)
    {
        /* Operation was cancelled. Bail out */
        new_files_state_unref (state);
        return;
    }

    directory = nautilus_directory_ref (state->directory);

    /* Queue up the new file. */
    info = g_file_query_info_finish (G_FILE (source_object), res, NULL);
    if (info != NULL)
    {
        directory_load_one (directory, info);
        g_object_unref (info);
    }

    new_files_state_unref (state);

    nautilus_directory_unref (directory);
}


mount_state_free (MountState *state)
{
    g_object_unref (state->cancellable);
    g_free (state);
}


activate_callback (GList    *files,
                   gpointer  callback_data)
{
    ActivateParameters *parameters = callback_data;
    GList *l, *next;
    NautilusFile *file;
    LaunchLocation *location;

    parameters->files_handle = NULL;

    for (l = parameters->locations; l != NULL; l = next)
    {
        location = l->data;
        file = location->file;
        next = l->next;

        if (file_was_cancelled (file))
        {
            launch_location_free (location);
            parameters->locations = g_list_delete_link (parameters->locations, l);
            continue;
        }

        if (file_was_not_mounted (file))
        {
            if (parameters->tried_mounting)
            {
                launch_location_free (location);
                parameters->locations = g_list_delete_link (parameters->locations, l);
            }
            else
            {
                parameters->not_mounted = g_list_prepend (parameters->not_mounted,
                                                          nautilus_file_ref (file));
            }
            continue;
        }
    }

    if (parameters->not_mounted != NULL)
    {
        activation_mount_not_mounted (parameters);
    }
    else
    {
        activate_files (parameters);
    }
}


compress_job_on_completed (AutoarCompressor *compressor,
                           gpointer          user_data)
{
    CompressJob *compress_job = user_data;
    g_autoptr (GFile) destination_directory = NULL;
    char *status;

    if (compress_job->total_files == 1)
    {
        status = f (_("Compressed “%B” into “%B”"),
                    G_FILE (compress_job->source_files->data),
                    compress_job->output_file);
    }
    else
    {
        status = f (ngettext ("Compressed %'d file into “%B”",
                              "Compressed %'d files into “%B”",
                              compress_job->total_files),
                    compress_job->total_files,
                    compress_job->output_file);
    }

    nautilus_progress_info_take_status (compress_job->common.progress,
                                        status);

    nautilus_file_changes_queue_file_added (compress_job->output_file);

    destination_directory = g_file_get_parent (compress_job->output_file);
    nautilus_progress_info_set_destination (compress_job->common.progress,
                                            destination_directory);
}


custom_basename_skip (va_list *va)
{
    (void) va_arg (*va, GFile *);
}


more_files_callback (GObject      *source_object,
                     GAsyncResult *res,
                     gpointer      user_data)
{
    DirectoryLoadState *state;
    NautilusDirectory *directory;
    GError *error;
    GList *files, *l;
    GFileInfo *info;

    state = user_data;

    if (state->directory == NULL)
    {
        /* Operation was cancelled. Bail out */
        directory_load_state_free (state);
        return;
    }

    directory = nautilus_directory_ref (state->directory);

    g_assert (directory->details->directory_load_in_progress != NULL);
    g_assert (directory->details->directory_load_in_progress == state);

    error = NULL;
    files = g_file_enumerator_next_files_finish (state->enumerator,
                                                 res, &error);

    for (l = files; l != NULL; l = l->next)
    {
        info = l->data;
        directory_load_one (directory, info);
        g_object_unref (info);
    }

    if (files == NULL)
    {
        directory_load_done (directory, error);
        directory_load_state_free (state);
    }
    else
    {
        g_file_enumerator_next_files_async (state->enumerator,
                                            DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
                                            G_PRIORITY_DEFAULT,
                                            state->cancellable,
                                            more_files_callback,
                                            state);
    }

    nautilus_directory_unref (directory);

    if (error)
    {
        g_error_free (error);
    }

    g_list_free (files);
}


link_task_thread_func (GTask        *task,
                       gpointer      source_object,
                       gpointer      task_data,
                       GCancellable *cancellable)
{
    CopyMoveJob *job;
    CommonJob *common;
    GFile *src;
    GdkPoint *point;
    char *dest_fs_type;
    int total, left;
    int i;
    GList *l;

    job = task_data;
    common = &job->common;

    dest_fs_type = NULL;

    nautilus_progress_info_start (job->common.progress);

    verify_destination (&job->common,
                        job->destination,
                        NULL,
                        -1);
    if (job_aborted (common))
    {
        goto aborted;
    }

    total = left = g_list_length (job->files);

    report_preparing_link_progress (job, total, left);

    i = 0;
    for (l = job->files;
         l != NULL && !job_aborted (common);
         l = l->next)
    {
        src = l->data;

        if (i < job->n_icon_positions)
        {
            point = &job->icon_positions[i];
        }
        else
        {
            point = NULL;
        }

        link_file (job, src, job->destination,
                   &dest_fs_type, job->debuting_files,
                   point, left);
        report_preparing_link_progress (job, total, --left);
        i++;
    }

aborted:
    g_free (dest_fs_type);
}


query_filesystem_info_callback (GObject      *source_object,
                                GAsyncResult *res,
                                gpointer      user_data)
{
    GFileInfo *info;
    FilesystemInfoState *state;

    state = user_data;
    if (state->directory == NULL)
    {
        /* Operation was cancelled. Bail out */
        filesystem_info_state_free (state);
        return;
    }

    info = g_file_query_filesystem_info_finish (G_FILE (source_object), res, NULL);

    got_filesystem_info (state, info);

    if (info != NULL)
    {
        g_object_unref (info);
    }
}


map_possibly_volatile_file_to_real_on_write (GFile              *volatile_file,
                                             GFileOutputStream  *stream,
                                             GCancellable       *cancellable,
                                             GError            **error)
{
    GFile *real_file = NULL;
    GFileInfo *info = NULL;

    info = g_file_output_stream_query_info (stream,
                                            G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
                                            G_FILE_ATTRIBUTE_STANDARD_IS_VOLATILE ","
                                            G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
                                            cancellable,
                                            error);
    if (info == NULL)
    {
        return NULL;
    }
    else
    {
        gboolean is_volatile;

        is_volatile = g_file_info_get_attribute_boolean (info,
                                                         G_FILE_ATTRIBUTE_STANDARD_IS_VOLATILE);
        if (is_volatile)
        {
            const gchar *target;

            target = g_file_info_get_symlink_target (info);
            real_file = g_file_resolve_relative_path (volatile_file, target);
        }
    }

    g_object_unref (info);

    if (real_file == NULL)
    {
        real_file = g_object_ref (volatile_file);
    }

    return real_file;
}


request_counter_add_request (RequestCounter counter,
                             Request        request)
{
    guint i;

    for (i = 0; i < REQUEST_TYPE_LAST; i++)
    {
        if (REQUEST_WANTS_TYPE (request, i))
        {
            counter[i]++;
        }
    }
}


nautilus_file_operations_new_file (GtkWidget              *parent_view,
                                   GdkPoint               *target_point,
                                   const char             *parent_dir,
                                   const char             *target_filename,
                                   const char             *initial_contents,
                                   int                     length,
                                   NautilusCreateCallback  done_callback,
                                   gpointer                done_callback_data)
{
    GTask *task;
    CreateJob *job;
    GtkWindow *parent_window;

    parent_window = NULL;
    if (parent_view)
    {
        parent_window = (GtkWindow *) gtk_widget_get_ancestor (parent_view, GTK_TYPE_WINDOW);
    }

    job = op_job_new (CreateJob, parent_window);
    job->done_callback = done_callback;
    job->done_callback_data = done_callback_data;
    job->dest_dir = g_file_new_for_uri (parent_dir);
    if (target_point != NULL)
    {
        job->position = *target_point;
        job->has_position = TRUE;
    }
    job->src_data = g_memdup (initial_contents, length);
    job->length = length;
    job->filename = g_strdup (target_filename);

    if (!nautilus_file_undo_manager_is_operating ())
    {
        job->common.undo_info = nautilus_file_undo_info_create_new (NAUTILUS_FILE_UNDO_OP_CREATE_EMPTY_FILE);
    }

    task = g_task_new (NULL, job->common.cancellable, create_task_done, job);
    g_task_set_task_data (task, job, NULL);
    g_task_run_in_thread (task, create_task_thread_func);
    g_object_unref (task);
}


open_with_response_cb (GtkDialog *dialog,
                       gint       response_id,
                       gpointer   user_data)
{
    GtkWindow *parent_window;
    NautilusFile *file;
    GList files;
    GAppInfo *info;
    ActivateParametersInstall *parameters = user_data;

    if (response_id != GTK_RESPONSE_OK)
    {
        gtk_widget_destroy (GTK_WIDGET (dialog));
        return;
    }

    parent_window = parameters->parent_window;
    file = g_object_get_data (G_OBJECT (dialog), "mime-action:file");
    info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (dialog));

    gtk_widget_destroy (GTK_WIDGET (dialog));

    g_signal_emit_by_name (nautilus_signaller_get_current (), "mime-data-changed");

    files.next = NULL;
    files.prev = NULL;
    files.data = file;
    nautilus_launch_application (info, &files, parent_window);

    g_object_unref (info);

    activate_parameters_install_free (parameters);
}


nautilus_file_operations_copy_file (GFile                *source_file,
                                    GFile                *target_dir,
                                    const gchar          *source_display_name,
                                    const gchar          *new_name,
                                    GtkWindow            *parent_window,
                                    NautilusCopyCallback  done_callback,
                                    gpointer              done_callback_data)
{
    GTask *task;
    CopyMoveJob *job;

    job = op_job_new (CopyMoveJob, parent_window);
    job->done_callback = done_callback;
    job->done_callback_data = done_callback_data;
    job->files = g_list_append (NULL, g_object_ref (source_file));
    job->destination = g_object_ref (target_dir);
    /* Need to indicate the destination for the operation notification open
     * button. */
    nautilus_progress_info_set_destination (((CommonJob *) job)->progress, target_dir);
    job->target_name = g_strdup (new_name);
    job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, NULL);

    if (source_display_name != NULL)
    {
        gchar *path;

        path = g_build_filename ("/", source_display_name, NULL);
        job->fake_display_source = g_file_new_for_path (path);

        g_free (path);
    }

    inhibit_power_manager ((CommonJob *) job, _("Copying Files"));

    task = g_task_new (NULL, job->common.cancellable, copy_task_done, job);
    g_task_set_task_data (task, job, NULL);
    g_task_run_in_thread (task, copy_task_thread_func);
    g_object_unref (task);
}


compress_job_on_progress (AutoarCompressor *compressor,
                          guint64           completed_size,
                          guint             completed_files,
                          gpointer          user_data)
{
    CompressJob *compress_job = user_data;
    CommonJob *common = user_data;
    char *status;
    char *details;
    int files_left;
    double elapsed;
    double transfer_rate;
    int remaining_time;

    files_left = compress_job->total_files - completed_files;

    if (compress_job->total_files == 1)
    {
        status = f (_("Compressing “%B” into “%B”"),
                    G_FILE (compress_job->source_files->data),
                    compress_job->output_file);
    }
    else
    {
        status = f (ngettext ("Compressing %'d file into “%B”",
                              "Compressing %'d files into “%B”",
                              compress_job->total_files),
                    compress_job->total_files,
                    compress_job->output_file);
    }

    nautilus_progress_info_take_status (common->progress, status);

    elapsed = g_timer_elapsed (common->time, NULL);

    transfer_rate = 0;
    remaining_time = -1;

    if (elapsed > 0)
    {
        if (completed_size > 0)
        {
            transfer_rate = completed_size / elapsed;
            remaining_time = (compress_job->total_size - completed_size) / transfer_rate;
        }
        else if (completed_files > 0)
        {
            transfer_rate = completed_files / elapsed;
            remaining_time = (compress_job->total_files - completed_files) / transfer_rate;
        }
    }

    if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE ||
        transfer_rate == 0)
    {
        if (compress_job->total_files == 1)
        {
            /* To translators: %S will expand to a size like "2 bytes" or "3 MB", so something like "4 kb / 4 MB" */
            details = f (_("%S / %S"), completed_size, compress_job->total_size);
        }
        else
        {
            details = f (_("%'d / %'d"),
                         files_left > 0 ? completed_files + 1 : completed_files,
                         compress_job->total_files);
        }
    }
    else
    {
        if (compress_job->total_files == 1)
        {
            if (files_left > 0)
            {
                /* To translators: %S will expand to a size like "2 bytes" or "3 MB", %T to a time duration like
                 * "2 minutes". So the whole thing will be something like "2 kb / 4 MB -- 2 hours left (4kb/sec)"
                 *
                 * The singular/plural form will be used depending on the remaining time (i.e. the %T argument).
                 */
                details = f (ngettext ("%S / %S \xE2\x80\x94 %T left (%S/sec)",
                                       "%S / %S \xE2\x80\x94 %T left (%S/sec)",
                                       seconds_count_format_time_units (remaining_time)),
                             completed_size, compress_job->total_size,
                             remaining_time,
                             (goffset) transfer_rate);
            }
            else
            {
                /* To translators: %S will expand to a size like "2 bytes" or "3 MB". */
                details = f (_("%S / %S"),
                             completed_size,
                             compress_job->total_size);
            }
        }
        else
        {
            if (files_left > 0)
            {
                /* To translators: %T will expand to a time duration like "2 minutes".
                 * So the whole thing will be something like "1 / 5 -- 2 hours left (4kb/sec)"
                 *
                 * The singular/plural form will be used depending on the remaining time (i.e. the %T argument).
                 */
                details = f (ngettext ("%'d / %'d \xE2\x80\x94 %T left (%S/sec)",
                                       "%'d / %'d \xE2\x80\x94 %T left (%S/sec)",
                                       seconds_count_format_time_units (remaining_time)),
                             completed_files + 1, compress_job->total_files,
                             remaining_time,
                             (goffset) transfer_rate);
            }
            else
            {
                /* To translators: %'d is the number of files completed for the operation,
                 * so it will be something like 2/14. */
                details = f (_("%'d / %'d"),
                             completed_files,
                             compress_job->total_files);
            }
        }
    }

    nautilus_progress_info_take_details (common->progress, details);

    if (elapsed > SECONDS_NEEDED_FOR_APROXIMATE_TRANSFER_RATE)
    {
        nautilus_progress_info_set_remaining_time (common->progress,
                                                   remaining_time);
        nautilus_progress_info_set_elapsed_time (common->progress,
                                                 elapsed);
    }

    nautilus_progress_info_set_progress (common->progress,
                                         completed_size,
                                         compress_job->total_size);
}


launch_location_update_from_file (LaunchLocation *location,
                                  NautilusFile   *file)
{
    nautilus_file_unref (location->file);
    g_free (location->uri);
    location->file = nautilus_file_ref (file);
    location->uri = nautilus_file_get_uri (file);
}


mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod)
{
  struct RProc *proc;
  mrb_value ary;
  struct RClass *c = NULL;

  mrb_get_args(mrb, "");
  ary = mrb_ary_new(mrb);
  proc = mrb->c->ci[-1].proc;   /* callee proc */
  mrb_assert(!MRB_PROC_CFUNC_P(proc));
  while (proc) {
    if (MRB_PROC_SCOPE_P(proc)) {
      struct RClass *c2 = MRB_PROC_TARGET_CLASS(proc);

      if (c2 != c) {
        c = c2;
        mrb_ary_push(mrb, ary, mrb_obj_value(c));
      }
    }
    proc = proc->upper;
  }
  return ary;
}


envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size)
{
  mrb_callinfo *ci = mrb->c->cibase;

  if (newbase == oldbase) return;
  while (ci <= mrb->c->ci) {
    struct REnv *e = ci->env;
    mrb_value *st;

    if (e && MRB_ENV_STACK_SHARED_P(e) &&
        (st = e->stack) && oldbase <= st && st < oldbase+size) {
      ptrdiff_t off = e->stack - oldbase;

      e->stack = newbase + off;
    }

    if (ci->proc && MRB_PROC_ENV_P(ci->proc) && ci->env != MRB_PROC_ENV(ci->proc)) {
      e = MRB_PROC_ENV(ci->proc);

      if (e && MRB_ENV_STACK_SHARED_P(e) &&
          (st = e->stack) && oldbase <= st && st < oldbase+size) {
        ptrdiff_t off = e->stack - oldbase;

        e->stack = newbase + off;
      }
    }

    ci->stackent = newbase + (ci->stackent - oldbase);
    ci++;
  }
}


uvenv(mrb_state *mrb, int up)
{
  struct RProc *proc = mrb->c->ci->proc;
  struct REnv *e;

  while (up--) {
    proc = proc->upper;
    if (!proc) return NULL;
  }
  e = MRB_PROC_ENV(proc);
  if (e) return e;              /* proc has enclosed env */
  else {
    mrb_callinfo *ci = mrb->c->ci;
    mrb_callinfo *cb = mrb->c->cibase;

    while (cb <= ci) {
      if (ci->proc == proc) {
        return ci->env;
      }
      ci--;
    }
  }
  return NULL;
}


top_proc(mrb_state *mrb, struct RProc *proc)
{
  while (proc->upper) {
    if (MRB_PROC_SCOPE_P(proc) || MRB_PROC_STRICT_P(proc))
      return proc;
    proc = proc->upper;
  }
  return proc;
}


uint32_t translateZeroToUnlimited(uint32_t limit) {
  return (limit != 0) ? limit : std::numeric_limits<uint32_t>::max();
}


ActiveClient::~ActiveClient() { releaseResourcesBase(); }


bool ConnPoolImplBase::maybePreconnectImpl(float global_preconnect_ratio) {
  ASSERT(!deferred_deleting_);
  return tryCreateNewConnection(global_preconnect_ratio) == ConnectionResult::CreatedNewConnection;
}


TEST_P(CdsIntegrationTest, CdsClusterDownWithLotsOfIdleConnections) {
  constexpr int num_requests = 2000;
  // Make upstream H/1 so it creates connection for each request
  upstream_codec_type_ = Http::CodecType::HTTP1;
  // Relax default circuit breaker limits and timeouts so Envoy can accumulate a lot of idle
  // connections
  cluster_creator_ = &ConfigHelper::buildH1ClusterWithHighCircuitBreakersLimits;
  config_helper_.addConfigModifier(
      [&](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
              hcm) -> void {
        hcm.mutable_route_config()
            ->mutable_virtual_hosts(0)
            ->mutable_routes(0)
            ->mutable_route()
            ->mutable_timeout()
            ->set_seconds(600);
        hcm.mutable_route_config()
            ->mutable_virtual_hosts(0)
            ->mutable_routes(0)
            ->mutable_route()
            ->mutable_idle_timeout()
            ->set_seconds(600);
      });
  initialize();
  std::vector<IntegrationStreamDecoderPtr> responses;
  std::vector<FakeHttpConnectionPtr> upstream_connections;
  std::vector<FakeStreamPtr> upstream_requests;
  codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http"))));
  // The first loop establishes a lot of open connections with active requests to upstream
  for (int i = 0; i < num_requests; ++i) {
    Http::TestRequestHeaderMapImpl request_headers{{":method", "GET"},
                                                   {":path", "/cluster1"},
                                                   {":scheme", "http"},
                                                   {":authority", "host"},
                                                   {"x-lyft-user-id", absl::StrCat(i)}};

    auto response = codec_client_->makeHeaderOnlyRequest(request_headers);
    responses.push_back(std::move(response));

    FakeHttpConnectionPtr fake_upstream_connection;
    waitForNextUpstreamConnection({UpstreamIndex1}, TestUtility::DefaultTimeout,
                                  fake_upstream_connection);
    // Wait for the next stream on the upstream connection.
    FakeStreamPtr upstream_request;
    AssertionResult result =
        fake_upstream_connection->waitForNewStream(*dispatcher_, upstream_request);
    RELEASE_ASSERT(result, result.message());
    // Wait for the stream to be completely received.
    result = upstream_request->waitForEndStream(*dispatcher_);
    RELEASE_ASSERT(result, result.message());
    upstream_connections.push_back(std::move(fake_upstream_connection));
    upstream_requests.push_back(std::move(upstream_request));
  }

  // This loop completes all requests making the all upstream connections idle
  for (int i = 0; i < num_requests; ++i) {
    // Send response headers, and end_stream if there is no response body.
    upstream_requests[i]->encodeHeaders(default_response_headers_, true);
    // Wait for the response to be read by the codec client.
    RELEASE_ASSERT(responses[i]->waitForEndStream(), "unexpected timeout");
    ASSERT_TRUE(responses[i]->complete());
    EXPECT_EQ("200", responses[i]->headers().getStatusValue());
  }

  test_server_->waitForCounterGe("cluster_manager.cluster_added", 1);

  // Tell Envoy that cluster_1 is gone. Envoy will try to close all idle connections
  EXPECT_TRUE(compareDiscoveryRequest(Config::TypeUrl::get().Cluster, "55", {}, {}, {}));
  sendDiscoveryResponse<envoy::config::cluster::v3::Cluster>(Config::TypeUrl::get().Cluster, {}, {},
                                                             {ClusterName1}, "42");
  // We can continue the test once we're sure that Envoy's ClusterManager has made use of
  // the DiscoveryResponse that says cluster_1 is gone.
  test_server_->waitForCounterGe("cluster_manager.cluster_removed", 1);

  // If we made it this far then everything is ok.
  for (int i = 0; i < num_requests; ++i) {
    AssertionResult result = upstream_connections[i]->close();
    RELEASE_ASSERT(result, result.message());
    result = upstream_connections[i]->waitForDisconnect();
    RELEASE_ASSERT(result, result.message());
  }
  upstream_connections.clear();
  cleanupUpstreamAndDownstream();
  ASSERT_TRUE(codec_client_->waitForDisconnect());
}


void ConnPoolImplBase::deleteIsPendingImpl() {
  deferred_deleting_ = true;
  ASSERT(isIdleImpl());
  ASSERT(connecting_stream_capacity_ == 0);
}


void ConnPoolImplBase::onUpstreamReady() {
  while (!pending_streams_.empty() && !ready_clients_.empty()) {
    ActiveClientPtr& client = ready_clients_.front();
    ENVOY_CONN_LOG(debug, "attaching to next stream", *client);
    // Pending streams are pushed onto the front, so pull from the back.
    attachStreamToClient(*client, pending_streams_.back()->context());
    state_.decrPendingStreams(1);
    pending_streams_.pop_back();
  }
  if (!pending_streams_.empty()) {
    tryCreateNewConnections();
  }
}


void ConfigHelper::setLds(absl::string_view version_info) {
  applyConfigModifiers();

  envoy::service::discovery::v3::DiscoveryResponse lds;
  lds.set_version_info(std::string(version_info));
  for (auto& listener : bootstrap_.static_resources().listeners()) {
    ProtobufWkt::Any* resource = lds.add_resources();
    resource->PackFrom(listener);
  }

  const std::string lds_filename =
      bootstrap().dynamic_resources().lds_config().path_config_source().path();
  std::string file = TestEnvironment::writeStringToFileForTest(
      "new_lds_file", MessageUtil::getJsonStringFromMessageOrDie(lds));
  TestEnvironment::renameFile(file, lds_filename);
}


void ConnPoolImplBase::checkForIdleAndCloseIdleConnsIfDraining() {
  if (is_draining_for_deletion_) {
    closeIdleConnectionsForDrainingPool();
  }

  checkForIdleAndNotify();
}


static krb5_boolean ks_is_master_key_principal(krb5_context context,
					       krb5_const_principal princ)
{
	return krb5_princ_size(context, princ) == 2 &&
	       ks_data_eq_string(princ->data[0], "K") &&
	       ks_data_eq_string(princ->data[1], "M");
}


static int decode_update_thread_context(AVCodecContext *dst,
                                        const AVCodecContext *src)
{
    H264Context *h = dst->priv_data, *h1 = src->priv_data;
    int inited = h->context_initialized, err = 0;
    int context_reinitialized = 0;
    int i, ret;

    if (dst == src)
        return 0;

    if (inited &&
        (h->width                 != h1->width                 ||
         h->height                != h1->height                ||
         h->mb_width              != h1->mb_width              ||
         h->mb_height             != h1->mb_height             ||
         h->sps.bit_depth_luma    != h1->sps.bit_depth_luma    ||
         h->sps.chroma_format_idc != h1->sps.chroma_format_idc ||
         h->sps.colorspace        != h1->sps.colorspace)) {

        /* set bits_per_raw_sample to the previous value. the check for changed
         * bit depth in h264_set_parameter_from_sps() uses it and sets it to
         * the current value */
        h->avctx->bits_per_raw_sample = h->sps.bit_depth_luma;

        av_freep(&h->bipred_scratchpad);

        h->width     = h1->width;
        h->height    = h1->height;
        h->mb_height = h1->mb_height;
        h->mb_width  = h1->mb_width;
        h->mb_num    = h1->mb_num;
        h->mb_stride = h1->mb_stride;
        h->b_stride  = h1->b_stride;
        // SPS/PPS
        if ((ret = copy_parameter_set((void **)h->sps_buffers,
                                      (void **)h1->sps_buffers,
                                      MAX_SPS_COUNT, sizeof(SPS))) < 0)
            return ret;
        h->sps = h1->sps;
        if ((ret = copy_parameter_set((void **)h->pps_buffers,
                                      (void **)h1->pps_buffers,
                                      MAX_PPS_COUNT, sizeof(PPS))) < 0)
            return ret;
        h->pps = h1->pps;

        if ((err = h264_slice_header_init(h, 1)) < 0) {
            av_log(h->avctx, AV_LOG_ERROR, "h264_slice_header_init() failed");
            return err;
        }
        context_reinitialized = 1;

#if 0
        h264_set_parameter_from_sps(h);
        //Note we set context_reinitialized which will cause h264_set_parameter_from_sps to be reexecuted
        h->cur_chroma_format_idc = h1->cur_chroma_format_idc;
#endif
    }
    /* update linesize on resize for h264. The h264 decoder doesn't
     * necessarily call ff_MPV_frame_start in the new thread */
    h->linesize   = h1->linesize;
    h->uvlinesize = h1->uvlinesize;

    /* copy block_offset since frame_start may not be called */
    memcpy(h->block_offset, h1->block_offset, sizeof(h->block_offset));

    if (!inited) {
        for (i = 0; i < MAX_SPS_COUNT; i++)
            av_freep(h->sps_buffers + i);

        for (i = 0; i < MAX_PPS_COUNT; i++)
            av_freep(h->pps_buffers + i);

        av_freep(&h->rbsp_buffer[0]);
        av_freep(&h->rbsp_buffer[1]);
        memcpy(h, h1, offsetof(H264Context, intra_pcm_ptr));
        memcpy(&h->cabac, &h1->cabac,
               sizeof(H264Context) - offsetof(H264Context, cabac));
        av_assert0((void*)&h->cabac == &h->mb_padding + 1);

        memset(h->sps_buffers, 0, sizeof(h->sps_buffers));
        memset(h->pps_buffers, 0, sizeof(h->pps_buffers));

        memset(&h->er, 0, sizeof(h->er));
        memset(&h->me, 0, sizeof(h->me));
        memset(&h->mb, 0, sizeof(h->mb));
        memset(&h->mb_luma_dc, 0, sizeof(h->mb_luma_dc));
        memset(&h->mb_padding, 0, sizeof(h->mb_padding));

        h->avctx             = dst;
        h->DPB               = NULL;
        h->qscale_table_pool = NULL;
        h->mb_type_pool      = NULL;
        h->ref_index_pool    = NULL;
        h->motion_val_pool   = NULL;
        for (i = 0; i < 2; i++) {
            h->rbsp_buffer[i] = NULL;
            h->rbsp_buffer_size[i] = 0;
        }

        if (h1->context_initialized) {
        h->context_initialized = 0;

        memset(&h->cur_pic, 0, sizeof(h->cur_pic));
        av_frame_unref(&h->cur_pic.f);
        h->cur_pic.tf.f = &h->cur_pic.f;

        ret = ff_h264_alloc_tables(h);
        if (ret < 0) {
            av_log(dst, AV_LOG_ERROR, "Could not allocate memory\n");
            return ret;
        }
        ret = context_init(h);
        if (ret < 0) {
            av_log(dst, AV_LOG_ERROR, "context_init() failed.\n");
            return ret;
        }
        }

        h->bipred_scratchpad = NULL;
        h->edge_emu_buffer   = NULL;

        h->thread_context[0] = h;
        h->context_initialized = h1->context_initialized;
    }

    h->avctx->coded_height  = h1->avctx->coded_height;
    h->avctx->coded_width   = h1->avctx->coded_width;
    h->avctx->width         = h1->avctx->width;
    h->avctx->height        = h1->avctx->height;
    h->coded_picture_number = h1->coded_picture_number;
    h->first_field          = h1->first_field;
    h->picture_structure    = h1->picture_structure;
    h->qscale               = h1->qscale;
    h->droppable            = h1->droppable;
    h->low_delay            = h1->low_delay;

    for (i = 0; h->DPB && i < MAX_PICTURE_COUNT; i++) {
        unref_picture(h, &h->DPB[i]);
        if (h1->DPB && h1->DPB[i].f.buf[0] &&
            (ret = ref_picture(h, &h->DPB[i], &h1->DPB[i])) < 0)
            return ret;
    }

    h->cur_pic_ptr = REBASE_PICTURE(h1->cur_pic_ptr, h, h1);
    unref_picture(h, &h->cur_pic);
    if (h1->cur_pic.f.buf[0] && (ret = ref_picture(h, &h->cur_pic, &h1->cur_pic)) < 0)
        return ret;

    h->workaround_bugs = h1->workaround_bugs;
    h->low_delay       = h1->low_delay;
    h->droppable       = h1->droppable;

    // extradata/NAL handling
    h->is_avc = h1->is_avc;

    // SPS/PPS
    if ((ret = copy_parameter_set((void **)h->sps_buffers,
                                  (void **)h1->sps_buffers,
                                  MAX_SPS_COUNT, sizeof(SPS))) < 0)
        return ret;
    h->sps = h1->sps;
    if ((ret = copy_parameter_set((void **)h->pps_buffers,
                                  (void **)h1->pps_buffers,
                                  MAX_PPS_COUNT, sizeof(PPS))) < 0)
        return ret;
    h->pps = h1->pps;

    // Dequantization matrices
    // FIXME these are big - can they be only copied when PPS changes?
    copy_fields(h, h1, dequant4_buffer, dequant4_coeff);

    for (i = 0; i < 6; i++)
        h->dequant4_coeff[i] = h->dequant4_buffer[0] +
                               (h1->dequant4_coeff[i] - h1->dequant4_buffer[0]);

    for (i = 0; i < 6; i++)
        h->dequant8_coeff[i] = h->dequant8_buffer[0] +
                               (h1->dequant8_coeff[i] - h1->dequant8_buffer[0]);

    h->dequant_coeff_pps = h1->dequant_coeff_pps;

    // POC timing
    copy_fields(h, h1, poc_lsb, redundant_pic_count);

    // reference lists
    copy_fields(h, h1, short_ref, cabac_init_idc);

    copy_picture_range(h->short_ref, h1->short_ref, 32, h, h1);
    copy_picture_range(h->long_ref, h1->long_ref, 32, h, h1);
    copy_picture_range(h->delayed_pic, h1->delayed_pic,
                       MAX_DELAYED_PIC_COUNT + 2, h, h1);

    h->frame_recovered       = h1->frame_recovered;

    if (context_reinitialized)
        h264_set_parameter_from_sps(h);

    if (!h->cur_pic_ptr)
        return 0;

    if (!h->droppable) {
        err = ff_h264_execute_ref_pic_marking(h, h->mmco, h->mmco_index);
        h->prev_poc_msb = h->poc_msb;
        h->prev_poc_lsb = h->poc_lsb;
    }
    h->prev_frame_num_offset = h->frame_num_offset;
    h->prev_frame_num        = h->frame_num;
    h->outputed_poc          = h->next_outputed_poc;

    h->recovery_frame        = h1->recovery_frame;

    return err;
}


int ff_h264_decode_extradata(H264Context *h, const uint8_t *buf, int size)
{
    AVCodecContext *avctx = h->avctx;
    int ret;

    if (!buf || size <= 0)
        return -1;

    if (buf[0] == 1) {
        int i, cnt, nalsize;
        const unsigned char *p = buf;

        h->is_avc = 1;

        if (size < 7) {
            av_log(avctx, AV_LOG_ERROR,
                   "avcC %d too short\n", size);
            return AVERROR_INVALIDDATA;
        }
        /* sps and pps in the avcC always have length coded with 2 bytes,
         * so put a fake nal_length_size = 2 while parsing them */
        h->nal_length_size = 2;
        // Decode sps from avcC
        cnt = *(p + 5) & 0x1f; // Number of sps
        p  += 6;
        for (i = 0; i < cnt; i++) {
            nalsize = AV_RB16(p) + 2;
            if(nalsize > size - (p-buf))
                return AVERROR_INVALIDDATA;
            ret = decode_nal_units(h, p, nalsize, 1);
            if (ret < 0) {
                av_log(avctx, AV_LOG_ERROR,
                       "Decoding sps %d from avcC failed\n", i);
                return ret;
            }
            p += nalsize;
        }
        // Decode pps from avcC
        cnt = *(p++); // Number of pps
        for (i = 0; i < cnt; i++) {
            nalsize = AV_RB16(p) + 2;
            if(nalsize > size - (p-buf))
                return AVERROR_INVALIDDATA;
            ret = decode_nal_units(h, p, nalsize, 1);
            if (ret < 0) {
                av_log(avctx, AV_LOG_ERROR,
                       "Decoding pps %d from avcC failed\n", i);
                return ret;
            }
            p += nalsize;
        }
        // Now store right nal length size, that will be used to parse all other nals
        h->nal_length_size = (buf[4] & 0x03) + 1;
    } else {
        h->is_avc = 0;
        ret = decode_nal_units(h, buf, size, 1);
        if (ret < 0)
            return ret;
    }
    return size;
}


static int execute_decode_slices(H264Context *h, unsigned context_count)
{
    AVCodecContext *const avctx = h->avctx;
    H264Context *hx;
    int i;

    av_assert0(h->mb_y < h->mb_height);

    if (h->avctx->hwaccel ||
        h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
        return 0;
    if (context_count == 1) {
        return decode_slice(avctx, &h);
    } else {
        av_assert0(context_count > 0);
        for (i = 1; i < context_count; i++) {
            hx                 = h->thread_context[i];
            if (CONFIG_ERROR_RESILIENCE) {
                hx->er.error_count = 0;
            }
            hx->x264_build     = h->x264_build;
        }

        avctx->execute(avctx, decode_slice, h->thread_context,
                       NULL, context_count, sizeof(void *));

        /* pull back stuff from slices to master context */
        hx                   = h->thread_context[context_count - 1];
        h->mb_x              = hx->mb_x;
        h->mb_y              = hx->mb_y;
        h->droppable         = hx->droppable;
        h->picture_structure = hx->picture_structure;
        if (CONFIG_ERROR_RESILIENCE) {
            for (i = 1; i < context_count; i++)
                h->er.error_count += h->thread_context[i]->er.error_count;
        }
    }

    return 0;
}