Snippets Collections
<?php

/**
 * Checkout billing information form
 *
 * This template can be overridden by copying it to yourtheme/woocommerce/checkout/form-billing.php.
 *
 * HOWEVER, on occasion WooCommerce will need to update template files and you
 * (the theme developer) will need to copy the new files to your theme to
 * maintain compatibility. We try to do this as little as possible, but it does
 * happen. When this occurs the version of the template file will be bumped and
 * the readme will list any important changes.
 *
 * @see     https://woocommerce.com/document/template-structure/
 * @package WooCommerce\Templates
 * @version 3.6.0
 * @global WC_Checkout $checkout
 */

defined('ABSPATH') || exit;
$fields = $checkout->get_checkout_fields('billing');
?>
<?php if (!is_user_logged_in() && $checkout->is_registration_enabled()) : ?>
  <div class="woocommerce-billing-fields woocommerce-billing-fields-top">
    <h3><?php esc_html_e('Login', 'woocommerce'); ?></h3>
    <p>Log in to place your order</p>
    <div class="woocommerce-billing-fields__field-wrapper">
      <?php
      foreach ($fields as $key => $field) {
        if ($key === 'billing_email') {
          woocommerce_form_field($key, $field, $checkout->get_value($key));
        }
      }
      ?>
      <p class="form-row form-row-wide" id="billing_password_field" data-priority="110">
        <span class="woocommerce-input-wrapper">
          <input type="password" class="input-text" name="billing_password" id="billing_password" placeholder="Password">
        </span>
      </p>
      <div class="flogin-btn">
        <button type="button"><?php _e('Login and place order', 'wp'); ?></button>
      </div>
      <div class="flogin-footer">
        <div>Not yet a member?</div>
        <div>create an account</div>
        <div>Create an account and place your order</div>
      </div>
    </div>
  </div>
<?php else : ?>
  <div class="woocommerce-billing-fields">
    <h3><?php esc_html_e('Account', 'woocommerce'); ?></h3>
    <div class="woocommerce-billing-fields__field-wrapper">
      <?php
      foreach ($fields as $key => $field) {
        if ($key === 'billing_email') {
          woocommerce_form_field($key, $field, $checkout->get_value($key));
        }
      }
      ?>
    </div>
  </div>
<?php endif; ?>
<div class="woocommerce-billing-fields">
  <?php if (wc_ship_to_billing_address_only() && WC()->cart->needs_shipping()) : ?>

    <h3><?php esc_html_e('Billing &amp; Shipping', 'woocommerce'); ?></h3>

  <?php else : ?>

    <h3><?php esc_html_e('Billing Info', 'woocommerce'); ?></h3>

  <?php endif; ?>

  <?php do_action('woocommerce_before_checkout_billing_form', $checkout); ?>

  <div class="woocommerce-billing-fields__field-wrapper">
    <?php
    foreach ($fields as $key => $field) {
      if ($key !== 'billing_email') {
        woocommerce_form_field($key, $field, $checkout->get_value($key));
      }
    }
    ?>
	 
      <?php woocommerce_form_field('billing_notes', array(
            'type' => 'textarea',
            'class' => array('form-row-wide'),
            'label' => false,
            'placeholder' => __('Order notes(optional)', 'woocommerce'),
            'required' => false,
        ), $checkout->get_value('billing_notes')); ?>
    
    <div class="form-row shipping-address-method-field">
      <input type="radio" name="shipping-address-method[]" value="billing_address" id="method-billing_address" checked>
      <label for="method-billing_address">Ship to this address</label>
    </div>
  </div>

  <?php do_action('woocommerce_after_checkout_billing_form', $checkout); ?>
</div>

<?php if (!is_user_logged_in() && $checkout->is_registration_enabled()) : ?>
  <div class="woocommerce-account-fields">
    <?php if (!$checkout->is_registration_required()) : ?>

      <p class="form-row form-row-wide create-account">
        <label class="woocommerce-form__label woocommerce-form__label-for-checkbox checkbox">
          <input class="woocommerce-form__input woocommerce-form__input-checkbox input-checkbox" id="createaccount" <?php checked((true === $checkout->get_value('createaccount') || (true === apply_filters('woocommerce_create_account_default_checked', false))), true); ?> type="checkbox" name="createaccount" value="1" /> <span><?php esc_html_e('Create an account?', 'woocommerce'); ?></span>
        </label>
      </p>

    <?php endif; ?>

    <?php do_action('woocommerce_before_checkout_registration_form', $checkout); ?>

    <?php if ($checkout->get_checkout_fields('account')) : ?>

      <div class="create-account">
        <?php foreach ($checkout->get_checkout_fields('account') as $key => $field) : ?>
          <?php woocommerce_form_field($key, $field, $checkout->get_value($key)); ?>
        <?php endforeach; ?>
        <div class="clear"></div>
      </div>

    <?php endif; ?>

    <?php do_action('woocommerce_after_checkout_registration_form', $checkout); ?>
  </div>
<?php endif; ?>
git add FILENAME

git commit -m FILENAME

git push
//To specify a custom ID in the i18n attribute or $localize tagged message string, use the @@ prefix. The following example defines the introductionHeader custom ID in a heading element.
<h1 i18n="@@introductionHeader">Hello i18n!</h1>

variableText1 = $localize `:@@introductionHeader:Hello i18n!`;

//The following example includes a description, followed by the custom ID.
<h1 i18n="An introduction header for this sample@@introductionHeader">Hello i18n!</h1>

variableText2 = $localize `:An introduction header for this sample@@introductionHeader:Hello i18n!`;
res = thisapp.Residents.Fetchallresbyemail(input.Email);
for each  item in res
{
	counterr = 0;
	resprop = Residents[ID == item && Developments == 39703000013659197].Property_address;
	ipdcheck = pod_planner.Properties.IPDprivate(resprop);
	if(ipdcheck == "True")
	{
		counterr = counterr + 1;
	}
}
$ git commit -m "Make everything work.
dquote>
dquote> Add magic code that fixes everything"
<?php
// Define the start year and get the current year
$start_year = 2020; // Replace with your start year
$current_year = date('Y');
?>
<p>&copy; <?php echo $start_year; ?><?php if ($start_year != $current_year) echo '-' . $current_year; ?> <?php bloginfo('name'); ?>. Minden jog fenntartva.</p>
fun main() {
         var a:Int=76
         println("Value of a :${a}")
         
         var b:Char='A'
         println("value of b :${b}")
         
         var c:String="Welcome to my world"
         println("Value of String :${c}")
         
         var d:String="""
                 Welcome
                 To
                 My
                 World
                 """
          println("Value Of String :${d}")
          
          val numbers:IntArray= intArrayOf(1,2,3,4,5)
          val chars=charArrayOf('A','B','C')
          val games: Array<String> =arrayOf("Cricket","Kabaddi")
          
          println("Integers Array:${numbers.contentToString()}")
           println("Characters Array:${chars.contentToString()}")
            println("String Array:${games.contentToString()}")
         
 println("Mutable List Example :")
         
         var e = mutableListOf("C","C++","Java")
          println("List:${e}")
           e.add("Python")
           println("Updated List :${e}")
         
 println("Immutable List Example :")
         
         var k = listOf("C","C++","Java")
          println("List:${k}")
          
 println("Mutable Set Ex:")
          
          var g =mutableSetOf(1,2,3,4,5)
             println("SET :${g}")
             
             g.add(6)
             println("Updated Set:${g}")
             
 println("Immutable Set Ex:")
          
          var h =setOf(5,6,7,8,9)
             println("SET :${h}")
         
 println("Immutable Map Ex:")      
         
           var details = mapOf("Sno" to 101,"Sname" to "Hari")
           println("Map :${details}")         
          
 println("Mutable Map Ex:")  
 
          var courses = mutableMapOf("Sno" to 102,"Sname" to "Pari")
          println("Map :${courses}")
          
         courses["marks"]=100
          println("Updated Map :${courses}")
          
 println("Range Ex:")
      
          var r = 1..10
          for(e in r){
          println(e)
          }
          println("Enter value of m:")
          var m =readln()
          println(m)
                   
         }
import React, { useState } from 'react';

function Example() {
  const [user, setUser] = useState({
    name: 'John Doe',
    age: 30
  });

  return (
    <div>
      <p>Name: {user.name}</p>
      <p>Age: {user.age}</p>
      <p>Email: {user.email}</p>
      <button onClick={() => setUser({ ...user, name: 'Jane Doe' })}>Change Name</button>
      <button onClick={() => setUser({ ...user, email: 'jane.doe@example.com' })}>Add Email</button>
      <button onClick={() => {
        const { age, ...rest } = user;
        setUser(rest);
      }}>Delete Age</button>
    </div>
  );
}

export default Example;
import React, { useState } from 'react';

function Example() {
  const [users, setUsers] = useState([
    { id: 1, name: 'John Doe', age: 30 },
    { id: 2, name: 'Jane Smith', age: 25 }
  ]);

  return (
    <div>
      {users.map(user => (
        <div key={user.id}>
          <p>Name: {user.name}</p>
          <p>Age: {user.age}</p>
        </div>
      ))}
      <button onClick={() => setUsers(users.map(user => 
        user.id === 1 ? { ...user, name: 'Jane Doe' } : user
      ))}>Change Name of User 1</button>
      <button onClick={() => setUsers([...users, { id: 3, name: 'Sam Green', age: 28 }])}>Add User</button>
      <button onClick={() => setUsers(users.filter(user => user.id !== 2))}>Delete User 2</button>
    </div>
  );
}

export default Example;
Request
  URI: /cashcards/{id}
  HTTP Verb: GET
  Body: None

Response:
  HTTP Status:
    200 OK if the user is authorized and the Cash Card was successfully retrieved
    401 UNAUTHORIZED if the user is unauthenticated or unauthorized
    404 NOT FOUND if the user is authenticated and authorized but the Cash Card cannot be found
  Response Body Type: JSON
  Example Response Body:
    {
      "id": 99,
      "amount": 123.45
    }
You can use the async keyword to create an asynchronous function, which returns a promise.

Example Code
const example = async () => {
  console.log("this is an example");
};

The try block is designed to handle potential errors, and the code inside the catch block will be executed in case an error occurs.

Example Code
try {
  const name = "freeCodeCamp";
  name = "fCC";
} catch (err) {
  console.log(err); // TypeError: Assignment to constant variable.
}

The await keyword waits for a promise to resolve and returns the result.

Example Code
const example = async () => {
  const data = await fetch("https://example.com/api");
  console.log(data);
}
The Fetch API is a built-in JavaScript interface to make network requests to a server. It has a fetch() method you can use to make GET, POST, PUT, or PATCH requests. In this project, you'll make a GET request to a URL for a JSON file with information about authors on freeCodeCamp News.

Here is how you can make a GET request with the fetch() method:

Example Code
fetch("url-goes-here")

The fetch() method returns a Promise, which is a placeholder object that will either be fulfilled if your request is successful, or rejected if your request is unsuccessful.

If the Promise is fulfilled, it resolves to a Response object, and you can use the .then() method to access the Response.

Here's how you can chain .then() to the fetch() method:

Example Code
fetch("sample-url-goes-here")
  .then((res) => res)

The data you get from a GET request is not usable at first. To make the data usable, you can use the .json() method on the Response object to parse it into JSON. If you expand the Prototype of the Response object in the console, you will see the .json() method there.

In order to start working with the data, you will need to use another .then() method.

Chain another .then() to the existing .then() method. This time, pass in data as the parameter for the callback function. For the callback, use a curly brace because you will have more than one expression.

The .catch() method is another asynchronous JavaScript method you can use to handle errors. This is useful in case the Promise gets rejected.
<ul>
    {{#each customDataModel.links}}
        <li><a href="{{this.link}}" title="{{this.title}}">{{this.title}}</a></li>
    {{/each}}
</ul>
   
// CustomDataModel
{
    "links": [
        { "title": "New Models", "link": "/new-models" },
        { "title": "Inventory", "link": "/search/inventory" },
        { "title": "New Inventory", "link": "/search/inventory/usage/New" },
        { "title": "Used Inventory", "link": "/search/inventory/usage/Used" },
        { "title": "Services", "link": "/services" },
        { "title": "Finacing", "link": "/financing" },
        { "title": "Comapany Info", "link": "/aboutus" },
        { "title": "Contact Us", "link": "/contactus" }
    ]  
}
RK3229

Typical application areas

Key Features

Quad-core Cortex-A7 up to 1.5GHz
Mali-400MP2 GPU
DDR3/DDR3L/LPDDR2/LPDDR3
4K UHD H265/H264/VP9
BT.2020/BT.709
H264 encoder
TS in/CSA 2.0
USB 2.0
HDMI 2.0 with HDCP 2.2
FE PHY/Audio DAC/CVBS/RGMII
TrustZone/TEE/DRM
SPECIFICATION
Technology	• 28nm
CPU	• Quad-core Cortex-A7, up to 1.5GHz
GPU	• Mali400MP, supports OpenGL ES1.1/2.0
multimedia	• Support 4K VP9 and 4K 10bits H265/H264 video decoding, up to 60fps
• 1080P multi-format video decoding (WMV, MPEG-1/2/4, VP8)
• 1080P video encoding, support H.264, VP8 format
show	• HDMI 2.0 supports 4K 60Hz display and HDCP 1.4/2.2
• CVBS output
Safety	• ARM TrustZone (TEE), Secure Video Path, Cipher Engine, Secure boot
Memory	• 32bit DDR3-1600/DDR3L-1600/LPDDR3-1333/LPDDR2-1066
• Support MLC NAND Flash, eMMC 4.51, SPI NAND Flash
interface	• Dual SDIO 3.0 interface
• 8-channel I2S interface, supporting 8-way digital microphone input and output
• Integrated CVBS, HDMI TX, Ethernet MAC and PHY, S/PDIF, Audio Codec, USB, I2C/UART/SPI
Encapsulation	• BGA316 14X14, 0.65mm pitch
state	• MP Now
PX5

Typical application areas

Key Features

Octa-core Cortex-A53 up to 1.5GHz
PowerVR G6110 GPU
DDR3/DDR3L/LPDDR2/LPDDR3
4K UHD H265/H264 decoder
FHD panel display
ADAS Algorithm support
SmartPhone connection support
Fast Reverse view
SPECIFICATION
Technology	• 28nm
CPU	• Octa-core 64-bit Cortex-A53, up to 1.5GHz
GPU	• PowerVR G6110 GPU
• Support OpenGL ES 1.1/2.0/3.1, OpenCL, DirectX9.3
• Built-in high-performance 2D acceleration hardware
multimedia	• Support 4K H265 60fps/H264 25fps video decoding
• 1080P multi-format video decoding (VC-1, MPEG-1/2/4, VP8)
• 1080P video encoding, support H.264, VP8 format
show	• Support RGB, LVDS, MIPI-DSI, eDP display interface, with the highest resolution of 2048*1536
• HDMI 2.0 supports 4K 60Hz display and HDCP 1.4/2.2
Safety	• ARM TrustZone (TEE), Secure Video Path, Cipher Engine, Secure boot
Memory	• 32bit DDR3-1600/DDR3L-1600/LPDDR3-1333
• Support MLC NAND Flash, eMMC 4.51, SPI SPI Flash booting
interface	• Built-in 8M ISP, supports MIPI CSI-2 and DVP interface
• Dual SDIO 3.0 interface
• TS in/CSA2.0
• Integrated HDMI, Ethernet MAC, S/PDIF, USB, I2C, I2S, UART, SPI
Encapsulation	• BGA453 19X19, 0.8mm pitch
state	• MP Now
 
/*Replace the class .mesh-test with your own as well as the four lines of code 
following right underneath (with the code from Mesher)*/

.mesh-test{
    background-color:hsla(95,0%,0%,1);
    background-image:
    radial-gradient(at 88% 79%, hsla(227,93%,77%,1) 0px, transparent 50%),
    radial-gradient(at 13% 9%, hsla(80,95%,71%,1) 0px, transparent 50%);

animation: gradient 13s ease infinite;
    background-size: 200% 200%;
}

@keyframes gradient {
	0% {
		background-position: 0% 20%;
	}
	25% {
		background-position: 100% 50%;
	}
	50% {
		background-position: 50% 70%;
	}
	100% {
		background-position: 0% 20%;
	}
}
// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        red: 'hsl(14, 86%, 42%)',
        green: 'hsl(159, 69%, 38%)',
        rose: {
          50: 'hsl(20, 50%, 98%)',
          100: 'hsl(13, 31%, 94%)',
          300: 'hsl(14, 25%, 72%)',
          400: 'hsl(7, 20%, 60%)',
          500: 'hsl(12, 20%, 44%)',
          900: 'hsl(14, 65%, 9%)',
        },
      },
    },
  },
};
/* ./src/fonts.css */
@font-face {
  font-family: 'Karla';
  src: url('../assets/fonts/Karla-Regular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
}

@font-face {
  font-family: 'Karla';
  src: url('../assets/fonts/Karla-Italic-VariableFont_wght.ttf') format('truetype');
  font-weight: 400;
  font-style: italic;
}

@font-face {
  font-family: 'Karla';
  src: url('../assets/fonts/Karla-VariableFont_wght.ttf') format('truetype');
  font-weight: 100 900;
  font-style: normal;
}


/* ./src/index.css */
@import './fonts.css';

@tailwind base;
@tailwind components;
@tailwind utilities;


// tailwind.config.js
module.exports = {
  content: ['./src/**/*.{html,js,jsx,ts,tsx}', './dist/index.html'],
  theme: {
    extend: {
      fontFamily: {
        karla: ['Karla', 'sans-serif'],
      },
    },
  },
  plugins: [],
};
<?php
/**
 * Review order table
 *
 * This template can be overridden by copying it to yourtheme/woocommerce/checkout/review-order.php.
 *
 * HOWEVER, on occasion WooCommerce will need to update template files and you
 * (the theme developer) will need to copy the new files to your theme to
 * maintain compatibility. We try to do this as little as possible, but it does
 * happen. When this occurs the version of the template file will be bumped and
 * the readme will list any important changes.
 *
 * @see https://woocommerce.com/document/template-structure/
 * @package WooCommerce\Templates
 * @version 5.2.0
 */

defined( 'ABSPATH' ) || exit;
$total_order = WC()->cart->total;
$total_sale = 0;

foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
    $product = $cart_item['data'];
    if ( $product->is_on_sale() ) {
        $total_sale += ( $product->get_regular_price() - $product->get_sale_price() ) * $cart_item['quantity'];
    }
}
?>
<div class="woocommerce-checkout-review-order-table">
	<?php do_action('custom-freeshiping-bar');?>
    <div id="total-header">
    <button type="button" id="toggle-cart-items" class="button-toggle-cart">
        Order Summary
		<i class="fa-solid fa-chevron-down"></i>
    </button>
	<div class="total-money">
       <span class="total-sale">$<?php echo number_format($total_sale, 2); ?></span>
       <span class="total-order">$<?php echo number_format($total_order, 2); ?></span>
    </div>
</div>
    <div id="cart-details">
		<div class="title-in-review">
				<h3 class="co-h3">PURCHARE SUMMARY</h3>
				<?php do_action('custom-freeshiping-bar');?>
			</div>
        <ul id="cart-items-list" class="woocommerce-mini-cart cart_list product_list_widget">
            <?php if ( ! WC()->cart->is_empty() ) : ?>
                <?php
                    do_action( 'woocommerce_review_order_before_cart_contents' );

                    foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
                        $_product     = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
                        $product_id   = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );

                        if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters( 'woocommerce_checkout_cart_item_visible', true, $cart_item, $cart_item_key ) ) {
                            $product_name      = apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key );
                            $thumbnail         = apply_filters( 'woocommerce_cart_item_thumbnail', $_product->get_image(), $cart_item, $cart_item_key );
                            $product_price     = apply_filters( 'woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key );
                            $product_permalink = apply_filters( 'woocommerce_cart_item_permalink', $_product->is_visible() ? $_product->get_permalink( $cart_item ) : '', $cart_item, $cart_item_key );

                            if ( empty( $product_permalink ) ) {
                                $product_name = '<span class="nm-cart-panel-product-title">' . wp_kses_post( $product_name ) . '</span>';
                            } else {
                                $product_permalink = esc_url( $product_permalink );
                                $thumbnail = '<a href="' . $product_permalink . '">' . $thumbnail . '</a>';
                                $product_name = '<a href="' . $product_permalink . '" class="nm-cart-panel-product-title">' . wp_kses_post( $product_name ) . '</a>';
                            }

                            $product = wc_get_product($product_id);

                            ?>
                            <li id="nm-cart-panel-item-<?php echo esc_attr( $cart_item_key ); ?>" class="woocommerce-mini-cart-item <?php echo esc_attr( apply_filters( 'woocommerce_mini_cart_item_class', 'mini_cart_item', $cart_item, $cart_item_key ) ); ?>">
                                <div class="nm-cart-panel-item-thumbnail">
                                    <div class="nm-cart-item-loader nm-loader"></div>
                                    <div class="nm-cart-panel-thumbnail-wrap">
                                        <?php echo $thumbnail; ?>
                                        <div class="nm-cart-panel-thumbnail-loader nm-loader"></div>
                                    </div>
                                </div>
                                <div class="nm-cart-panel-item-details">
                                    <?php echo apply_filters( 'woocommerce_cart_item_remove_link',
                                        sprintf(
                                            '<a href="%s" class="remove remove_from_cart_button" aria-label="%s" data-product_id="%s" data-cart_item_key="%s" data-product_sku="%s"><i class="nm-font nm-font-close2"></i></a>',
                                            esc_url( wc_get_cart_remove_url( $cart_item_key ) ),
                                            esc_attr( sprintf( __( 'Remove %s from cart', 'woocommerce' ), wp_strip_all_tags( $product_name ) ) ),
                                            esc_attr( $product_id ),
                                            esc_attr( $cart_item_key ),
                                            esc_attr( $_product->get_sku() )
                                        ), $cart_item_key );
                                    ?>
                                    <?php echo $product_name; ?>
                                    <?php echo wc_get_formatted_cart_item_data( $cart_item ); ?>
                                    <div class="nm-cart-panel-quantity-pricing">
                                        <?php if ( $_product->is_sold_individually() ) : ?>
                                            <?php echo apply_filters( 'woocommerce_widget_cart_item_quantity', '<span class="quantity">' . esc_html__( 'Qty', 'woocommerce' ) . ': ' . $cart_item['quantity'] . '</span>', $cart_item, $cart_item_key ); ?>
                                        <?php else: ?>
                                            <div class="product-quantity" data-title="<?php esc_html_e( 'Quantity', 'woocommerce' ); ?>">
                                                <?php
                                                    $product_quantity = woocommerce_quantity_input( array(
                                                        'input_name'  => "cart[{$cart_item_key}][qty]",
                                                        'input_value' => $cart_item['quantity'],
                                                        'max_value'   => $_product->backorders_allowed() ? '' : $_product->get_stock_quantity(),
                                                        'min_value'   => '1',
                                                        'nm_mini_cart_quantity' => true 
                                                    ), $_product, false );

                                                    echo apply_filters( 'woocommerce_widget_cart_item_quantity', $product_quantity, $cart_item, $cart_item_key );
                                                ?>
                                            </div>
                                        <?php endif; ?>

                                        <div class="nm-cart-panel-item-price">
                                            <?php if ( $price_html = $product->get_price_html() ) : ?>
                                                <span class="price"><?php echo $price_html; ?></span>
                                            <?php endif; ?>
                                        </div>
                                    </div>
                                </div>
                            </li>
                            <?php
                        }
                    }

                    do_action( 'woocommerce_review_order_after_cart_contents' );
                ?>
            <?php else: ?>
                <li class="empty">
                    <i class="nm-font nm-font-close2"></i>
                    <span><?php esc_html_e( 'No products in the cart.', 'woocommerce' ); ?></span>
                </li>
            <?php endif; ?>
        </ul>

        <?php do_action( 'woocommerce_custom_checkout_counpon' ); ?>
        <table class="shop_table">
            <tfoot>
                <tr class="cart-subtotal">
                    <th><?php esc_html_e( 'Subtotal', 'woocommerce' ); ?></th>
                    <td><?php wc_cart_totals_subtotal_html(); ?></td>
                </tr>

                <?php foreach ( WC()->cart->get_coupons() as $code => $coupon ) : ?>
                    <tr class="cart-discount coupon-<?php echo esc_attr( sanitize_title( $code ) ); ?>">
                        <th><?php wc_cart_totals_coupon_label( $coupon ); ?></th>
                        <td><?php wc_cart_totals_coupon_html( $coupon ); ?></td>
                    </tr>
                <?php endforeach; ?>

                <?php if ( WC()->cart->needs_shipping() && WC()->cart->show_shipping() ) : ?>
				<?php
				// Get available shipping methods
				$available_methods = WC()->shipping->get_packages()[0]['rates'];
				$chosen_methods = WC()->session->get('chosen_shipping_methods');
				$chosen_method = !empty($chosen_methods[0]) ? $chosen_methods[0] : '';

				// Only display the chosen method
				if (!empty($available_methods[$chosen_method])) {
					echo '<tr class="shipping">';
					echo '<th>' . esc_html__('Shipping', 'woocommerce') . '</th>';
					echo '<td data-title="Shipping">' . wp_kses_post($available_methods[$chosen_method]->label . ': ' . wc_price($available_methods[$chosen_method]->cost)) . '</td>';
					echo '</tr>';
				}
				?>
			<?php endif; ?>


                <?php foreach ( WC()->cart->get_fees() as $fee ) : ?>
                    <tr class="fee">
                        <th><?php echo esc_html( $fee->name ); ?></th>
                        <td><?php wc_cart_totals_fee_html( $fee ); ?></td>
                    </tr>
                <?php endforeach; ?>

                <?php if ( wc_tax_enabled() && ! WC()->cart->display_prices_including_tax() ) : ?>
                    <?php if ( 'itemized' === get_option( 'woocommerce_tax_total_display' ) ) : ?>
                        <?php foreach ( WC()->cart->get_tax_totals() as $code => $tax ) : ?>
                            <tr class="tax-rate tax-rate-<?php echo esc_attr( sanitize_title( $code ) ); ?>">
                                <th><?php echo esc_html( $tax->label ); ?></th>
                                <td><?php echo wp_kses_post( $tax->formatted_amount ); ?></td>
                            </tr>
                        <?php endforeach; ?>
                    <?php else : ?>
                        <tr class="tax-total">
                            <th><?php echo esc_html( WC()->countries->tax_or_vat() ); ?></th>
                            <td><?php wc_cart_totals_taxes_total_html(); ?></td>
                        </tr>
                    <?php endif; ?>
                <?php endif; ?>

                <?php do_action( 'woocommerce_review_order_before_order_total' ); ?>

                <tr class="order-total">
                    <th><?php esc_html_e( 'Total', 'woocommerce' ); ?></th>
                    <td><?php wc_cart_totals_order_total_html(); ?></td>
                </tr>

                <?php do_action( 'woocommerce_review_order_after_order_total' ); ?>
            </tfoot>
        </table>
    </div>
</div>


WITH RECURSIVE date_range AS (
    SELECT date'2019-01-03' dateval, 0 mes  /*start date, use cast(? as date) if you need a parameter */
    FROM rdb$database
    UNION ALL 
    SELECT DATEADD(MONTH,1,dateval), mes + 1
    FROM date_range
    WHERE mes < 12 /* end date */
)
SELECT *
FROM date_range;
void merge(int *arr, int s, int e) {
  int mid = s + (e - s) / 2;
  int len1 = mid - s + 1;
  int len2 = e - mid;
  int *first = new int[len1];
  int *second = new int[len2];

  // copy vales
  int mainArrayIndex = s;
  for (int i = 0; i < len1; i++) {
    first[i] = arr[mainArrayIndex++];
  }
  mainArrayIndex = mid + 1;
  for (int i = 0; i < len2; i++) {
    second[i] = arr[mainArrayIndex++];
  }

  // merge 2 sorted arrays
  int index1 = 0;
  int index2 = 0;
  mainArrayIndex = s;
  while (index1 < len1 && index2 < len2) {
    if (first[index1] < second[index2]) {
      arr[mainArrayIndex++] = first[index1++];
    } else {
      arr[mainArrayIndex++] = second[index2++];
    }
  }
  while (index1 < len1) {
    arr[mainArrayIndex++] = first[index1++];
  }
  while (index2 < len2) {
    arr[mainArrayIndex++] = second[index2++];
  }
}

void mergeSort(int *arr, int s, int e) {
  if (s >= e) {
    return;
  }
  int mid = s + (e - s) / 2;
  // left  part
  mergeSort(arr, s, mid);
  // right part
  mergeSort(arr, mid + 1, e);
  // merge
  merge(arr, s, e);
}
Product	Year	Version	Product Keys
Visual Studio 2022	2022	17.x	Professional:
 	 	 	TD244-P4NB7-YQ6XK-Y8MMM-YWV2J
 	 	 	Enterprise:
 	 	 	VHF9H-NXBBB-638P6-6JHCY-88JWH
Visual Studio 2020	2020	 	HG8FD-DR6F8-T7G9Y-H80UI-9NUB8
 	 	 	YV7T8-R6C8R-C6VT9-7GBHY-80NUJ
 	 	 	T6RX5-EZXCR-6VT7B-Y80NU-HBGVF
 	 	 	CDX5X-7E5CR-86VT7-9BY9V-7TC8R
Visual Studio 2019	2019	16.x	Professional:
 	 	 	NYWVH-HT4XC-R2WYW-9Y3CM-X4V3Y
 	 	 	Enterprise:
 	 	 	BF8Y8-GN2QH-T84XB-QVY3B-RC4DF
Visual Studio 2017	2017	15.x	Test Professional:
 	 	 	VG622-NKFP4-GTWPH-XB2JJ-JFHVF
 	 	 	Professional:
 	 	 	KBJFW-NXHK6-W4WJM-CRMQB-G3CDH
 	 	 	4F3PR-NFKDB-8HFP7-9WXGY-K77T7
 	 	 	Enterprise:
 	 	 	NJVYC-BMHX2-G77MM-4XJMR-6Q8QF
 	 	 	N2VYX-9VR2K-T733M-MWD9X-KQCDF
Visual Studio 2015	2015	14.x	Professional:
 	 	 	HMGNV-WCYXV-X7G9W-YCX63-B98R2
 	 	 	Enterprise:
 	 	 	HM6NR-QXX7C-DFW2Y-8B82K-WTYJV
 	 	 	2XNFG-KFHR8-QV3CP-3W6HT-683CH
 	 	 	Team Foundation Server:
 	 	 	PTBNK-HVGCM-HB2GW-MXWMH-T3BJQ
Visual Studio 2013	2013	12.x	Professional:
 	 	 	XDM3T-W3T3V-MGJWK-8BFVD-GVPKY
 	 	 	Premium:
 	 	 	FBJVC-3CMTX-D8DVP-RTQCT-92494
 	 	 	Ultimate:
 	 	 	BWG7X-J98B3-W34RT-33B3R-JVYW9
 	 	 	Team Foundation Server:
 	 	 	MHG9J-HHHX9-WWPQP-D8T7H-7KCQG
Visual Studio 2012	2012	11.x	Professional:
 	 	 	4D974-9QX42-9Y43G-YJ7JG-JDYBP
 	 	 	Premium:
 	 	 	MH2FR-BC9R2-84433-47M63-KQVWC
 	 	 	Ultimate:
 	 	 	YKCW6-BPFPF-BT8C9-7DCTH-QXGWC
 	 	 	RBCXF-CVBGR-382MK-DFHJ4-C69G8
 	 	 	YQ7PR-QTHDM-HCBCV-9GKGG-TB2TM
 	 	 	MMVJ9-FKY74-W449Y-RB79G-8GJGJ
 	 	 	YCFHQ-9DWCY-DKV88-T2TMH-G7BHP
 	 	 	Team Foundation Server:
 	 	 	BVGTF-T7MVR-TP46H-9Q97G-XBXRB
Visual Studio 2010	2010	10.x	Professional/Ultimate (built-in or below):
 	 	 	YCFHQ-9DWCY-DKV88-T2TMH-G7BHP
Visual Studio 2008	2007	9.x	Express: Not required
 	 	 	Professional:
 	 	 	XMQ2Y-4T3V6-XJ48Y-D3K2V-6C4WT
 	 	 	WPX3J-BXC3W-BPYWP-PJ8CM-F7M8T
 	 	 	PYHYP-WXB3B-B2CCM-V9DX9-VDY8T
 	 	 	WPDW8-M962C-VJX9M-HQB4Q-JVTDM
Visual Studio 2005	2005	8.x	Express: Not required
 	 	 	Standard: Not required
 	 	 	Professional:
 	 	 	KGR3T-F2C26-RRTGT-D6DQT-QBBB3
Visual Studio 6.0	1998	6.x	111-1111111
 	 	 	123456789
 	 	 	1234567890
 
has context menu
SELECT(room_type[room id],[hotel id]=[_THISROW].[hotel name])
room_type[room id]-SELECT(Service Record[room],AND([checkin]<[_THISROW].[checkout],[checkout]>[_THISROW].[checkin],[No]<>[_THISROW].[No]))
bool checkPalindrome (string s, int start, int length) {
  if (start>length) {
    return true;
	}
  if (s[start] != s[length]) {
    return false;
	}
  else {
    return checkPalindrome(s,start+1,length-1;)
  }
}
blob: e522f4d4d3ff87ccb606a8549db4efd0e6228faa [file] [log] [blame]
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "commands.h"
#include <inttypes.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unordered_set>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android/hardware/boot/1.1/IBootControl.h>
#include <cutils/android_reboot.h>
#include <ext4_utils/wipe.h>
#include <fs_mgr.h>
#include <fs_mgr/roots.h>
#include <libgsi/libgsi.h>
#include <liblp/builder.h>
#include <liblp/liblp.h>
#include <libsnapshot/snapshot.h>
#include <storage_literals/storage_literals.h>
#include <uuid/uuid.h>
#include <bootloader_message/bootloader_message.h>
#include "BootControlClient.h"
#include "constants.h"
#include "fastboot_device.h"
#include "flashing.h"
#include "utility.h"
#ifdef FB_ENABLE_FETCH
static constexpr bool kEnableFetch = true;
#else
static constexpr bool kEnableFetch = false;
#endif
using android::fs_mgr::MetadataBuilder;
using android::hal::CommandResult;
using ::android::hardware::hidl_string;
using android::snapshot::SnapshotManager;
using MergeStatus = android::hal::BootControlClient::MergeStatus;
using namespace android::storage_literals;
struct VariableHandlers {
    // Callback to retrieve the value of a single variable.
    std::function<bool(FastbootDevice*, const std::vector<std::string>&, std::string*)> get;
    // Callback to retrieve all possible argument combinations, for getvar all.
    std::function<std::vector<std::vector<std::string>>(FastbootDevice*)> get_all_args;
};
static bool IsSnapshotUpdateInProgress(FastbootDevice* device) {
    auto hal = device->boot1_1();
    if (!hal) {
        return false;
    }
    auto merge_status = hal->getSnapshotMergeStatus();
    return merge_status == MergeStatus::SNAPSHOTTED || merge_status == MergeStatus::MERGING;
}
static bool IsProtectedPartitionDuringMerge(FastbootDevice* device, const std::string& name) {
    static const std::unordered_set<std::string> ProtectedPartitionsDuringMerge = {
            "userdata", "metadata", "misc"};
    if (ProtectedPartitionsDuringMerge.count(name) == 0) {
        return false;
    }
    return IsSnapshotUpdateInProgress(device);
}
static void GetAllVars(FastbootDevice* device, const std::string& name,
                       const VariableHandlers& handlers) {
    if (!handlers.get_all_args) {
        std::string message;
        if (!handlers.get(device, std::vector<std::string>(), &message)) {
            return;
        }
        device->WriteInfo(android::base::StringPrintf("%s:%s", name.c_str(), message.c_str()));
        return;
    }
    auto all_args = handlers.get_all_args(device);
    for (const auto& args : all_args) {
        std::string message;
        if (!handlers.get(device, args, &message)) {
            continue;
        }
        std::string arg_string = android::base::Join(args, ":");
        device->WriteInfo(android::base::StringPrintf("%s:%s:%s", name.c_str(), arg_string.c_str(),
                                                      message.c_str()));
    }
}
const std::unordered_map<std::string, VariableHandlers> kVariableMap = {
        {FB_VAR_VERSION, {GetVersion, nullptr}},
        {FB_VAR_VERSION_BOOTLOADER, {GetBootloaderVersion, nullptr}},
        {FB_VAR_VERSION_BASEBAND, {GetBasebandVersion, nullptr}},
        {FB_VAR_VERSION_OS, {GetOsVersion, nullptr}},
        {FB_VAR_VERSION_VNDK, {GetVndkVersion, nullptr}},
        {FB_VAR_PRODUCT, {GetProduct, nullptr}},
        {FB_VAR_SERIALNO, {GetSerial, nullptr}},
        {FB_VAR_VARIANT, {GetVariant, nullptr}},
        {FB_VAR_SECURE, {GetSecure, nullptr}},
        {FB_VAR_UNLOCKED, {GetUnlocked, nullptr}},
        {FB_VAR_MAX_DOWNLOAD_SIZE, {GetMaxDownloadSize, nullptr}},
        {FB_VAR_CURRENT_SLOT, {::GetCurrentSlot, nullptr}},
        {FB_VAR_SLOT_COUNT, {GetSlotCount, nullptr}},
        {FB_VAR_HAS_SLOT, {GetHasSlot, GetAllPartitionArgsNoSlot}},
        {FB_VAR_SLOT_SUCCESSFUL, {GetSlotSuccessful, nullptr}},
        {FB_VAR_SLOT_UNBOOTABLE, {GetSlotUnbootable, nullptr}},
        {FB_VAR_PARTITION_SIZE, {GetPartitionSize, GetAllPartitionArgsWithSlot}},
        {FB_VAR_PARTITION_TYPE, {GetPartitionType, GetAllPartitionArgsWithSlot}},
        {FB_VAR_IS_LOGICAL, {GetPartitionIsLogical, GetAllPartitionArgsWithSlot}},
        {FB_VAR_IS_USERSPACE, {GetIsUserspace, nullptr}},
        {FB_VAR_IS_FORCE_DEBUGGABLE, {GetIsForceDebuggable, nullptr}},
        {FB_VAR_OFF_MODE_CHARGE_STATE, {GetOffModeChargeState, nullptr}},
        {FB_VAR_BATTERY_VOLTAGE, {GetBatteryVoltage, nullptr}},
        {FB_VAR_BATTERY_SOC, {GetBatterySoC, nullptr}},
        {FB_VAR_BATTERY_SOC_OK, {GetBatterySoCOk, nullptr}},
        {FB_VAR_HW_REVISION, {GetHardwareRevision, nullptr}},
        {FB_VAR_SUPER_PARTITION_NAME, {GetSuperPartitionName, nullptr}},
        {FB_VAR_SNAPSHOT_UPDATE_STATUS, {GetSnapshotUpdateStatus, nullptr}},
        {FB_VAR_CPU_ABI, {GetCpuAbi, nullptr}},
        {FB_VAR_SYSTEM_FINGERPRINT, {GetSystemFingerprint, nullptr}},
        {FB_VAR_VENDOR_FINGERPRINT, {GetVendorFingerprint, nullptr}},
        {FB_VAR_DYNAMIC_PARTITION, {GetDynamicPartition, nullptr}},
        {FB_VAR_FIRST_API_LEVEL, {GetFirstApiLevel, nullptr}},
        {FB_VAR_SECURITY_PATCH_LEVEL, {GetSecurityPatchLevel, nullptr}},
        {FB_VAR_TREBLE_ENABLED, {GetTrebleEnabled, nullptr}},
        {FB_VAR_MAX_FETCH_SIZE, {GetMaxFetchSize, nullptr}},
        {FB_VAR_BATTERY_SERIAL_NUMBER, {GetBatterySerialNumber, nullptr}},
        {FB_VAR_BATTERY_PART_STATUS, {GetBatteryPartStatus, nullptr}},
};
static bool GetVarAll(FastbootDevice* device) {
    for (const auto& [name, handlers] : kVariableMap) {
        GetAllVars(device, name, handlers);
    }
    return true;
}
static void PostWipeData() {
    std::string err;
    // Reset mte state of device.
    if (!WriteMiscMemtagMessage({}, &err)) {
        LOG(ERROR) << "Failed to reset MTE state: " << err;
    }
}
const std::unordered_map<std::string, std::function<bool(FastbootDevice*)>> kSpecialVars = {
        {"all", GetVarAll},
        {"dmesg", GetDmesg},
};
bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    if (args.size() < 2) {
        return device->WriteFail("Missing argument");
    }
    // "all" and "dmesg" are multiline and handled specially.
    auto found_special = kSpecialVars.find(args[1]);
    if (found_special != kSpecialVars.end()) {
        if (!found_special->second(device)) {
            return false;
        }
        return device->WriteOkay("");
    }
    // args[0] is command name, args[1] is variable.
    auto found_variable = kVariableMap.find(args[1]);
    if (found_variable == kVariableMap.end()) {
        return device->WriteFail("Unknown variable");
    }
    std::string message;
    std::vector<std::string> getvar_args(args.begin() + 2, args.end());
    if (!found_variable->second.get(device, getvar_args, &message)) {
        return device->WriteFail(message);
    }
    return device->WriteOkay(message);
}
bool OemPostWipeData(FastbootDevice* device) {
    auto fastboot_hal = device->fastboot_hal();
    if (!fastboot_hal) {
        return false;
    }
    auto status = fastboot_hal->doOemSpecificErase();
    if (status.isOk()) {
        device->WriteStatus(FastbootResult::OKAY, "Erasing succeeded");
        return true;
    }
    switch (status.getExceptionCode()) {
        case EX_UNSUPPORTED_OPERATION:
            return false;
        case EX_SERVICE_SPECIFIC:
            device->WriteStatus(FastbootResult::FAIL, status.getDescription());
            return false;
        default:
            LOG(ERROR) << "Erase operation failed" << status.getDescription();
            return false;
    }
}
bool EraseHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    if (args.size() < 2) {
        return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
    }
    if (GetDeviceLockStatus()) {
        return device->WriteStatus(FastbootResult::FAIL, "Erase is not allowed on locked devices");
    }
    const auto& partition_name = args[1];
    if (IsProtectedPartitionDuringMerge(device, partition_name)) {
        auto message = "Cannot erase " + partition_name + " while a snapshot update is in progress";
        return device->WriteFail(message);
    }
    PartitionHandle handle;
    if (!OpenPartition(device, partition_name, &handle)) {
        return device->WriteStatus(FastbootResult::FAIL, "Partition doesn't exist");
    }
    if (wipe_block_device(handle.fd(), get_block_device_size(handle.fd())) == 0) {
        //Perform oem PostWipeData if Android userdata partition has been erased
        bool support_oem_postwipedata = false;
        if (partition_name == "userdata") {
            PostWipeData();
            support_oem_postwipedata = OemPostWipeData(device);
        }
        if (!support_oem_postwipedata) {
            return device->WriteStatus(FastbootResult::OKAY, "Erasing succeeded");
        } else {
            //Write device status in OemPostWipeData(), so just return true
            return true;
        }
    }
    return device->WriteStatus(FastbootResult::FAIL, "Erasing failed");
}
bool OemCmdHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    auto fastboot_hal = device->fastboot_hal();
    if (!fastboot_hal) {
        return device->WriteStatus(FastbootResult::FAIL, "Unable to open fastboot HAL");
    }
    //Disable "oem postwipedata userdata" to prevent user wipe oem userdata only.
    if (args[0] == "oem postwipedata userdata") {
        return device->WriteStatus(FastbootResult::FAIL, "Unable to do oem postwipedata userdata");
    }
    std::string message;
    auto status = fastboot_hal->doOemCommand(args[0], &message);
    if (!status.isOk()) {
        LOG(ERROR) << "Unable to do OEM command " << args[0].c_str() << status.getDescription();
        return device->WriteStatus(FastbootResult::FAIL,
                                   "Unable to do OEM command " + status.getDescription());
    }
    device->WriteInfo(message);
    return device->WriteStatus(FastbootResult::OKAY, message);
}
bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    if (args.size() < 2) {
        return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified");
    }
    if (GetDeviceLockStatus()) {
        return device->WriteStatus(FastbootResult::FAIL,
                                   "Download is not allowed on locked devices");
    }
    // arg[0] is the command name, arg[1] contains size of data to be downloaded
    // which should always be 8 bytes
    if (args[1].length() != 8) {
        return device->WriteStatus(FastbootResult::FAIL,
                                   "Invalid size (length of size != 8)");
    }
    unsigned int size;
    if (!android::base::ParseUint("0x" + args[1], &size, kMaxDownloadSizeDefault)) {
        return device->WriteStatus(FastbootResult::FAIL, "Invalid size");
    }
    if (size == 0) {
        return device->WriteStatus(FastbootResult::FAIL, "Invalid size (0)");
    }
    device->download_data().resize(size);
    if (!device->WriteStatus(FastbootResult::DATA, android::base::StringPrintf("%08x", size))) {
        return false;
    }
    if (device->HandleData(true, &device->download_data())) {
        return device->WriteStatus(FastbootResult::OKAY, "");
    }
    PLOG(ERROR) << "Couldn't download data";
    return device->WriteStatus(FastbootResult::FAIL, "Couldn't download data");
}
bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    if (args.size() < 2) {
        return device->WriteStatus(FastbootResult::FAIL, "Missing slot argument");
    }
    if (GetDeviceLockStatus()) {
        return device->WriteStatus(FastbootResult::FAIL,
                                   "set_active command is not allowed on locked devices");
    }
    int32_t slot = 0;
    if (!GetSlotNumber(args[1], &slot)) {
        // Slot suffix needs to be between 'a' and 'z'.
        return device->WriteStatus(FastbootResult::FAIL, "Bad slot suffix");
    }
    // Non-A/B devices will not have a boot control HAL.
    auto boot_control_hal = device->boot_control_hal();
    if (!boot_control_hal) {
        return device->WriteStatus(FastbootResult::FAIL,
                                   "Cannot set slot: boot control HAL absent");
    }
    if (slot >= boot_control_hal->GetNumSlots()) {
        return device->WriteStatus(FastbootResult::FAIL, "Slot out of range");
    }
    // If the slot is not changing, do nothing.
    if (args[1] == device->GetCurrentSlot()) {
        return device->WriteOkay("");
    }
    // Check how to handle the current snapshot state.
    if (auto hal11 = device->boot1_1()) {
        auto merge_status = hal11->getSnapshotMergeStatus();
        if (merge_status == MergeStatus::MERGING) {
            return device->WriteFail("Cannot change slots while a snapshot update is in progress");
        }
        // Note: we allow the slot change if the state is SNAPSHOTTED. First-
        // stage init does not have access to the HAL, and uses the slot number
        // and /metadata OTA state to determine whether a slot change occurred.
        // Booting into the old slot would erase the OTA, and switching A->B->A
        // would simply resume it if no boots occur in between. Re-flashing
        // partitions implicitly cancels the OTA, so leaving the state as-is is
        // safe.
        if (merge_status == MergeStatus::SNAPSHOTTED) {
            device->WriteInfo(
                    "Changing the active slot with a snapshot applied may cancel the"
                    " update.");
        }
    }
    CommandResult ret = boot_control_hal->SetActiveBootSlot(slot);
    if (ret.success) {
        // Save as slot suffix to match the suffix format as returned from
        // the boot control HAL.
        auto current_slot = "_" + args[1];
        device->set_active_slot(current_slot);
        return device->WriteStatus(FastbootResult::OKAY, "");
    }
    return device->WriteStatus(FastbootResult::FAIL, "Unable to set slot");
}
bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
    auto result = device->WriteStatus(FastbootResult::OKAY, "Shutting down");
    android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,fastboot");
    device->CloseDevice();
    TEMP_FAILURE_RETRY(pause());
    return result;
}
bool RebootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
    auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting");
    android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,from_fastboot");
    device->CloseDevice();
    TEMP_FAILURE_RETRY(pause());
    return result;
}
bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
    auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting bootloader");
    android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader");
    device->CloseDevice();
    TEMP_FAILURE_RETRY(pause());
    return result;
}
bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
    auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting fastboot");
    android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,fastboot");
    device->CloseDevice();
    TEMP_FAILURE_RETRY(pause());
    return result;
}
static bool EnterRecovery() {
    const char msg_switch_to_recovery = 'r';
    android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
    if (sock < 0) {
        PLOG(ERROR) << "Couldn't create sock";
        return false;
    }
    struct sockaddr_un addr = {.sun_family = AF_UNIX};
    strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
    if (connect(sock.get(), (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        PLOG(ERROR) << "Couldn't connect to recovery";
        return false;
    }
    // Switch to recovery will not update the boot reason since it does not
    // require a reboot.
    auto ret = write(sock.get(), &msg_switch_to_recovery, sizeof(msg_switch_to_recovery));
    if (ret != sizeof(msg_switch_to_recovery)) {
        PLOG(ERROR) << "Couldn't write message to switch to recovery";
        return false;
    }
    return true;
}
bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
    auto status = true;
    if (EnterRecovery()) {
        status = device->WriteStatus(FastbootResult::OKAY, "Rebooting to recovery");
    } else {
        status = device->WriteStatus(FastbootResult::FAIL, "Unable to reboot to recovery");
    }
    device->CloseDevice();
    TEMP_FAILURE_RETRY(pause());
    return status;
}
// Helper class for opening a handle to a MetadataBuilder and writing the new
// partition table to the same place it was read.
class PartitionBuilder {
  public:
    explicit PartitionBuilder(FastbootDevice* device, const std::string& partition_name);
    bool Write();
    bool Valid() const { return !!builder_; }
    MetadataBuilder* operator->() const { return builder_.get(); }
  private:
    FastbootDevice* device_;
    std::string super_device_;
    uint32_t slot_number_;
    std::unique_ptr<MetadataBuilder> builder_;
};
PartitionBuilder::PartitionBuilder(FastbootDevice* device, const std::string& partition_name)
    : device_(device) {
    std::string slot_suffix = GetSuperSlotSuffix(device, partition_name);
    slot_number_ = android::fs_mgr::SlotNumberForSlotSuffix(slot_suffix);
    auto super_device = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number_));
    if (!super_device) {
        return;
    }
    super_device_ = *super_device;
    builder_ = MetadataBuilder::New(super_device_, slot_number_);
}
bool PartitionBuilder::Write() {
    auto metadata = builder_->Export();
    if (!metadata) {
        return false;
    }
    return UpdateAllPartitionMetadata(device_, super_device_, *metadata.get());
}
bool CreatePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    if (args.size() < 3) {
        return device->WriteFail("Invalid partition name and size");
    }
    if (GetDeviceLockStatus()) {
        return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
    }
    uint64_t partition_size;
    std::string partition_name = args[1];
    if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
        return device->WriteFail("Invalid partition size");
    }
    PartitionBuilder builder(device, partition_name);
    if (!builder.Valid()) {
        return device->WriteFail("Could not open super partition");
    }
    // TODO(112433293) Disallow if the name is in the physical table as well.
    if (builder->FindPartition(partition_name)) {
        return device->WriteFail("Partition already exists");
    }
    auto partition = builder->AddPartition(partition_name, 0);
    if (!partition) {
        return device->WriteFail("Failed to add partition");
    }
    if (!builder->ResizePartition(partition, partition_size)) {
        builder->RemovePartition(partition_name);
        return device->WriteFail("Not enough space for partition");
    }
    if (!builder.Write()) {
        return device->WriteFail("Failed to write partition table");
    }
    return device->WriteOkay("Partition created");
}
bool DeletePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    if (args.size() < 2) {
        return device->WriteFail("Invalid partition name and size");
    }
    if (GetDeviceLockStatus()) {
        return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
    }
    std::string partition_name = args[1];
    PartitionBuilder builder(device, partition_name);
    if (!builder.Valid()) {
        return device->WriteFail("Could not open super partition");
    }
    builder->RemovePartition(partition_name);
    if (!builder.Write()) {
        return device->WriteFail("Failed to write partition table");
    }
    return device->WriteOkay("Partition deleted");
}
bool ResizePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    if (args.size() < 3) {
        return device->WriteFail("Invalid partition name and size");
    }
    if (GetDeviceLockStatus()) {
        return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
    }
    uint64_t partition_size;
    std::string partition_name = args[1];
    if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
        return device->WriteFail("Invalid partition size");
    }
    PartitionBuilder builder(device, partition_name);
    if (!builder.Valid()) {
        return device->WriteFail("Could not open super partition");
    }
    auto partition = builder->FindPartition(partition_name);
    if (!partition) {
        return device->WriteFail("Partition does not exist");
    }
    // Remove the updated flag to cancel any snapshots.
    uint32_t attrs = partition->attributes();
    partition->set_attributes(attrs & ~LP_PARTITION_ATTR_UPDATED);
    if (!builder->ResizePartition(partition, partition_size)) {
        return device->WriteFail("Not enough space to resize partition");
    }
    if (!builder.Write()) {
        return device->WriteFail("Failed to write partition table");
    }
    return device->WriteOkay("Partition resized");
}
void CancelPartitionSnapshot(FastbootDevice* device, const std::string& partition_name) {
    PartitionBuilder builder(device, partition_name);
    if (!builder.Valid()) return;
    auto partition = builder->FindPartition(partition_name);
    if (!partition) return;
    // Remove the updated flag to cancel any snapshots.
    uint32_t attrs = partition->attributes();
    partition->set_attributes(attrs & ~LP_PARTITION_ATTR_UPDATED);
    builder.Write();
}
bool FlashHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    if (args.size() < 2) {
        return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
    }
    if (GetDeviceLockStatus()) {
        return device->WriteStatus(FastbootResult::FAIL,
                                   "Flashing is not allowed on locked devices");
    }
    const auto& partition_name = args[1];
    if (IsProtectedPartitionDuringMerge(device, partition_name)) {
        auto message = "Cannot flash " + partition_name + " while a snapshot update is in progress";
        return device->WriteFail(message);
    }
    if (LogicalPartitionExists(device, partition_name)) {
        CancelPartitionSnapshot(device, partition_name);
    }
    int ret = Flash(device, partition_name);
    if (ret < 0) {
        return device->WriteStatus(FastbootResult::FAIL, strerror(-ret));
    }
    if (partition_name == "userdata") {
        PostWipeData();
    }
    return device->WriteStatus(FastbootResult::OKAY, "Flashing succeeded");
}
bool UpdateSuperHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    if (args.size() < 2) {
        return device->WriteFail("Invalid arguments");
    }
    if (GetDeviceLockStatus()) {
        return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
    }
    bool wipe = (args.size() >= 3 && args[2] == "wipe");
    return UpdateSuper(device, args[1], wipe);
}
static bool IsLockedDsu() {
    std::string active_dsu;
    android::gsi::GetActiveDsu(&active_dsu);
    return android::base::EndsWith(active_dsu, ".lock");
}
bool GsiHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    if (args.size() != 2) {
        return device->WriteFail("Invalid arguments");
    }
    AutoMountMetadata mount_metadata;
    if (!mount_metadata) {
        return device->WriteFail("Could not find GSI install");
    }
    if (!android::gsi::IsGsiInstalled()) {
        return device->WriteStatus(FastbootResult::FAIL, "No GSI is installed");
    }
    if ((args[1] == "wipe" || args[1] == "disable") && GetDeviceLockStatus() && IsLockedDsu()) {
        // Block commands that modify the states of locked DSU
        return device->WriteFail("Command not available on locked DSU/devices");
    }
    if (args[1] == "wipe") {
        if (!android::gsi::UninstallGsi()) {
            return device->WriteStatus(FastbootResult::FAIL, strerror(errno));
        }
    } else if (args[1] == "disable") {
        if (!android::gsi::DisableGsi()) {
            return device->WriteStatus(FastbootResult::FAIL, strerror(errno));
        }
    } else if (args[1] == "status") {
        std::string active_dsu;
        if (!android::gsi::IsGsiRunning()) {
            device->WriteInfo("Not running");
        } else if (!android::gsi::GetActiveDsu(&active_dsu)) {
            return device->WriteFail(strerror(errno));
        } else {
            device->WriteInfo("Running active DSU: " + active_dsu);
        }
    } else {
        return device->WriteFail("Invalid arguments");
    }
    return device->WriteStatus(FastbootResult::OKAY, "Success");
}
bool SnapshotUpdateHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    // Note that we use the HAL rather than mounting /metadata, since we want
    // our results to match the bootloader.
    auto hal = device->boot1_1();
    if (!hal) return device->WriteFail("Not supported");
    // If no arguments, return the same thing as a getvar. Note that we get the
    // HAL first so we can return "not supported" before we return the less
    // specific error message below.
    if (args.size() < 2 || args[1].empty()) {
        std::string message;
        if (!GetSnapshotUpdateStatus(device, {}, &message)) {
            return device->WriteFail("Could not determine update status");
        }
        device->WriteInfo(message);
        return device->WriteOkay("");
    }
    MergeStatus status = hal->getSnapshotMergeStatus();
    if (args.size() != 2) {
        return device->WriteFail("Invalid arguments");
    }
    if (args[1] == "cancel") {
        switch (status) {
            case MergeStatus::SNAPSHOTTED:
            case MergeStatus::MERGING: {
                const auto ret = hal->SetSnapshotMergeStatus(MergeStatus::CANCELLED);
                if (!ret.success) {
                    device->WriteFail("Failed to SetSnapshotMergeStatus(MergeStatus::CANCELLED) " +
                                      ret.errMsg);
                }
                break;
            }
            default:
                break;
        }
    } else if (args[1] == "merge") {
        if (status != MergeStatus::MERGING) {
            return device->WriteFail("No snapshot merge is in progress");
        }
        auto sm = SnapshotManager::New();
        if (!sm) {
            return device->WriteFail("Unable to create SnapshotManager");
        }
        if (!sm->FinishMergeInRecovery()) {
            return device->WriteFail("Unable to finish snapshot merge");
        }
    } else {
        return device->WriteFail("Invalid parameter to snapshot-update");
    }
    return device->WriteStatus(FastbootResult::OKAY, "Success");
}
namespace {
// Helper of FetchHandler.
class PartitionFetcher {
  public:
    static bool Fetch(FastbootDevice* device, const std::vector<std::string>& args) {
        if constexpr (!kEnableFetch) {
            return device->WriteFail("Fetch is not allowed on user build");
        }
        if (GetDeviceLockStatus()) {
            return device->WriteFail("Fetch is not allowed on locked devices");
        }
        PartitionFetcher fetcher(device, args);
        if (fetcher.Open()) {
            fetcher.Fetch();
        }
        CHECK(fetcher.ret_.has_value());
        return *fetcher.ret_;
    }
  private:
    PartitionFetcher(FastbootDevice* device, const std::vector<std::string>& args)
        : device_(device), args_(&args) {}
    // Return whether the partition is successfully opened.
    // If successfully opened, ret_ is left untouched. Otherwise, ret_ is set to the value
    // that FetchHandler should return.
    bool Open() {
        if (args_->size() < 2) {
            ret_ = device_->WriteFail("Missing partition arg");
            return false;
        }
        partition_name_ = args_->at(1);
        if (std::find(kAllowedPartitions.begin(), kAllowedPartitions.end(), partition_name_) ==
            kAllowedPartitions.end()) {
            ret_ = device_->WriteFail("Fetch is only allowed on [" +
                                      android::base::Join(kAllowedPartitions, ", ") + "]");
            return false;
        }
        if (!OpenPartition(device_, partition_name_, &handle_, O_RDONLY)) {
            ret_ = device_->WriteFail(
                    android::base::StringPrintf("Cannot open %s", partition_name_.c_str()));
            return false;
        }
        partition_size_ = get_block_device_size(handle_.fd());
        if (partition_size_ == 0) {
            ret_ = device_->WriteOkay(android::base::StringPrintf("Partition %s has size 0",
                                                                  partition_name_.c_str()));
            return false;
        }
        start_offset_ = 0;
        if (args_->size() >= 3) {
            if (!android::base::ParseUint(args_->at(2), &start_offset_)) {
                ret_ = device_->WriteFail("Invalid offset, must be integer");
                return false;
            }
            if (start_offset_ > std::numeric_limits<off64_t>::max()) {
                ret_ = device_->WriteFail(
                        android::base::StringPrintf("Offset overflows: %" PRIx64, start_offset_));
                return false;
            }
        }
        if (start_offset_ > partition_size_) {
            ret_ = device_->WriteFail(android::base::StringPrintf(
                    "Invalid offset 0x%" PRIx64 ", partition %s has size 0x%" PRIx64, start_offset_,
                    partition_name_.c_str(), partition_size_));
            return false;
        }
        uint64_t maximum_total_size_to_read = partition_size_ - start_offset_;
        total_size_to_read_ = maximum_total_size_to_read;
        if (args_->size() >= 4) {
            if (!android::base::ParseUint(args_->at(3), &total_size_to_read_)) {
                ret_ = device_->WriteStatus(FastbootResult::FAIL, "Invalid size, must be integer");
                return false;
            }
        }
        if (total_size_to_read_ == 0) {
            ret_ = device_->WriteOkay("Read 0 bytes");
            return false;
        }
        if (total_size_to_read_ > maximum_total_size_to_read) {
            ret_ = device_->WriteFail(android::base::StringPrintf(
                    "Invalid size to read 0x%" PRIx64 ", partition %s has size 0x%" PRIx64
                    " and fetching from offset 0x%" PRIx64,
                    total_size_to_read_, partition_name_.c_str(), partition_size_, start_offset_));
            return false;
        }
        if (total_size_to_read_ > kMaxFetchSizeDefault) {
            ret_ = device_->WriteFail(android::base::StringPrintf(
                    "Cannot fetch 0x%" PRIx64
                    " bytes because it exceeds maximum transport size 0x%x",
                    partition_size_, kMaxDownloadSizeDefault));
            return false;
        }
        return true;
    }
    // Assume Open() returns true.
    // After execution, ret_ is set to the value that FetchHandler should return.
    void Fetch() {
        CHECK(start_offset_ <= std::numeric_limits<off64_t>::max());
        if (lseek64(handle_.fd(), start_offset_, SEEK_SET) != static_cast<off64_t>(start_offset_)) {
            ret_ = device_->WriteFail(android::base::StringPrintf(
                    "On partition %s, unable to lseek(0x%" PRIx64 ": %s", partition_name_.c_str(),
                    start_offset_, strerror(errno)));
            return;
        }
        if (!device_->WriteStatus(FastbootResult::DATA,
                                  android::base::StringPrintf(
                                          "%08x", static_cast<uint32_t>(total_size_to_read_)))) {
            ret_ = false;
            return;
        }
        uint64_t end_offset = start_offset_ + total_size_to_read_;
        std::vector<char> buf(1_MiB);
        uint64_t current_offset = start_offset_;
        while (current_offset < end_offset) {
            // On any error, exit. We can't return a status message to the driver because
            // we are in the middle of writing data, so just let the driver guess what's wrong
            // by ending the data stream prematurely.
            uint64_t remaining = end_offset - current_offset;
            uint64_t chunk_size = std::min<uint64_t>(buf.size(), remaining);
            if (!android::base::ReadFully(handle_.fd(), buf.data(), chunk_size)) {
                PLOG(ERROR) << std::hex << "Unable to read 0x" << chunk_size << " bytes from "
                            << partition_name_ << " @ offset 0x" << current_offset;
                ret_ = false;
                return;
            }
            if (!device_->HandleData(false /* is read */, buf.data(), chunk_size)) {
                PLOG(ERROR) << std::hex << "Unable to send 0x" << chunk_size << " bytes of "
                            << partition_name_ << " @ offset 0x" << current_offset;
                ret_ = false;
                return;
            }
            current_offset += chunk_size;
        }
        ret_ = device_->WriteOkay(android::base::StringPrintf(
                "Fetched %s (offset=0x%" PRIx64 ", size=0x%" PRIx64, partition_name_.c_str(),
                start_offset_, total_size_to_read_));
    }
    static constexpr std::array<const char*, 3> kAllowedPartitions{
            "vendor_boot",
            "vendor_boot_a",
            "vendor_boot_b",
    };
    FastbootDevice* device_;
    const std::vector<std::string>* args_ = nullptr;
    std::string partition_name_;
    PartitionHandle handle_;
    uint64_t partition_size_ = 0;
    uint64_t start_offset_ = 0;
    uint64_t total_size_to_read_ = 0;
    // What FetchHandler should return.
    std::optional<bool> ret_ = std::nullopt;
};
}  // namespace
bool FetchHandler(FastbootDevice* device, const std::vector<std::string>& args) {
    return PartitionFetcher::Fetch(device, args);
}
tree: bc578ef605815cf4bbc3d788961dd8fce25926b9 [path history] [tgz]
commands.cpp
commands.h
fastboot_device.cpp
fastboot_device.h
flashing.cpp
flashing.h
main.cpp
tcp_client.cpp
tcp_client.h
usb.cpp
usb.h
usb_client.cpp
usb_client.h
usb_iouring.cpp
usb_iouring.h
utility.cpp
utility.h
variables.cpp
variables.h
Examples
In the examples below, S indicates the starting client sequence number.

Host                                    Client
======================================================================
[Initialization, S = 0x55AA]
[Host: version 1, 2048-byte packets. Client: version 2, 1024-byte packets.]
[Resulting values to use: version = 1, max packet size = 1024]
ID   Flag SeqH SeqL Data                ID   Flag SeqH SeqL Data
----------------------------------------------------------------------
0x01 0x00 0x00 0x00
                                        0x01 0x00 0x00 0x00 0x55 0xAA
0x02 0x00 0x55 0xAA 0x00 0x01 0x08 0x00
                                        0x02 0x00 0x55 0xAA 0x00 0x02 0x04 0x00

----------------------------------------------------------------------
[fastboot "getvar" commands, S = 0x0001]
ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
----------------------------------------------------------------------
0x03  0x00  0x00  0x01  getvar:version
                                        0x03  0x00  0x00  0x01
0x03  0x00  0x00  0x02
                                        0x03  0x00  0x00  0x02  OKAY0.4
0x03  0x00  0x00  0x03  getvar:none
                                        0x03  0x00  0x00  0x03
0x03  0x00  0x00  0x04
                                        0x03  0x00  0x00  0x04  FAILUnknown var

----------------------------------------------------------------------
[fastboot "INFO" responses, S = 0x0000]
ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
----------------------------------------------------------------------
0x03  0x00  0x00  0x00  <command>
                                        0x03  0x00  0x00  0x00
0x03  0x00  0x00  0x01
                                        0x03  0x00  0x00  0x01  INFOWait1
0x03  0x00  0x00  0x02
                                        0x03  0x00  0x00  0x02  INFOWait2
0x03  0x00  0x00  0x03
                                        0x03  0x00  0x00  0x03  OKAY

----------------------------------------------------------------------
[Chunking 2100 bytes of data, max packet size = 1024, S = 0xFFFF]
ID   Flag SeqH SeqL Data                ID   Flag SeqH SeqL Data
----------------------------------------------------------------------
0x03 0x00 0xFF 0xFF download:0000834
                                        0x03 0x00 0xFF 0xFF
0x03 0x00 0x00 0x00
                                        0x03 0x00 0x00 0x00 DATA0000834
0x03 0x01 0x00 0x01 <1020 bytes>
                                        0x03 0x00 0x00 0x01
0x03 0x01 0x00 0x02 <1020 bytes>
                                        0x03 0x00 0x00 0x02
0x03 0x00 0x00 0x03 <60 bytes>
                                        0x03 0x00 0x00 0x03
0x03 0x00 0x00 0x04
                                        0x03 0x00 0x00 0x04 OKAY

----------------------------------------------------------------------
[Unknown ID error, S = 0x0000]
ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
----------------------------------------------------------------------
0x10  0x00  0x00  0x00
                                        0x00  0x00  0x00  0x00  <error message>

----------------------------------------------------------------------
[Host packet loss and retransmission, S = 0x0000]
ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
----------------------------------------------------------------------
0x03  0x00  0x00  0x00  getvar:version [lost]
0x03  0x00  0x00  0x00  getvar:version [lost]
0x03  0x00  0x00  0x00  getvar:version
                                        0x03  0x00  0x00  0x00
0x03  0x00  0x00  0x01
                                        0x03  0x00  0x00  0x01  OKAY0.4

----------------------------------------------------------------------
[Client packet loss and retransmission, S = 0x0000]
ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
----------------------------------------------------------------------
0x03  0x00  0x00  0x00  getvar:version
                                        0x03  0x00  0x00  0x00 [lost]
0x03  0x00  0x00  0x00  getvar:version
                                        0x03  0x00  0x00  0x00 [lost]
0x03  0x00  0x00  0x00  getvar:version
                                        0x03  0x00  0x00  0x00
0x03  0x00  0x00  0x01
                                        0x03  0x00  0x00  0x01  OKAY0.4

----------------------------------------------------------------------
[Host packet delayed, S = 0x0000]
ID    Flags SeqH  SeqL  Data            ID    Flags SeqH  SeqL  Data
----------------------------------------------------------------------
0x03  0x00  0x00  0x00  getvar:version [delayed]
0x03  0x00  0x00  0x00  getvar:version
                                        0x03  0x00  0x00  0x00
0x03  0x00  0x00  0x01
                                        0x03  0x00  0x00  0x01  OKAY0.4
0x03  0x00  0x00  0x00  getvar:version [arrives late with old seq#, is ignored]
 Save
Packet Size
The maximum packet size is negotiated by the host and device in the Init packet. Devices must support at least 512-byte packets, but packet size has a direct correlation with download speed, so devices are strongly suggested to support at least 1024-byte packets. On a local network with 0.5ms round-trip time this will provide transfer rates of ~2MB/s. Over WiFi it will likely be significantly less.

Query and Initialization packets, which are sent before size negotiation is complete, must always be 512 bytes or less.

Packet Re-Transmission
The host will re-transmit any packet that does not receive a response. The requirement of exactly one device response packet per host packet is how we achieve reliability and in-order delivery of packets.

For simplicity of implementation, there is no windowing of multiple unacknowledged packets in this version of the protocol. The host will continue to send the same packet until a response is received. Windowing functionality may be implemented in future versions if necessary to increase performance.

The first Query packet will only be attempted a small number of times, but subsequent packets will attempt to retransmit for at least 1 minute before giving up. This means a device may safely ignore host UDP packets for up to 1 minute during long operations, e.g. writing to flash.

Continuation Packets
Any packet may set the continuation flag to indicate that the data is incomplete. Large data such as downloading an image may require many continuation packets. The receiver should respond to a continuation packet with an empty packet to acknowledge receipt. See examples below.

Summary
The host starts with a Query packet, then an Initialization packet, after which only Fastboot packets are sent. Fastboot packets may contain data from the host for writes, or from the device for reads, but not both.

Given a next expected sequence number S and a received packet P, the device behavior should be:

if P is a Query packet:
  * respond with a Query packet with S in the data field
else if P has sequence == S:
  * process P and take any required action
  * create a response packet R with the same ID and sequence as P, containing
    any response data required.
  * transmit R and save it in case of re-transmission
  * increment S
else if P has sequence == S - 1:
  * re-transmit the saved response packet R from above
else:
  * ignore the packet
 Save
Query
      The host sends a query packet once on startup to sync with the device.
      The host will not know the current sequence number, so the device must
      respond to all query packets regardless of sequence number.

      The response data field should contain a 2-byte big-endian value
      giving the next expected sequence number.

Init
      The host sends an init packet once the query response is returned. The
      device must abort any in-progress operation and prepare for a new
      fastboot session. This message is meant to allow recovery if a
      previous session failed, e.g. due to network error or user Ctrl+C.

      The data field contains two big-endian 2-byte values, a protocol
      version and the max UDP packet size (including the 4-byte header).
      Both the host and device will send these values, and in each case
      the minimum of the sent values must be used.

Fastboot
      These packets wrap the fastboot protocol. To write, the host will
      send a packet with fastboot data, and the device will reply with an
      empty packet as an ACK. To read, the host will send an empty packet,
      and the device will reply with fastboot data. The device may not give
      any data in the ACK packet.

Error
      The device may respond to any packet with an error packet to indicate
      a UDP protocol error. The data field should contain an ASCII string
      describing the error. This is the only case where a device is allowed
      to return a packet ID other than the one sent by the host.
UDP Protocol v1
The UDP protocol is more complex than TCP since we must implement reliability to ensure no packets are lost, but the general concept of wrapping the fastboot protocol is the same.

Overview:

As with TCP, the device will listen on UDP port 5554.
Maximum UDP packet size is negotiated during initialization.
The host drives all communication; the device may only send a packet as a response to a host packet.
If the host does not receive a response in 500ms it will re-transmit.
UDP Packet format
+----------+----+-------+-------+--------------------+
| Byte #   | 0  |   1   | 2 - 3 |  4+                |
+----------+----+-------+-------+--------------------+
| Contents | ID | Flags | Seq # | Data               |
+----------+----+-------+-------+--------------------+

ID      Packet ID:
          0x00: Error.
          0x01: Query.
          0x02: Initialization.
          0x03: Fastboot.

        Packet types are described in more detail below.

Flags   Packet flags: 0 0 0 0 0 0 0 C
          C=1 indicates a continuation packet; the data is too large and will
              continue in the next packet.

          Remaining bits are reserved for future use and must be set to 0.

Seq #   2-byte packet sequence number (big-endian). The host will increment
        this by 1 with each new packet, and the device must provide the
        corresponding sequence number in the response packets.

Data    Packet data, not present in all packets.
 Save
Where data_size is an unsigned 8-byte big-endian binary value, and data is the fastboot packet. The 8-byte length is intended to provide future-proofing even though currently fastboot packets have a 4-byte maximum length.

Example
In this example the fastboot host queries the device for two variables, “version” and “none”.

Host    <connect to the device on port 5555>
Host    FB01
Device  FB01
Host    [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x0E]getvar:version
Device  [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x07]OKAY0.4
Host    [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x0B]getvar:none
Device  [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x14]FAILUnknown variable
Host    <disconnect>
 Save
TCP Protocol v1
The TCP protocol is designed to be a simple way to use the fastboot protocol over ethernet if USB is not available.

The device will open a TCP server on port 5554 and wait for a fastboot client to connect.

Handshake
Upon connecting, both sides will send a 4-byte handshake message to ensure they are speaking the same protocol. This consists of the ASCII characters “FB” followed by a 2-digit base-10 ASCII version number. For example, the version 1 handshake message will be [FB01].

If either side detects a malformed handshake, it should disconnect.

The protocol version to use must be the minimum of the versions sent by each side; if either side cannot speak this protocol version, it should disconnect.

Fastboot Data
Once the handshake is complete, fastboot data will be sent as follows:

[data_size][data]
 Save
is-logical:%s       If the value is "yes", the partition is logical.
                    Otherwise the partition is physical.
update-super:%s:%s  Write the previously downloaded image to a super
                    partition. Unlike the "flash" command, this has
                    special rules. The image must have been created by
                    the lpmake command, and must not be a sparse image.
                    If the last argument is "wipe", then all existing
                    logical partitions are deleted. If no final argument
                    is specified, the partition tables are merged. Any
                    partition in the new image that does not exist in the
                    old image is created with a zero size.

                    In all cases, this will cause the temporary "scratch"
                    partition to be deleted if it exists.

create-logical-partition:%s:%d
                    Create a logical partition with the given name and
                    size, in the super partition.

delete-logical-partition:%s
                    Delete a logical partition with the given name.

resize-logical-partition:%s:%d
                    Change the size of the named logical partition.
version             Version of FastBoot protocol supported.
                    It should be "0.4" for this document.

version-bootloader  Version string for the Bootloader.

version-baseband    Version string of the Baseband Software

product             Name of the product

serialno            Product serial number

secure              If the value is "yes", this is a secure
                    bootloader requiring a signature before
                    it will install or boot images.

is-userspace        If the value is "yes", the device is running
                    fastbootd. Otherwise, it is running fastboot
                    in the bootloader.
After generating the list of tasks to execute, Fastboot will try and
optimize the flashing of the dynamic partitions by constructing an
optimized flash super task. Fastboot will explicitly pattern match the
following commands and try and concatenate it into this task. (doing so
will allow us to avoid the reboot into userspace fastbootd which takes
significant time)

//Optimizable Block
reboot fastboot
update-super                        ---> generate optimized flash super task
$FOR EACH {dynamic partition}
    flash {dynamic partition}
After generating the list of tasks to execute, Fastboot will try and
optimize the flashing of the dynamic partitions by constructing an
optimized flash super task. Fastboot will explicitly pattern match the
following commands and try and concatenate it into this task. (doing so
will allow us to avoid the reboot into userspace fastbootd which takes
significant time)

//Optimizable Block
reboot fastboot
update-super                        ---> generate optimized flash super task
$FOR EACH {dynamic partition}
    flash {dynamic partition}
flash %s           Flash a given partition. Optional arguments include
                   --slot-other, {filename_path}, --apply-vbmeta

reboot %s          Reboot to either bootloader or fastbootd

update-super       Updates the super partition

if-wipe            Conditionally run some other functionality if
                   wipe is specified

erase %s           Erase a given partition (can only be used in conjunction)
                   with if-wipe -> eg. if-wipe erase cache
getvar:%s          Read a config/version variable from the bootloader.
                   The variable contents will be returned after the
                   OKAY response. If the variable is unknown, the bootloader
                   should return a FAIL response, optionally with an error
                   message.

                   Previous versions of this document indicated that getvar
                   should return an empty OKAY response for unknown
                   variables, so older devices might exhibit this behavior,
                   but new implementations should return FAIL instead.

download:%08x      Write data to memory which will be later used
                   by "boot", "ramdisk", "flash", etc.  The client
                   will reply with "DATA%08x" if it has enough
                   space in RAM or "FAIL" if not.  The size of
                   the download is remembered.

upload             Read data from memory which was staged by the last
                   command, e.g. an oem command.  The client will reply
                   with "DATA%08x" if it is ready to send %08x bytes of
                   data.  If no data was staged in the last command,
                   the client must reply with "FAIL".  After the client
                   successfully sends %08x bytes, the client shall send
                   a single packet starting with "OKAY".  Clients
                   should not support "upload" unless it supports an
                   oem command that requires "upload" capabilities.

flash:%s           Write the previously downloaded image to the
                   named partition (if possible).

erase:%s           Erase the indicated partition (clear to 0xFFs)

boot               The previously downloaded data is a boot.img
                   and should be booted according to the normal
                   procedure for a boot.img

continue           Continue booting as normal (if possible)

reboot             Reboot the device.

reboot-bootloader
                   Reboot back into the bootloader.
                   Useful for upgrade processes that require upgrading
                   the bootloader and then upgrading other partitions
                   using the new bootloader.
Host:    "getvar:version"        request version variable

Client:  "OKAY0.4"               return version "0.4"

Host:    "getvar:nonexistant"    request some undefined variable

Client:  "FAILUnknown variable"  getvar failure; see getvar details below

Host:    "download:00001234"     request to send 0x1234 bytes of data

Client:  "DATA00001234"          ready to accept data

Host:    < 0x1234 bytes >        send data

Client:  "OKAY"                  success

Host:    "flash:bootloader"      request to flash the data to the bootloader

Client:  "INFOerasing flash"     indicate status / progress
         "INFOwriting flash"
         "OKAY"                  indicate success

Host:    "powerdown"             send a command

Client:  "FAILunknown command"   indicate failure
/*
 * Copyright (C) 2008 The Android Open Source Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/usbdevice_fs.h>
#include <linux/version.h>
#include <linux/usb/ch9.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <chrono>
#include <memory>
#include <thread>
#include "usb.h"
#include "util.h"
using namespace std::chrono_literals;
#define MAX_RETRIES 2
/* Timeout in seconds for usb_wait_for_disconnect.
 * It doesn't usually take long for a device to disconnect (almost always
 * under 2 seconds) but we'll time out after 3 seconds just in case.
 */
#define WAIT_FOR_DISCONNECT_TIMEOUT  3
#ifdef TRACE_USB
#define DBG1(x...) fprintf(stderr, x)
#define DBG(x...) fprintf(stderr, x)
#else
#define DBG(x...)
#define DBG1(x...)
#endif
// Kernels before 3.3 have a 16KiB transfer limit. That limit was replaced
// with a 16MiB global limit in 3.3, but each URB submitted required a
// contiguous kernel allocation, so you would get ENOMEM if you tried to
// send something larger than the biggest available contiguous kernel
// memory region. 256KiB contiguous allocations are generally not reliable
// on a device kernel that has been running for a while fragmenting its
// memory, but that shouldn't be a problem for fastboot on the host.
// In 3.6, the contiguous buffer limit was removed by allocating multiple
// 16KiB chunks and having the USB driver stitch them back together while
// transmitting using a scatter-gather list, so 256KiB bulk transfers should
// be reliable.
// 256KiB seems to work, but 1MiB bulk transfers lock up my z620 with a 3.13
// kernel.
// 128KiB was experimentally found to be enough to saturate the bus at
// SuperSpeed+, so we first try double that for writes. If the operation fails
// due to a lack of contiguous regions (or an ancient kernel), try smaller sizes
// until we find one that works (see LinuxUsbTransport::Write). Reads are less
// performance critical so for now just use a known good size.
#define MAX_USBFS_BULK_WRITE_SIZE (256 * 1024)
#define MAX_USBFS_BULK_READ_SIZE (16 * 1024)
// This size should pretty much always work (it's compatible with pre-3.3
// kernels and it's what we used to use historically), so if it doesn't work
// something has gone badly wrong.
#define MIN_USBFS_BULK_WRITE_SIZE (16 * 1024)
struct usb_handle
{
    char fname[64];
    int desc;
    unsigned char ep_in;
    unsigned char ep_out;
};
class LinuxUsbTransport : public UsbTransport {
  public:
    explicit LinuxUsbTransport(std::unique_ptr<usb_handle> handle, uint32_t ms_timeout = 0)
        : handle_(std::move(handle)), ms_timeout_(ms_timeout) {}
    ~LinuxUsbTransport() override;
    ssize_t Read(void* data, size_t len) override;
    ssize_t Write(const void* data, size_t len) override;
    int Close() override;
    int Reset() override;
    int WaitForDisconnect() override;
  private:
    std::unique_ptr<usb_handle> handle_;
    const uint32_t ms_timeout_;
    size_t max_usbfs_bulk_write_size_ = MAX_USBFS_BULK_WRITE_SIZE;
    DISALLOW_COPY_AND_ASSIGN(LinuxUsbTransport);
};
/* True if name isn't a valid name for a USB device in /sys/bus/usb/devices.
 * Device names are made up of numbers, dots, and dashes, e.g., '7-1.5'.
 * We reject interfaces (e.g., '7-1.5:1.0') and host controllers (e.g. 'usb1').
 * The name must also start with a digit, to disallow '.' and '..'
 */
static inline int badname(const char *name)
{
    if (!isdigit(*name))
      return 1;
    while(*++name) {
        if(!isdigit(*name) && *name != '.' && *name != '-')
            return 1;
    }
    return 0;
}
static int check(void *_desc, int len, unsigned type, int size)
{
    struct usb_descriptor_header *hdr = (struct usb_descriptor_header *)_desc;
    if(len < size) return -1;
    if(hdr->bLength < size) return -1;
    if(hdr->bLength > len) return -1;
    if(hdr->bDescriptorType != type) return -1;
    return 0;
}
static int filter_usb_device(char* sysfs_name,
                             char *ptr, int len, int writable,
                             ifc_match_func callback,
                             int *ept_in_id, int *ept_out_id, int *ifc_id)
{
    struct usb_device_descriptor *dev;
    struct usb_config_descriptor *cfg;
    struct usb_interface_descriptor *ifc;
    struct usb_endpoint_descriptor *ept;
    struct usb_ifc_info info;
    int in, out;
    unsigned i;
    unsigned e;
    if (check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
        return -1;
    dev = (struct usb_device_descriptor *)ptr;
    len -= dev->bLength;
    ptr += dev->bLength;
    if (check(ptr, len, USB_DT_CONFIG, USB_DT_CONFIG_SIZE))
        return -1;
    cfg = (struct usb_config_descriptor *)ptr;
    len -= cfg->bLength;
    ptr += cfg->bLength;
    info.dev_vendor = dev->idVendor;
    info.dev_product = dev->idProduct;
    info.dev_class = dev->bDeviceClass;
    info.dev_subclass = dev->bDeviceSubClass;
    info.dev_protocol = dev->bDeviceProtocol;
    info.writable = writable;
    snprintf(info.device_path, sizeof(info.device_path), "usb:%s", sysfs_name);
    /* Read device serial number (if there is one).
     * We read the serial number from sysfs, since it's faster and more
     * reliable than issuing a control pipe read, and also won't
     * cause problems for devices which don't like getting descriptor
     * requests while they're in the middle of flashing.
     */
    info.serial_number[0] = '\0';
    if (dev->iSerialNumber) {
        char path[80];
        int fd;
        snprintf(path, sizeof(path),
                 "/sys/bus/usb/devices/%s/serial", sysfs_name);
        path[sizeof(path) - 1] = '\0';
        fd = open(path, O_RDONLY);
        if (fd >= 0) {
            int chars_read = read(fd, info.serial_number,
                                  sizeof(info.serial_number) - 1);
            close(fd);
            if (chars_read <= 0)
                info.serial_number[0] = '\0';
            else if (info.serial_number[chars_read - 1] == '\n') {
                // strip trailing newline
                info.serial_number[chars_read - 1] = '\0';
            }
        }
    }
    for(i = 0; i < cfg->bNumInterfaces; i++) {
        while (len > 0) {
	        struct usb_descriptor_header *hdr = (struct usb_descriptor_header *)ptr;
            if (check(hdr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE) == 0)
                break;
            len -= hdr->bLength;
            ptr += hdr->bLength;
        }
        if (len <= 0)
            return -1;
        ifc = (struct usb_interface_descriptor *)ptr;
        len -= ifc->bLength;
        ptr += ifc->bLength;
        in = -1;
        out = -1;
        info.ifc_class = ifc->bInterfaceClass;
        info.ifc_subclass = ifc->bInterfaceSubClass;
        info.ifc_protocol = ifc->bInterfaceProtocol;
        for(e = 0; e < ifc->bNumEndpoints; e++) {
            while (len > 0) {
	            struct usb_descriptor_header *hdr = (struct usb_descriptor_header *)ptr;
                if (check(hdr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE) == 0)
                    break;
                len -= hdr->bLength;
                ptr += hdr->bLength;
            }
            if (len < 0) {
                break;
            }
            ept = (struct usb_endpoint_descriptor *)ptr;
            len -= ept->bLength;
            ptr += ept->bLength;
            if((ept->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
                continue;
            if(ept->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
                in = ept->bEndpointAddress;
            } else {
                out = ept->bEndpointAddress;
            }
            // For USB 3.0 devices skip the SS Endpoint Companion descriptor
            if (check((struct usb_descriptor_hdr *)ptr, len,
                      USB_DT_SS_ENDPOINT_COMP, USB_DT_SS_EP_COMP_SIZE) == 0) {
                len -= USB_DT_SS_EP_COMP_SIZE;
                ptr += USB_DT_SS_EP_COMP_SIZE;
            }
        }
        info.has_bulk_in = (in != -1);
        info.has_bulk_out = (out != -1);
        std::string interface;
        auto path = android::base::StringPrintf("/sys/bus/usb/devices/%s/%s:1.%d/interface",
                                                sysfs_name, sysfs_name, ifc->bInterfaceNumber);
        if (android::base::ReadFileToString(path, &interface)) {
            if (!interface.empty() && interface.back() == '\n') {
                interface.pop_back();
            }
            snprintf(info.interface, sizeof(info.interface), "%s", interface.c_str());
        }
        if(callback(&info) == 0) {
            *ept_in_id = in;
            *ept_out_id = out;
            *ifc_id = ifc->bInterfaceNumber;
            return 0;
        }
    }
    return -1;
}
static int read_sysfs_string(const char *sysfs_name, const char *sysfs_node,
                             char* buf, int bufsize)
{
    char path[80];
    int fd, n;
    snprintf(path, sizeof(path),
             "/sys/bus/usb/devices/%s/%s", sysfs_name, sysfs_node);
    path[sizeof(path) - 1] = '\0';
    fd = open(path, O_RDONLY);
    if (fd < 0)
        return -1;
    n = read(fd, buf, bufsize - 1);
    close(fd);
    if (n < 0)
        return -1;
    buf[n] = '\0';
    return n;
}
static int read_sysfs_number(const char *sysfs_name, const char *sysfs_node)
{
    char buf[16];
    int value;
    if (read_sysfs_string(sysfs_name, sysfs_node, buf, sizeof(buf)) < 0)
        return -1;
    if (sscanf(buf, "%d", &value) != 1)
        return -1;
    return value;
}
/* Given the name of a USB device in sysfs, get the name for the same
 * device in devfs. Returns 0 for success, -1 for failure.
 */
static int convert_to_devfs_name(const char* sysfs_name,
                                 char* devname, int devname_size)
{
    int busnum, devnum;
    busnum = read_sysfs_number(sysfs_name, "busnum");
    if (busnum < 0)
        return -1;
    devnum = read_sysfs_number(sysfs_name, "devnum");
    if (devnum < 0)
        return -1;
    snprintf(devname, devname_size, "/dev/bus/usb/%03d/%03d", busnum, devnum);
    return 0;
}
static std::unique_ptr<usb_handle> find_usb_device(const char* base, ifc_match_func callback)
{
    std::unique_ptr<usb_handle> usb;
    char devname[64];
    char desc[1024];
    int n, in, out, ifc;
    struct dirent *de;
    int fd;
    int writable;
    std::unique_ptr<DIR, decltype(&closedir)> busdir(opendir(base), closedir);
    if (busdir == 0) return 0;
    while ((de = readdir(busdir.get())) && (usb == nullptr)) {
        if (badname(de->d_name)) continue;
        if (!convert_to_devfs_name(de->d_name, devname, sizeof(devname))) {
//            DBG("[ scanning %s ]\n", devname);
            writable = 1;
            if ((fd = open(devname, O_RDWR)) < 0) {
                // Check if we have read-only access, so we can give a helpful
                // diagnostic like "adb devices" does.
                writable = 0;
                if ((fd = open(devname, O_RDONLY)) < 0) {
                    continue;
                }
            }
            n = read(fd, desc, sizeof(desc));
            if (filter_usb_device(de->d_name, desc, n, writable, callback, &in, &out, &ifc) == 0) {
                usb.reset(new usb_handle());
                strcpy(usb->fname, devname);
                usb->ep_in = in;
                usb->ep_out = out;
                usb->desc = fd;
                n = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &ifc);
                if (n != 0) {
                    close(fd);
                    usb.reset();
                    continue;
                }
            } else {
                close(fd);
            }
        }
    }
    return usb;
}
LinuxUsbTransport::~LinuxUsbTransport() {
    Close();
}
ssize_t LinuxUsbTransport::Write(const void* _data, size_t len)
{
    unsigned char *data = (unsigned char*) _data;
    unsigned count = 0;
    struct usbdevfs_urb urb[2] = {};
    bool pending[2] = {};
    if (handle_->ep_out == 0 || handle_->desc == -1) {
        return -1;
    }
    auto submit_urb = [&](size_t i) {
        while (true) {
            int xfer = (len > max_usbfs_bulk_write_size_) ? max_usbfs_bulk_write_size_ : len;
            urb[i].type = USBDEVFS_URB_TYPE_BULK;
            urb[i].endpoint = handle_->ep_out;
            urb[i].buffer_length = xfer;
            urb[i].buffer = data;
            urb[i].usercontext = (void *)i;
            int n = ioctl(handle_->desc, USBDEVFS_SUBMITURB, &urb[i]);
            if (n != 0) {
                if (errno == ENOMEM && max_usbfs_bulk_write_size_ > MIN_USBFS_BULK_WRITE_SIZE) {
                    max_usbfs_bulk_write_size_ /= 2;
                    continue;
                }
                DBG("ioctl(USBDEVFS_SUBMITURB) failed\n");
                return false;
            }
            pending[i] = true;
            count += xfer;
            len -= xfer;
            data += xfer;
            return true;
        }
    };
    auto reap_urb = [&](size_t i) {
        while (pending[i]) {
            struct usbdevfs_urb *urbp;
            int res = ioctl(handle_->desc, USBDEVFS_REAPURB, &urbp);
            if (res != 0) {
                DBG("ioctl(USBDEVFS_REAPURB) failed\n");
                return false;
            }
            size_t done = (size_t)urbp->usercontext;
            if (done >= 2 || !pending[done]) {
                DBG("unexpected urb\n");
                return false;
            }
            if (urbp->status != 0 || urbp->actual_length != urbp->buffer_length) {
                DBG("urb returned error\n");
                return false;
            }
            pending[done] = false;
        }
        return true;
    };
    if (!submit_urb(0)) {
        return -1;
    }
    while (len > 0) {
        if (!submit_urb(1)) {
            return -1;
        }
        if (!reap_urb(0)) {
            return -1;
        }
        if (len <= 0) {
            if (!reap_urb(1)) {
                return -1;
            }
            return count;
        }
        if (!submit_urb(0)) {
            return -1;
        }
        if (!reap_urb(1)) {
            return -1;
        }
    }
    if (!reap_urb(0)) {
        return -1;
    }
    return count;
}
ssize_t LinuxUsbTransport::Read(void* _data, size_t len)
{
    unsigned char *data = (unsigned char*) _data;
    unsigned count = 0;
    struct usbdevfs_bulktransfer bulk;
    int n, retry;
    if (handle_->ep_in == 0 || handle_->desc == -1) {
        return -1;
    }
    while (len > 0) {
        int xfer = (len > MAX_USBFS_BULK_READ_SIZE) ? MAX_USBFS_BULK_READ_SIZE : len;
        bulk.ep = handle_->ep_in;
        bulk.len = xfer;
        bulk.data = data;
        bulk.timeout = ms_timeout_;
        retry = 0;
        do {
            DBG("[ usb read %d fd = %d], fname=%s\n", xfer, handle_->desc, handle_->fname);
            n = ioctl(handle_->desc, USBDEVFS_BULK, &bulk);
            DBG("[ usb read %d ] = %d, fname=%s, Retry %d \n", xfer, n, handle_->fname, retry);
            if (n < 0) {
                DBG1("ERROR: n = %d, errno = %d (%s)\n",n, errno, strerror(errno));
                if (++retry > MAX_RETRIES) return -1;
                std::this_thread::sleep_for(100ms);
            }
        } while (n < 0);
        count += n;
        len -= n;
        data += n;
        if(n < xfer) {
            break;
        }
    }
    return count;
}
int LinuxUsbTransport::Close()
{
    int fd;
    fd = handle_->desc;
    handle_->desc = -1;
    if(fd >= 0) {
        close(fd);
        DBG("[ usb closed %d ]\n", fd);
    }
    return 0;
}
int LinuxUsbTransport::Reset() {
    int ret = 0;
    // We reset the USB connection
    if ((ret = ioctl(handle_->desc, USBDEVFS_RESET, 0))) {
        return ret;
    }
    return 0;
}
std::unique_ptr<UsbTransport> usb_open(ifc_match_func callback, uint32_t timeout_ms) {
    std::unique_ptr<UsbTransport> result;
    std::unique_ptr<usb_handle> handle = find_usb_device("/sys/bus/usb/devices", callback);
    if (handle) {
        result = std::make_unique<LinuxUsbTransport>(std::move(handle), timeout_ms);
    }
    return result;
}
/* Wait for the system to notice the device is gone, so that a subsequent
 * fastboot command won't try to access the device before it's rebooted.
 * Returns 0 for success, -1 for timeout.
 */
int LinuxUsbTransport::WaitForDisconnect()
{
  double deadline = now() + WAIT_FOR_DISCONNECT_TIMEOUT;
  while (now() < deadline) {
    if (access(handle_->fname, F_OK)) return 0;
    std::this_thread::sleep_for(50ms);
  }
  return -1;
}
device/
fuzzer/
fuzzy_fastboot/
testdata/
.clang-format
⇨ ../.clang-format-4
Android.bp
Android.mk
bootimg_utils.cpp
bootimg_utils.h
constants.h
fastboot.bash
fastboot.cpp
fastboot.h
fastboot_driver.cpp
fastboot_driver.h
fastboot_driver_interface.h
fastboot_driver_mock.h
fastboot_driver_test.cpp
fastboot_integration_test.xml
fastboot_test.cpp
filesystem.cpp
filesystem.h
fs.cpp
fs.h
LICENSE
main.cpp
mock_transport.h
OWNERS
README.md
result.h
socket.cpp
socket.h
socket_mock.cpp
socket_mock.h
socket_test.cpp
storage.cpp
storage.h
super_flash_helper.cpp
super_flash_helper.h
super_flash_helper_test.cpp
task.cpp
task.h
task_test.cpp
tcp.cpp
tcp.h
tcp_test.cpp
test_fastboot.py
TEST_MAPPING
transport.h
udp.cpp
udp.h
udp_test.cpp
usb.h
usb_linux.cpp
usb_osx.cpp
usb_windows.cpp
util.cpp
util.h
vendor_boot_img_utils.cpp
vendor_boot_img_utils.h
vendor_boot_img_utils_test.cpp
#pragma once
#include <inttypes.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <android-base/unique_fd.h>
#include <bootimg.h>
#include <liblp/liblp.h>
#include <sparse/sparse.h>
using SparsePtr = std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)>;
/* util stuff */
double now();
void set_verbose();
// These printf-like functions are implemented in terms of vsnprintf, so they
// use the same attribute for compile-time format string checking.
void die(const char* fmt, ...) __attribute__((__noreturn__))
__attribute__((__format__(__printf__, 1, 2)));
void verbose(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
void die(const std::string& str) __attribute__((__noreturn__));
bool should_flash_in_userspace(const android::fs_mgr::LpMetadata& metadata,
                               const std::string& partition_name);
bool is_sparse_file(android::base::borrowed_fd fd);
int64_t get_file_size(android::base::borrowed_fd fd);
std::string fb_fix_numeric_var(std::string var);
class ImageSource {
  public:
    virtual ~ImageSource(){};
    virtual bool ReadFile(const std::string& name, std::vector<char>* out) const = 0;
    virtual android::base::unique_fd OpenFile(const std::string& name) const = 0;
};
#cd to the relevant file
cd /usr/share/applications
#us nano text editor on the proper file
sudo nano yourapp.desktop
#Make entry into the file and save it 
[Desktop Entry]
Name=YourAppName
Exec=/path/to/your/executable
Icon=/path/to/your/icon
Type=Application
Terminal=false
add_action( 'admin_menu', 'my_custom_menu_page' );
function my_custom_menu_page() {
add_menu_page(
__( 'Custom Menu Title', 'textdomain' ),
'Custom Menu',
'manage_options',
'custompage',
'my_custom_menu_page_content',
'dashicons-admin-generic',
);
}

add_action( 'admin_menu', 'my_custom_submenu_page' );
function my_custom_submenu_page() {
add_submenu_page(
'custompage',
__( 'Custom Submenu Title', 'textdomain' ),
'Custom Submenu',
'manage_options',
'customsubmenu',
'my_custom_submenu_page_content'
);
}
 function direction(item) {
    const increment =
      item.classList[1] === "decrease"
        ? counter--
        : item.classList[1] === "increase"
        ? counter++
        : item.classList[1] === "reset"
        ? (counter = 0)
        : counter; 

    return increment;
  }
star

Mon Jul 15 2024 15:27:35 GMT+0000 (Coordinated Universal Time)

@quanganh141220 #php #single #product

star

Mon Jul 15 2024 15:10:56 GMT+0000 (Coordinated Universal Time)

@lettuceranger #github #vs-code #commandline

star

Mon Jul 15 2024 15:04:06 GMT+0000 (Coordinated Universal Time) https://v17.angular.io/guide/i18n-optional-manage-marked-text

@lettuceranger #angular #lokalise #key-names

star

Mon Jul 15 2024 14:59:49 GMT+0000 (Coordinated Universal Time)

@nishpod

star

Mon Jul 15 2024 14:59:39 GMT+0000 (Coordinated Universal Time) https://stackoverflow.com/questions/9562304/git-github-commit-with-extended-message-description?newreg

@lettuceranger #commandline #github

star

Mon Jul 15 2024 10:24:13 GMT+0000 (Coordinated Universal Time)

@peterteszary #php

star

Mon Jul 15 2024 09:45:46 GMT+0000 (Coordinated Universal Time)

@signup

star

Mon Jul 15 2024 09:35:23 GMT+0000 (Coordinated Universal Time)

@Zohaib77 #react.js

star

Mon Jul 15 2024 09:33:40 GMT+0000 (Coordinated Universal Time)

@Zohaib77 #react.js

star

Mon Jul 15 2024 08:55:48 GMT+0000 (Coordinated Universal Time) https://spring.academy/courses/building-a-rest-api-with-spring-boot/lessons/data-contracts

@Mannan2105

star

Mon Jul 15 2024 03:51:54 GMT+0000 (Coordinated Universal Time)

@NoFox420 #javascript

star

Mon Jul 15 2024 02:24:11 GMT+0000 (Coordinated Universal Time)

@NoFox420 #javascript

star

Mon Jul 15 2024 01:05:52 GMT+0000 (Coordinated Universal Time)

@vishalsingh21

star

Sun Jul 14 2024 23:28:21 GMT+0000 (Coordinated Universal Time) https://gunsbuyerusa.com/product-category/ak47-ak74-rifles-and-pistols-for-sale/

@ak74uforsale

star

Sun Jul 14 2024 22:49:59 GMT+0000 (Coordinated Universal Time) https://www.rock-chips.com/a/cn/product/RK32xilie/2016/1109/798.html

@Dewaldt

star

Sun Jul 14 2024 22:44:01 GMT+0000 (Coordinated Universal Time) https://www.rock-chips.com/a/cn/product/rkpower/2017/0308/834.html

@Dewaldt

star

Sun Jul 14 2024 19:34:39 GMT+0000 (Coordinated Universal Time) https://csshero.org/mesher/

@webisko #css

star

Sun Jul 14 2024 15:32:24 GMT+0000 (Coordinated Universal Time)

@ishwarpatel100 #tailwind

star

Sun Jul 14 2024 15:14:49 GMT+0000 (Coordinated Universal Time) https://chatgpt.com/c/66391479-3f97-4db8-a2fe-2b8817ba3dcc

@ishwarpatel100

star

Sun Jul 14 2024 15:13:57 GMT+0000 (Coordinated Universal Time)

@quanganh141220 #php #single #product

star

Sun Jul 14 2024 14:05:37 GMT+0000 (Coordinated Universal Time) https://youtu.be/cdHEpbBVjRM?list=PLDzeHZWIZsTryvtXdMr6rPh4IDexB5NIA

@vishnu_jha #c++ #dsa #recursion #string #mergesort

star

Sun Jul 14 2024 13:03:21 GMT+0000 (Coordinated Universal Time)

@MinaTimo

star

Sun Jul 14 2024 11:13:35 GMT+0000 (Coordinated Universal Time)

@roamtravel

star

Sun Jul 14 2024 07:55:58 GMT+0000 (Coordinated Universal Time) https://youtu.be/WyY2Af3k1xI

@vishnu_jha #c++ #dsa #recursion #string #palindrome #checkpalindrome

star

Sun Jul 14 2024 07:40:35 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/refs/heads/main/fastboot/device/commands.cpp

@Dewaldt

star

Sun Jul 14 2024 07:39:10 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/refs/heads/main/fastboot/device/

@Dewaldt

star

Sun Jul 14 2024 07:37:41 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/

@Dewaldt

star

Sun Jul 14 2024 07:37:01 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/

@Dewaldt

star

Sun Jul 14 2024 07:36:26 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/#fastboot

@Dewaldt

star

Sun Jul 14 2024 07:35:57 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/

@Dewaldt

star

Sun Jul 14 2024 07:34:28 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/

@Dewaldt

star

Sun Jul 14 2024 07:33:43 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/

@Dewaldt

star

Sun Jul 14 2024 07:32:47 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/#fastboot

@Dewaldt

star

Sun Jul 14 2024 07:31:53 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/#fastboot

@Dewaldt

star

Sun Jul 14 2024 07:31:35 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/#fastboot

@Dewaldt

star

Sun Jul 14 2024 07:31:20 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/#fastboot

@Dewaldt

star

Sun Jul 14 2024 07:31:10 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/#fastboot

@Dewaldt

star

Sun Jul 14 2024 07:30:20 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/#fastboot

@Dewaldt

star

Sun Jul 14 2024 07:30:09 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/#fastboot

@Dewaldt

star

Sun Jul 14 2024 07:29:57 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/#fastboot

@Dewaldt

star

Sun Jul 14 2024 07:29:14 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/#fastboot

@Dewaldt

star

Sun Jul 14 2024 07:21:22 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/refs/heads/main/fastboot/usb_linux.cpp

@Dewaldt

star

Sun Jul 14 2024 07:15:35 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/master/fastboot/

@Dewaldt

star

Sun Jul 14 2024 07:12:37 GMT+0000 (Coordinated Universal Time) https://android.googlesource.com/platform/system/core/+/refs/heads/main/fastboot/util.h

@Dewaldt

star

Sun Jul 14 2024 05:43:20 GMT+0000 (Coordinated Universal Time)

@jrray #python

star

Sun Jul 14 2024 04:33:03 GMT+0000 (Coordinated Universal Time) https://exnori.com/wallets

@RJ45

star

Sat Jul 13 2024 22:50:15 GMT+0000 (Coordinated Universal Time)

@webisko #php

star

Sat Jul 13 2024 22:19:01 GMT+0000 (Coordinated Universal Time)

@davidmchale #ternary #nested #function

star

Sat Jul 13 2024 16:57:43 GMT+0000 (Coordinated Universal Time) https://limpanomecpf.framer.website/

@danzcampos

Save snippets that work with our extensions

Available in the Chrome Web Store Get Firefox Add-on Get VS Code extension