commit 9c88b8f7f6e790923fd85b78fb4f6505cb4e501d Author: happy Date: Tue Aug 25 14:47:05 2026 -0400 Base: BD-J Adjustments Blu-ray scaffold Vendored BD-J SDK, tsMuxeR + local VLC plugins, ffmpeg asset generation, and a signed BD-J Xlet menu (org.homebrew.MyXlet) authored into a UDF 2.50 ISO. Co-Authored-By: Claude Opus 4.8 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f500b4a --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +build/ +assets/generated/ +tools/downloads/ +*.iso +*.class +META-INF/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b0ce61b --- /dev/null +++ b/Makefile @@ -0,0 +1,116 @@ +DISC_LABEL := ADJUSTMENTS +DURATION ?= 24 + +BDJSDK_HOME := $(CURDIR)/vendor/bdj-sdk +JAVA8_HOME ?= $(BDJSDK_HOME)/host/jdk8 +JAVAC := $(JAVA8_HOME)/bin/javac +JAR := $(JAVA8_HOME)/bin/jar +BDSIGNER := $(BDJSDK_HOME)/host/bin/bdsigner +MAKEFS := $(BDJSDK_HOME)/host/bin/makefs +TSMUXER := $(CURDIR)/tools/tsmuxer/tsMuxeR + +BUILD_DIR := build +ASSET_DIR := assets/generated +MUX_DIR := $(BUILD_DIR)/muxed-bd +DISC_DIR := $(BUILD_DIR)/disc +CLASSES_DIR := $(BUILD_DIR)/classes + +VIDEO_ES := $(ASSET_DIR)/feature.m2v +AUDIO_ES := $(ASSET_DIR)/feature.ac3 +META_FILE := $(BUILD_DIR)/feature.meta +ISO_FILE := $(BUILD_DIR)/adjustments.iso +JAR_FILE := $(DISC_DIR)/BDMV/JAR/00000.jar + +SOURCES := $(shell find src -name '*.java' -type f 2>/dev/null) +PERMISSIONS := $(shell find src -name '*.perm' -type f 2>/dev/null) +STUBS := $(BDJSDK_HOME)/target/lib/enhanced-stubs.zip:$(BDJSDK_HOME)/target/lib/sony-stubs.jar + +export JAVA8_HOME + +.PHONY: all bootstrap assets mux disc iso inspect run open clean distclean + +all: $(ISO_FILE) + +bootstrap: + scripts/bootstrap-tools.sh + +assets: $(VIDEO_ES) $(AUDIO_ES) + +mux: $(MUX_DIR)/BDMV/STREAM/00000.m2ts + +disc: $(JAR_FILE) + +iso: $(ISO_FILE) + +$(VIDEO_ES): + mkdir -p $(ASSET_DIR) + ffmpeg -hide_banner -y \ + -f lavfi -i "smptebars=size=1280x720:rate=24000/1001" \ + -t $(DURATION) \ + -c:v mpeg2video -pix_fmt yuv420p -g 12 -bf 2 \ + -b:v 8000k -maxrate 15000k -bufsize 9781248 \ + -f mpeg2video $@ + +$(AUDIO_ES): + mkdir -p $(ASSET_DIR) + ffmpeg -hide_banner -y \ + -f lavfi -i "sine=frequency=73:sample_rate=48000" \ + -t $(DURATION) \ + -c:a ac3 -b:a 192k $@ + +$(META_FILE): $(VIDEO_ES) $(AUDIO_ES) + mkdir -p $(BUILD_DIR) + printf '%s\n' \ + 'MUXOPT --blu-ray --label="$(DISC_LABEL)"' \ + 'V_MPEG-2, $(CURDIR)/$(VIDEO_ES), fps=23.976, ar=16:9, lang=eng' \ + 'A_AC3, $(CURDIR)/$(AUDIO_ES), lang=eng' \ + > $@ + +$(MUX_DIR)/BDMV/STREAM/00000.m2ts: $(META_FILE) $(TSMUXER) + rm -rf $(MUX_DIR) + mkdir -p $(MUX_DIR) + $(TSMUXER) $(META_FILE) $(MUX_DIR) + +$(JAR_FILE): $(SOURCES) $(PERMISSIONS) $(MUX_DIR)/BDMV/STREAM/00000.m2ts + rm -rf $(DISC_DIR) $(CLASSES_DIR) + mkdir -p $(DISC_DIR) $(CLASSES_DIR) $(DISC_DIR)/BDMV/JAR + cp -a $(BDJSDK_HOME)/resources/AVCHD/. $(DISC_DIR)/ + mkdir -p $(DISC_DIR)/BDMV/BACKUP/CLIPINF $(DISC_DIR)/BDMV/BACKUP/PLAYLIST + cp -a $(MUX_DIR)/BDMV/STREAM/00000.m2ts $(DISC_DIR)/BDMV/STREAM/00000.m2ts + cp -a $(MUX_DIR)/BDMV/CLIPINF/00000.clpi $(DISC_DIR)/BDMV/CLIPINF/00000.clpi + cp -a $(MUX_DIR)/BDMV/PLAYLIST/00000.mpls $(DISC_DIR)/BDMV/PLAYLIST/00000.mpls + cp -a $(MUX_DIR)/BDMV/CLIPINF/00000.clpi $(DISC_DIR)/BDMV/BACKUP/CLIPINF/00000.clpi + cp -a $(MUX_DIR)/BDMV/PLAYLIST/00000.mpls $(DISC_DIR)/BDMV/BACKUP/PLAYLIST/00000.mpls + $(JAVAC) -Xlint:-options -source 1.3 -target 1.3 -cp $(STUBS) -d $(CLASSES_DIR) $(SOURCES) + mkdir -p $(CLASSES_DIR)/org/homebrew + cp $(PERMISSIONS) $(CLASSES_DIR)/org/homebrew/ + $(JAR) cf $@ -C $(CLASSES_DIR) . + $(BDSIGNER) -keystore $(BDJSDK_HOME)/resources/sig.ks $@ + rm -rf META-INF + +$(ISO_FILE): $(JAR_FILE) $(MAKEFS) + mkdir -p $(BUILD_DIR) + $(MAKEFS) -m 64m -t udf -o T=bdre,v=2.50,L=$(DISC_LABEL) $@ $(DISC_DIR) + +$(TSMUXER): + scripts/bootstrap-tools.sh + +$(MAKEFS): + scripts/bootstrap-tools.sh + +inspect: $(ISO_FILE) + bd_info $(ISO_FILE) + bd_list_titles $(ISO_FILE) -a + +run: bootstrap $(ISO_FILE) + scripts/run-vlc.sh $(ISO_FILE) + +open: run + +clean: + rm -rf $(BUILD_DIR) $(ASSET_DIR) + find src -name '*.class' -delete + rm -rf META-INF + +distclean: clean + rm -rf tools/tsmuxer tools/downloads diff --git a/README.md b/README.md new file mode 100644 index 0000000..eecb3ed --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# Adjustments Blu-ray + +BD-J scaffold for the off-beat dark comedy `Adjustments`. + +## Tooling + +- `mise` pins Temurin JDK 8 for legacy BD-J bytecode. +- `vendor/bdj-sdk` contains the BD-J Linux SDK pieces used for signing, + template BD-J metadata, stubs, and UDF ISO generation. +- `tools/tsmuxer/tsMuxeR` authors the generated elementary streams into a + Blu-ray playlist, clipinfo, and `.m2ts`. +- `tools/vlc-plugins` can hold project-local Arch VLC Blu-ray plugins when the + system VLC package is split and `vlc-plugin-bluray` is not installed. +- `ffmpeg` generates the temporary feature clip. +- `vlc` opens the resulting ISO. + +## Commands + +```sh +make bootstrap +make +make inspect +make run +``` + +The ISO is written to: + +```text +build/adjustments.iso +``` + +`make run` launches VLC through the Blu-ray access module, not as a generic +media file: + +```sh +vlc bluray:///absolute/path/to/build/adjustments.iso +``` + +The initial menu is a Java Xlet overlay with a few bonus-feature placeholders +and a hidden menu stub. The actual generated video is a short ffmpeg SMPTE bars +pattern with AC-3 audio, authored as playlist `00000`. diff --git a/docs/AUTHORING.md b/docs/AUTHORING.md new file mode 100644 index 0000000..f87aaca --- /dev/null +++ b/docs/AUTHORING.md @@ -0,0 +1,32 @@ +# Adjustments BD-J Authoring Notes + +This project starts from the BD-J Linux SDK template disc metadata. The Xlet +entry point is intentionally `org.homebrew.MyXlet` because +`vendor/bdj-sdk/resources/AVCHD/BDMV/BDJO/00000.bdjo` launches that class. + +The build does three separate jobs: + +1. `ffmpeg` generates a temporary 720p23.976 MPEG-2 elementary stream and AC-3 + audio. +2. `tsMuxeR` authors those streams into Blu-ray playlist, clipinfo, and M2TS + files. +3. The BD-J SDK signs `BDMV/JAR/00000.jar` and packages the final UDF 2.50 ISO. + +Useful commands: + +```sh +make bootstrap +make +make inspect +make run +``` + +Hidden-menu scaffold: + +- The visible menu has the main feature, two bonus-feature placeholders, and + settings. +- Pressing `6`, `6`, `6` opens the hidden placeholder menu. +- The generated main feature is playlist `00000`. + +For real assets later, keep the `00000` numbering until the BDJO/index metadata +is regenerated or replaced with an authoring tool that owns those files too. diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..c1ffa9e --- /dev/null +++ b/mise.toml @@ -0,0 +1,2 @@ +[tools] +java = "temurin-8.0.502+7" diff --git a/scripts/bootstrap-tools.sh b/scripts/bootstrap-tools.sh new file mode 100755 index 0000000..d7e3ee7 --- /dev/null +++ b/scripts/bootstrap-tools.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +MISE_BIN="${MISE_BIN:-$HOME/.local/bin/mise}" +BDJSDK_HOME="$ROOT_DIR/vendor/bdj-sdk" +TSMUXER_VERSION="2.7.0" +TSMUXER_ZIP="$ROOT_DIR/tools/downloads/tsMuxer-$TSMUXER_VERSION-linux.zip" +TSMUXER_BIN="$ROOT_DIR/tools/tsmuxer/tsMuxeR" +VLC_PLUGIN_DIR="$ROOT_DIR/tools/vlc-plugins/usr/lib/vlc/plugins" + +if [[ ! -x "$MISE_BIN" ]]; then + echo "Installing mise to $MISE_BIN" + curl https://mise.run | sh +fi + +"$MISE_BIN" install + +JDK8_HOME="$("$MISE_BIN" where java@temurin-8.0.502+7)" +ln -sfn "$JDK8_HOME" "$BDJSDK_HOME/host/jdk8" + +if [[ ! -x "$BDJSDK_HOME/host/bin/makefs" ]]; then + make -C "$BDJSDK_HOME/host/src/makefs_termux" + make -C "$BDJSDK_HOME/host/src/makefs_termux" install DESTDIR="$BDJSDK_HOME/host" +fi + +if [[ ! -f "$BDJSDK_HOME/target/lib/sony-stubs.jar" ]]; then + make -C "$BDJSDK_HOME/target" +fi + +if [[ ! -x "$TSMUXER_BIN" ]]; then + mkdir -p "$ROOT_DIR/tools/downloads" "$ROOT_DIR/tools/tsmuxer" + curl -L "https://github.com/justdan96/tsMuxer/releases/download/$TSMUXER_VERSION/tsMuxer-$TSMUXER_VERSION-linux.zip" -o "$TSMUXER_ZIP" + unzip -qo "$TSMUXER_ZIP" -d "$ROOT_DIR/tools/tsmuxer" + chmod +x "$TSMUXER_BIN" +fi + +if [[ -x /usr/bin/pacman && ! -f "$VLC_PLUGIN_DIR/access/liblibbluray_plugin.so" ]]; then + mkdir -p "$ROOT_DIR/tools/downloads" "$ROOT_DIR/tools/vlc-plugins" + for url in $(pacman -Sp vlc-plugin-bluray vlc-plugin-mpeg2 vlc-plugin-x264 vlc-plugin-dvd 2>/dev/null); do + pkg="$ROOT_DIR/tools/downloads/$(basename "$url")" + curl -L "$url" -o "$pkg" + tar -I zstd -xf "$pkg" -C "$ROOT_DIR/tools/vlc-plugins" usr/lib/vlc/plugins + done +fi + +echo "BD-J tools ready." diff --git a/scripts/build-and-run.sh b/scripts/build-and-run.sh new file mode 100755 index 0000000..9e3b7e7 --- /dev/null +++ b/scripts/build-and-run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT_DIR" + +make +scripts/run-vlc.sh build/adjustments.iso + diff --git a/scripts/run-vlc.sh b/scripts/run-vlc.sh new file mode 100755 index 0000000..085fb1b --- /dev/null +++ b/scripts/run-vlc.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +ISO_PATH="${1:-build/adjustments.iso}" +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +MISE_BIN="${MISE_BIN:-$HOME/.local/bin/mise}" + +if [[ ! -f "$ISO_PATH" ]]; then + echo "Missing ISO: $ISO_PATH" >&2 + echo "Run: make" >&2 + exit 1 +fi + +if [[ -x "$MISE_BIN" ]]; then + JDK8_HOME="$("$MISE_BIN" where java@temurin-8.0.502+7 2>/dev/null || true)" +else + JDK8_HOME="" +fi + +if [[ -z "$JDK8_HOME" && -d "$ROOT_DIR/vendor/bdj-sdk/host/jdk8" ]]; then + JDK8_HOME="$(cd "$ROOT_DIR/vendor/bdj-sdk/host/jdk8" && pwd)" +fi + +if [[ -n "$JDK8_HOME" ]]; then + export JAVA_HOME="$JDK8_HOME/jre" + export JDK_HOME="$JDK8_HOME" + export LD_LIBRARY_PATH="$JDK8_HOME/jre/lib/amd64/server:${LD_LIBRARY_PATH:-}" +fi + +LOCAL_VLC_PLUGINS="$ROOT_DIR/tools/vlc-plugins/usr/lib/vlc/plugins" +if [[ -d "$LOCAL_VLC_PLUGINS" ]]; then + export VLC_PLUGIN_PATH="$LOCAL_VLC_PLUGINS:/usr/lib/vlc/plugins${VLC_PLUGIN_PATH:+:$VLC_PLUGIN_PATH}" +fi + +ABS_ISO="$(cd "$(dirname "$ISO_PATH")" && pwd)/$(basename "$ISO_PATH")" +exec vlc --reset-plugins-cache "bluray://$ABS_ISO" diff --git a/src/org/homebrew/AdjustmentsMenu.java b/src/org/homebrew/AdjustmentsMenu.java new file mode 100644 index 0000000..1e94bc7 --- /dev/null +++ b/src/org/homebrew/AdjustmentsMenu.java @@ -0,0 +1,160 @@ +package org.homebrew; + +import java.awt.Color; +import java.awt.Container; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +public class AdjustmentsMenu extends Container implements KeyListener { + private static final String[] MAIN_ITEMS = { + "MAIN FEATURE", + "BONUS: WAITING ROOM OUTTAKES", + "BONUS: CLAIM DENIED", + "SETTINGS" + }; + + private static final String[] HIDDEN_ITEMS = { + "DELETED FORM 13-B", + "THE BASEMENT MENU", + "COMPLIANCE CONFESSIONAL", + "RETURN" + }; + + private final Font titleFont = new Font("SansSerif", Font.BOLD, 62); + private final Font itemFont = new Font("SansSerif", Font.BOLD, 28); + private final Font smallFont = new Font("SansSerif", Font.PLAIN, 18); + private int selected = 0; + private boolean hidden; + private int codeProgress; + private String status = "BD-J scaffold loaded"; + + public AdjustmentsMenu() { + setFocusable(true); + } + + public void paint(Graphics g) { + int w = getWidth(); + int h = getHeight(); + String[] items = hidden ? HIDDEN_ITEMS : MAIN_ITEMS; + + g.setColor(new Color(8, 8, 10)); + g.fillRect(0, 0, w, h); + + drawBars(g, w, h); + + g.setFont(titleFont); + g.setColor(new Color(245, 245, 230)); + g.drawString("ADJUSTMENTS", 78, 120); + + g.setFont(smallFont); + g.setColor(new Color(167, 201, 190)); + g.drawString(hidden ? "UNFILED MATERIALS" : "MAIN MENU", 84, 160); + + for (int i = 0; i < items.length; i++) { + int y = 250 + (i * 58); + boolean isSelected = i == selected; + + if (isSelected) { + g.setColor(new Color(183, 40, 48)); + g.fillRect(74, y - 34, 510, 44); + g.setColor(new Color(255, 248, 220)); + } else { + g.setColor(new Color(202, 202, 190)); + } + + g.setFont(itemFont); + g.drawString(items[i], 96, y); + } + + g.setFont(smallFont); + g.setColor(new Color(125, 125, 118)); + g.drawString(status, 82, h - 78); + + drawStamp(g, w, h); + } + + private void drawBars(Graphics g, int w, int h) { + g.setColor(new Color(22, 28, 30)); + for (int i = 0; i < 12; i++) { + int x = (i * 137) % w; + g.fillRect(x, 0, 8, h); + } + + g.setColor(new Color(178, 40, 47)); + g.fillRect(0, h - 34, w, 8); + g.setColor(new Color(48, 112, 102)); + g.fillRect(0, h - 24, w, 6); + } + + private void drawStamp(Graphics g, int w, int h) { + String copy = hidden ? "UNAPPROVED" : "TEMPORARY"; + g.setFont(new Font("SansSerif", Font.BOLD, 30)); + FontMetrics metrics = g.getFontMetrics(); + int textWidth = metrics.stringWidth(copy); + + g.setColor(new Color(52, 52, 48)); + g.drawRect(w - 312, 72, 230, 82); + g.drawRect(w - 306, 78, 218, 70); + g.setColor(new Color(183, 40, 48)); + g.drawString(copy, w - 198 - (textWidth / 2), 124); + } + + private void activate() { + String[] items = hidden ? HIDDEN_ITEMS : MAIN_ITEMS; + String item = items[selected]; + + if (hidden && selected == HIDDEN_ITEMS.length - 1) { + hidden = false; + selected = 0; + status = "Returned to approved materials"; + } else if ("MAIN FEATURE".equals(item)) { + status = "Main feature is playlist 00000"; + } else if ("SETTINGS".equals(item)) { + status = "Settings stub selected"; + } else { + status = item + " stub selected"; + } + + repaint(); + } + + private void unlockHidden() { + hidden = true; + selected = 0; + codeProgress = 0; + status = "Hidden menu unlocked"; + repaint(); + } + + public void keyPressed(KeyEvent e) { + int code = e.getKeyCode(); + String[] items = hidden ? HIDDEN_ITEMS : MAIN_ITEMS; + + if (code == KeyEvent.VK_UP) { + selected = (selected + items.length - 1) % items.length; + repaint(); + } else if (code == KeyEvent.VK_DOWN) { + selected = (selected + 1) % items.length; + repaint(); + } else if (code == KeyEvent.VK_ENTER || code == KeyEvent.VK_SPACE) { + activate(); + } else if (code == KeyEvent.VK_6 || e.getKeyChar() == '6') { + codeProgress++; + if (codeProgress >= 3) { + unlockHidden(); + } + } else { + codeProgress = 0; + } + } + + public void keyReleased(KeyEvent e) { + } + + public void keyTyped(KeyEvent e) { + } +} + diff --git a/src/org/homebrew/MyXlet.java b/src/org/homebrew/MyXlet.java new file mode 100644 index 0000000..711d371 --- /dev/null +++ b/src/org/homebrew/MyXlet.java @@ -0,0 +1,64 @@ +package org.homebrew; + +import java.awt.BorderLayout; +import javax.tv.xlet.Xlet; +import javax.tv.xlet.XletContext; +import javax.tv.xlet.XletStateChangeException; +import org.havi.ui.HScene; +import org.havi.ui.HSceneFactory; + +public class MyXlet extends Thread implements Xlet { + private HScene scene; + private AdjustmentsMenu menu; + private boolean running; + + public void initXlet(XletContext context) throws XletStateChangeException { + menu = new AdjustmentsMenu(); + menu.setSize(1280, 720); + + scene = HSceneFactory.getInstance().getDefaultHScene(); + scene.add(menu, BorderLayout.CENTER); + scene.addKeyListener(menu); + scene.validate(); + scene.repaint(); + } + + public void startXlet() throws XletStateChangeException { + running = true; + menu.setVisible(true); + scene.setVisible(true); + menu.requestFocus(); + scene.requestFocus(); + start(); + } + + public void pauseXlet() { + if (menu != null) { + menu.setVisible(false); + } + } + + public void destroyXlet(boolean unconditional) { + running = false; + interrupt(); + + if (scene != null && menu != null) { + menu.setVisible(false); + scene.remove(menu); + } + + scene = null; + menu = null; + } + + public void run() { + while (running) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + running = false; + } + } + } +} + diff --git a/src/org/homebrew/bluray.MyXlet.perm b/src/org/homebrew/bluray.MyXlet.perm new file mode 100644 index 0000000..b222f99 --- /dev/null +++ b/src/org/homebrew/bluray.MyXlet.perm @@ -0,0 +1,4 @@ +grant { + permission java.security.AllPermission; +}; + diff --git a/tools/tsmuxer/tsMuxeR b/tools/tsmuxer/tsMuxeR new file mode 100755 index 0000000..106022c Binary files /dev/null and b/tools/tsmuxer/tsMuxeR differ diff --git a/tools/vlc-plugins/usr/lib/vlc/plugins/access/libdvdnav_plugin.so b/tools/vlc-plugins/usr/lib/vlc/plugins/access/libdvdnav_plugin.so new file mode 100755 index 0000000..89ac2da Binary files /dev/null and b/tools/vlc-plugins/usr/lib/vlc/plugins/access/libdvdnav_plugin.so differ diff --git a/tools/vlc-plugins/usr/lib/vlc/plugins/access/libdvdread_plugin.so b/tools/vlc-plugins/usr/lib/vlc/plugins/access/libdvdread_plugin.so new file mode 100755 index 0000000..82f71a8 Binary files /dev/null and b/tools/vlc-plugins/usr/lib/vlc/plugins/access/libdvdread_plugin.so differ diff --git a/tools/vlc-plugins/usr/lib/vlc/plugins/access/liblibbluray_plugin.so b/tools/vlc-plugins/usr/lib/vlc/plugins/access/liblibbluray_plugin.so new file mode 100755 index 0000000..c589bf8 Binary files /dev/null and b/tools/vlc-plugins/usr/lib/vlc/plugins/access/liblibbluray_plugin.so differ diff --git a/tools/vlc-plugins/usr/lib/vlc/plugins/codec/liblibmpeg2_plugin.so b/tools/vlc-plugins/usr/lib/vlc/plugins/codec/liblibmpeg2_plugin.so new file mode 100755 index 0000000..8b7212f Binary files /dev/null and b/tools/vlc-plugins/usr/lib/vlc/plugins/codec/liblibmpeg2_plugin.so differ diff --git a/tools/vlc-plugins/usr/lib/vlc/plugins/codec/libx26410b_plugin.so b/tools/vlc-plugins/usr/lib/vlc/plugins/codec/libx26410b_plugin.so new file mode 100755 index 0000000..9dfcfb2 Binary files /dev/null and b/tools/vlc-plugins/usr/lib/vlc/plugins/codec/libx26410b_plugin.so differ diff --git a/tools/vlc-plugins/usr/lib/vlc/plugins/codec/libx264_plugin.so b/tools/vlc-plugins/usr/lib/vlc/plugins/codec/libx264_plugin.so new file mode 100755 index 0000000..e7698e8 Binary files /dev/null and b/tools/vlc-plugins/usr/lib/vlc/plugins/codec/libx264_plugin.so differ diff --git a/tools/vlc-plugins/usr/lib/vlc/plugins/plugins.dat b/tools/vlc-plugins/usr/lib/vlc/plugins/plugins.dat new file mode 100644 index 0000000..d7077a1 Binary files /dev/null and b/tools/vlc-plugins/usr/lib/vlc/plugins/plugins.dat differ diff --git a/vendor/bdj-sdk/.gitignore b/vendor/bdj-sdk/.gitignore new file mode 100644 index 0000000..e403478 --- /dev/null +++ b/vendor/bdj-sdk/.gitignore @@ -0,0 +1,7 @@ +*~ +host/bin/makefs +host/jdk +host/jdk8 +host/jdk11 +*.class + diff --git a/vendor/bdj-sdk/README.md b/vendor/bdj-sdk/README.md new file mode 100644 index 0000000..e83f721 --- /dev/null +++ b/vendor/bdj-sdk/README.md @@ -0,0 +1,33 @@ +# BD-J Linux SDK +This is a set of tools to simplify building BD-J ISO images on GNU/Linux systems. +It is an adaptation of the Win32 [minimal BD-J toolkit for the PS3][ps3], +with an updated authoring tool from [the HD Cookbook][hdc]. For creating ISO +images, we use a [Linux port][makefs_termux] of [NetBSD makefs][makefs] ported +by [Andrew Randrianasulu][Randrianasulu]. + +## Building +On Debian-flavored operating systems, you can invoke the following commands to +install dependencies, and compile the source code. + +```console +john@localhost:~$ sudo apt-get install build-essential libbsd-dev git pkg-config openjdk-8-jdk-headless openjdk-11-jdk-headless +john@localhost:~$ git clone --recurse-submodules https://github.com/john-tornblom/bdj-sdk +john@localhost:~$ ln -s /usr/lib/jvm/java-8-openjdk-amd64 bdj-sdk/host/jdk8 +john@localhost:~$ ln -s /usr/lib/jvm/java-11-openjdk-amd64 bdj-sdk/host/jdk11 +john@localhost:~$ make -C bdj-sdk/host/src/makefs_termux +john@localhost:~$ make -C bdj-sdk/host/src/makefs_termux install DESTDIR=$PWD/bdj-sdk/host +john@localhost:~$ make -C bdj-sdk/target +``` + +## Usage example +```console +john@localhost:~$ make -C bdj-sdk/samples/helloworld +``` +If everything was built successfully, you will find an BD-RE iso file +`bdj-sdk/samples/helloworld/helloworld.iso` + +[ps3]: https://ps3.brewology.com/downloads/download.php?id=2171&mcid=4 +[hdc]: http://oliverlietz.github.io/bd-j/hdcookbook.html +[makefs_termux]: https://github.com/Randrianasulu/makefs_termux +[makefs]: https://man.netbsd.org/makefs.8 +[Randrianasulu]: https://github.com/Randrianasulu diff --git a/vendor/bdj-sdk/host/bin/bdsigner b/vendor/bdj-sdk/host/bin/bdsigner new file mode 100755 index 0000000..49cfa55 --- /dev/null +++ b/vendor/bdj-sdk/host/bin/bdsigner @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +SCRIPTDIR="${BASH_SOURCE[0]}" +SCRIPTDIR="$(dirname "${SCRIPTDIR}")" +LIBDIR=${SCRIPTDIR}/../lib + +if [ "${JAVA8_HOME}" != "" ]; then + JAVA=${JAVA8_HOME}/bin/java +else + JAVA=java +fi + +$JAVA -cp ${LIBDIR}/'*' net.java.bd.tools.security.BDSigner $* + diff --git a/vendor/bdj-sdk/host/lib/LICENSE b/vendor/bdj-sdk/host/lib/LICENSE new file mode 100644 index 0000000..f017f49 --- /dev/null +++ b/vendor/bdj-sdk/host/lib/LICENSE @@ -0,0 +1,52 @@ +Copyright (c) 2007, Sun Microsystems, Inc. + +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. + * Neither the name of Sun Microsystems nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +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. + + Note: In order to comply with the binary form redistribution + requirement in the above license, the licensee may include + a URL reference to a copy of the required copyright notice, + the list of conditions and the disclaimer in a human readable + file with the binary form of the code that is subject to the + above license. For example, such file could be put on a + Blu-ray disc containing the binary form of the code or could + be put in a JAR file that is broadcast via a digital television + broadcast medium. In any event, you must include in any end + user licenses governing any code that includes the code subject + to the above license (in source and/or binary form) a disclaimer + that is at least as protective of Sun as the disclaimers in the + above license. + + A copy of the required copyright notice, the list of conditions and + the disclaimer will be maintained at + https://hdcookbook.dev.java.net/misc/license.html . + Thus, licensees may comply with the binary form redistribution + requirement with a text file that contains the following text: + + A copy of the license(s) governing this code is located + at https://hdcookbook.dev.java.net/misc/license.html + diff --git a/vendor/bdj-sdk/host/lib/README b/vendor/bdj-sdk/host/lib/README new file mode 100644 index 0000000..75cb87a --- /dev/null +++ b/vendor/bdj-sdk/host/lib/README @@ -0,0 +1,2 @@ +Source code available at: + https://github.com/oliverlietz/bd-j/tree/master/DiscCreationTools diff --git a/vendor/bdj-sdk/host/lib/bcprov-jdk15-137.jar b/vendor/bdj-sdk/host/lib/bcprov-jdk15-137.jar new file mode 100644 index 0000000..795242b Binary files /dev/null and b/vendor/bdj-sdk/host/lib/bcprov-jdk15-137.jar differ diff --git a/vendor/bdj-sdk/host/lib/jdktools.jar b/vendor/bdj-sdk/host/lib/jdktools.jar new file mode 100644 index 0000000..c180426 Binary files /dev/null and b/vendor/bdj-sdk/host/lib/jdktools.jar differ diff --git a/vendor/bdj-sdk/host/lib/security.jar b/vendor/bdj-sdk/host/lib/security.jar new file mode 100644 index 0000000..9258c70 Binary files /dev/null and b/vendor/bdj-sdk/host/lib/security.jar differ diff --git a/vendor/bdj-sdk/host/src/makefs_termux/Makefile b/vendor/bdj-sdk/host/src/makefs_termux/Makefile new file mode 100644 index 0000000..7b6417b --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/Makefile @@ -0,0 +1,44 @@ +# $NetBSD: Makefile,v 1.36 2013/08/05 14:41:57 reinoud Exp $ +# +CFLAGS=`pkg-config --cflags libbsd-overlay` +LDFLAGS=`pkg-config --libs libbsd-overlay` +WARNS?= 5 + +# .include + +PROG= makefs +SRCS= udf.c strstuff.c \ + makefs.c \ + walk.c +MAN= makefs.8 +#CC= clang +DESTDIR ?= /usr/local + +MKNODSRC= ${NETBSDSRCDIR}/sbin/mknod +MTREESRC= ${NETBSDSRCDIR}/usr.sbin/mtree + +CPPFLAGS+= -I${.CURDIR} -I${MKNODSRC} -I${MTREESRC} -DMAKEFS +#CPPFLAGS+= -DMSDOSFS_DEBUG +#PATH: ${MKNODSRC} ${MTREESRC} + +#.include "${.CURDIR}/cd9660/Makefile.inc" +#.include "${.CURDIR}/chfs/Makefile.inc" +#.include "${.CURDIR}/ffs/Makefile.inc" +#.include "${.CURDIR}/v7fs/Makefile.inc" +#.include "${.CURDIR}/msdos/Makefile.inc" + +SRCS+= udf_core.c udf_osta.c + +#if !defined(HOSTPROG) +DPADD+= ${LIBUTIL} ${LIBM} +LDADD+= -lutil -lm +#endif + +prog: + ${CC} -o $(PROG) $(SRCS) $(LDFLAGS) -D_GNU_SOURCE -std=c11 -lm -I./udf + +install: + install -D $(PROG) $(DESTDIR)/bin/$(PROG) + +#.include +# DO NOT DELETE diff --git a/vendor/bdj-sdk/host/src/makefs_termux/README b/vendor/bdj-sdk/host/src/makefs_termux/README new file mode 100644 index 0000000..bf418d6 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/README @@ -0,0 +1,135 @@ +$NetBSD: README,v 1.7 2015/01/12 19:50:47 christos Exp $ + +makefs - build a file system image from a directory tree + +NOTES: + + * This tool uses modified local copies of source found in other + parts of the tree. This is intentional. + + * makefs is a work in progress, and subject to change. + + +user overview: +-------------- + +makefs creates a file system image from a given directory tree. +the following file system types can be built: + + cd9660 ISO 9660 file system + chfs "Chip" file system, for flash devices + ffs BSD fast file system + msdos MS-DOS `FAT' file system (FAT12, FAT16, FAT32) + udf Universal Disk Format file system + v7fs 7th edition(V7) file system + +Support for the following file systems maybe be added in the future + + ext2fs Linux EXT2 file system + +Various file system independent parameters and contraints can be +specified, such as: + + - minimum file system size (in KB) + - maximum file system size (in KB) + - free inodes + - free blocks (in KB) + - mtree(8) specification file containing permissions and ownership + to use in image, overridding the settings in the directory tree + - file containing list of files to specifically exclude or include + - fnmatch(3) pattern of filenames to exclude or include + - endianness of target file system + +File system specific parameters can be given as well, with a command +line option such as "-o fsspeccific-options,comma-separated". +For example, ffs would allow tuning of: + + - block & fragment size + - cylinder groups + - number of blocks per inode + - minimum free space + +Other file systems might have controls on how to "munge" file names to +fit within the constraints of the target file system. + +Exit codes: + 0 all ok + 1 fatal error + 2 some files couldn't be added during image creation + (bad perms, missing file, etc). image will continue + to be made + + +Implementation overview: +------------------------ + +The implementation must allow for easy addition of extra file systems +with minimal changes to the file system independent sections. + +The main program will: + - parse the options, including calling fs-specific routines to + validate fs-specific options + - walk the tree, building up a data structure which represents + the tree to stuff into the image. The structure will + probably be a similar tree to what mtree(8) uses internally; + a linked list of entries per directory with a child pointer + to children of directories. ".." won't be stored in the list; + the fs-specific tree walker should add this if required by the fs. + this builder have the smarts to handle hard links correctly. + - (optionally) Change the permissions in the tree according to + the mtree(8) specfile + - Call an fs-specific routine to build the image based on the + data structures. + +Each fs-specific module should have the following external interfaces: + + prepare_options optional file system specific defaults that need to be + setup before parsing fs-specific options. + + parse_options parse the string for fs-specific options, feeding + errors back to the user as appropriate + + cleanup_options optional file system specific data that need to be + cleaned up when done with this filesystem. + + make_fs take the data structures representing the + directory tree and fs parameters, + validate that the parameters are valid + (e.g, the requested image will be large enough), + create the image, and + populate the image + +prepare_options and cleanup_options are optional and can be NULL. + +NOTE: All file system specific options are referenced via the fs_specific +pointer from the fsinfo_t strucutre. It is up to the filesystem to allocate +and free any data needed for this via the prepare and cleanup callbacks. + +Each fs-specific module will need to add its routines to the dispatch array +in makefs.c and add prototypes for these to makefs.h + +All other implementation details should not need to change any of the +generic code. + +ffs implementation +------------------ + +In the ffs case, we can leverage off sbin/newfs/mkfs.c to actually build +the image. When building and populating the image, the implementation +can be greatly simplified if some assumptions are made: + - the total required size (in blocks and inodes) is determined + as part of the validation phase + - a "file" (including a directory) has a known size, so + support for growing a file is not necessary + +Two underlying primitives are provided: + make_inode create an inode, returning the inode number + + write_file write file (from memory if DIR, file descriptor + if FILE or SYMLINK), referencing given inode. + it is smart enough to know if a short symlink + can be stuffed into the inode, etc. + +When creating a directory, the directory entries in the previously +built tree data structure is scanned and built in memory so it can +be written entirely as a single write_file() operation. diff --git a/vendor/bdj-sdk/host/src/makefs_termux/TODO b/vendor/bdj-sdk/host/src/makefs_termux/TODO new file mode 100644 index 0000000..dfd306a --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/TODO @@ -0,0 +1,41 @@ +$NetBSD: TODO,v 1.7 2007/12/10 23:54:35 dyoung Exp $ + +todo +---- + +- read files from multiple directories with or without root + specification, e.g., makefs -t cd9660 output.iso dir1 root2=dir2 + dir3 root4=dir4 + +- display block numbers for a given file (e.g, /boot) + +- finish makefs.8 + +- testing + +- even more testing + +- add support for converting a tar file (instead of a directory tree); + suggested by kpneal@pobox.com + + +outstanding bugs +---------------- + +- size estimation is still out (need to take into account indirect blocks!) + +- parameter checking when density is rather high or low. + +- filling up a file system (running out of inodes or whatever) + doesn't do the right thing. + + +discuss +------- + +- consider replacing ffs_balloc() et al with own code that doesn't + need hacked-up buf.c code + +- whacking on newfs/mkfs.c to allow .PATH-ing directly into makefs(8). + this would involve passing all of mkfs()'s parameters in a single + struct rather than a lot of global vars, etc. diff --git a/vendor/bdj-sdk/host/src/makefs_termux/cd9660.c b/vendor/bdj-sdk/host/src/makefs_termux/cd9660.c new file mode 100644 index 0000000..b2499d9 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/cd9660.c @@ -0,0 +1,2149 @@ +/* $NetBSD: cd9660.c,v 1.49 2015/06/17 01:05:41 christos Exp $ */ + +/* + * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan + * Perez-Rathke and Ram Vedam. All rights reserved. + * + * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys, + * Alan Perez-Rathke and Ram Vedam. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 DANIEL WATT, WALTER DEIGNAN, RYAN + * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``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 DANIEL WATT, WALTER DEIGNAN, RYAN + * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM 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. + */ +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Luke Mewburn for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#else +#include +#endif + +#include +#if defined(__RCSID) && !defined(__lint) +__RCSID("$NetBSD: cd9660.c,v 1.49 2015/06/17 01:05:41 christos Exp $"); +#endif /* !__lint */ + +#include +#include +#include +#include +#include + +#include "makefs.h" +#include "cd9660.h" +#include "cd9660/iso9660_rrip.h" +#include "cd9660/cd9660_archimedes.h" + +/* + * Global variables + */ + +static void cd9660_finalize_PVD(iso9660_disk *); +static cd9660node *cd9660_allocate_cd9660node(void); +static void cd9660_set_defaults(iso9660_disk *); +static int cd9660_arguments_set_string(const char *, const char *, int, + char, char *); +static void cd9660_populate_iso_dir_record( + struct _iso_directory_record_cd9660 *, u_char, u_char, u_char, + const char *); +static void cd9660_setup_root_node(iso9660_disk *); +static int cd9660_setup_volume_descriptors(iso9660_disk *); +#if 0 +static int cd9660_fill_extended_attribute_record(cd9660node *); +#endif +static void cd9660_sort_nodes(cd9660node *); +static int cd9660_translate_node_common(iso9660_disk *, cd9660node *); +static int cd9660_translate_node(iso9660_disk *, fsnode *, cd9660node *); +static int cd9660_compare_filename(const char *, const char *); +static void cd9660_sorted_child_insert(cd9660node *, cd9660node *); +static int cd9660_handle_collisions(iso9660_disk *, cd9660node *, int); +static cd9660node *cd9660_rename_filename(iso9660_disk *, cd9660node *, int, + int); +static void cd9660_copy_filenames(iso9660_disk *, cd9660node *); +static void cd9660_sorting_nodes(cd9660node *); +static int cd9660_count_collisions(cd9660node *); +static cd9660node *cd9660_rrip_move_directory(iso9660_disk *, cd9660node *); +static int cd9660_add_dot_records(iso9660_disk *, cd9660node *); + +static void cd9660_convert_structure(iso9660_disk *, fsnode *, cd9660node *, int, + int *, int *); +static void cd9660_free_structure(cd9660node *); +static int cd9660_generate_path_table(iso9660_disk *); +static int cd9660_level1_convert_filename(iso9660_disk *, const char *, char *, + int); +static int cd9660_level2_convert_filename(iso9660_disk *, const char *, char *, + int); +#if 0 +static int cd9660_joliet_convert_filename(iso9660_disk *, const char *, char *, + int); +#endif +static int cd9660_convert_filename(iso9660_disk *, const char *, char *, int); +static void cd9660_populate_dot_records(iso9660_disk *, cd9660node *); +static int64_t cd9660_compute_offsets(iso9660_disk *, cd9660node *, int64_t); +#if 0 +static int cd9660_copy_stat_info(cd9660node *, cd9660node *, int); +#endif +static cd9660node *cd9660_create_virtual_entry(iso9660_disk *, const char *, + cd9660node *, int, int); +static cd9660node *cd9660_create_file(iso9660_disk *, const char *, + cd9660node *, cd9660node *); +static cd9660node *cd9660_create_directory(iso9660_disk *, const char *, + cd9660node *, cd9660node *); +static cd9660node *cd9660_create_special_directory(iso9660_disk *, u_char, + cd9660node *); +static int cd9660_add_generic_bootimage(iso9660_disk *, const char *); + + +/* + * Allocate and initalize a cd9660node + * @returns struct cd9660node * Pointer to new node, or NULL on error + */ +static cd9660node * +cd9660_allocate_cd9660node(void) +{ + cd9660node *temp = ecalloc(1, sizeof(*temp)); + TAILQ_INIT(&temp->cn_children); + temp->parent = temp->dot_record = temp->dot_dot_record = NULL; + temp->ptnext = temp->ptprev = temp->ptlast = NULL; + temp->node = NULL; + temp->isoDirRecord = NULL; + temp->isoExtAttributes = NULL; + temp->rr_real_parent = temp->rr_relocated = NULL; + temp->su_tail_data = NULL; + return temp; +} + +int cd9660_defaults_set = 0; + +/** +* Set default values for cd9660 extension to makefs +*/ +static void +cd9660_set_defaults(iso9660_disk *diskStructure) +{ + /*Fix the sector size for now, though the spec allows for other sizes*/ + diskStructure->sectorSize = 2048; + + /* Set up defaults in our own structure */ + diskStructure->verbose_level = 0; + diskStructure->keep_bad_images = 0; + diskStructure->follow_sym_links = 0; + diskStructure->isoLevel = 2; + + diskStructure->rock_ridge_enabled = 0; + diskStructure->rock_ridge_renamed_dir_name = 0; + diskStructure->rock_ridge_move_count = 0; + diskStructure->rr_moved_dir = 0; + + diskStructure->archimedes_enabled = 0; + diskStructure->chrp_boot = 0; + + diskStructure->include_padding_areas = 1; + + /* Spec breaking functionality */ + diskStructure->allow_deep_trees = + diskStructure->allow_start_dot = + diskStructure->allow_max_name = + diskStructure->allow_illegal_chars = + diskStructure->allow_lowercase = + diskStructure->allow_multidot = + diskStructure->omit_trailing_period = 0; + + /* Make sure the PVD is clear */ + memset(&diskStructure->primaryDescriptor, 0, 2048); + + memset(diskStructure->primaryDescriptor.publisher_id, 0x20,128); + memset(diskStructure->primaryDescriptor.preparer_id, 0x20,128); + memset(diskStructure->primaryDescriptor.application_id, 0x20,128); + memset(diskStructure->primaryDescriptor.copyright_file_id, 0x20,37); + memset(diskStructure->primaryDescriptor.abstract_file_id, 0x20,37); + memset(diskStructure->primaryDescriptor.bibliographic_file_id, 0x20,37); + + strcpy(diskStructure->primaryDescriptor.system_id,"NetBSD"); + + cd9660_defaults_set = 1; + + /* Boot support: Initially disabled */ + diskStructure->has_generic_bootimage = 0; + diskStructure->generic_bootimage = NULL; + + diskStructure->boot_image_directory = 0; + /*memset(diskStructure->boot_descriptor, 0, 2048);*/ + + diskStructure->is_bootable = 0; + TAILQ_INIT(&diskStructure->boot_images); + LIST_INIT(&diskStructure->boot_entries); +} + +void +cd9660_prep_opts(fsinfo_t *fsopts) +{ + iso9660_disk *diskStructure = ecalloc(1, sizeof(*diskStructure)); + +#define OPT_STR(letter, name, desc) \ + { letter, name, NULL, OPT_STRBUF, 0, 0, desc } + +#define OPT_NUM(letter, name, field, min, max, desc) \ + { letter, name, &diskStructure->field, \ + sizeof(diskStructure->field) == 8 ? OPT_INT64 : \ + (sizeof(diskStructure->field) == 4 ? OPT_INT32 : \ + (sizeof(diskStructure->field) == 2 ? OPT_INT16 : OPT_INT8)), \ + min, max, desc } + +#define OPT_BOOL(letter, name, field, desc) \ + OPT_NUM(letter, name, field, 0, 1, desc) + + const option_t cd9660_options[] = { + OPT_NUM('l', "isolevel", isoLevel, + 1, 3, "ISO Level"), + OPT_NUM('v', "verbose", verbose_level, + 0, 2, "Turns on verbose output"), + + OPT_BOOL('h', "help", displayHelp, + "Show help message"), + OPT_BOOL('S', "follow-symlinks", follow_sym_links, + "Resolve symlinks in pathnames"), + OPT_BOOL('R', "rockridge", rock_ridge_enabled, + "Enable Rock-Ridge extensions"), + OPT_BOOL('C', "chrp-boot", chrp_boot, + "Enable CHRP boot"), + OPT_BOOL('K', "keep-bad-images", keep_bad_images, + "Keep bad images"), + OPT_BOOL('D', "allow-deep-trees", allow_deep_trees, + "Allow trees more than 8 levels"), + OPT_BOOL('a', "allow-max-name", allow_max_name, + "Allow 37 char filenames (unimplemented)"), + OPT_BOOL('i', "allow-illegal-chars", allow_illegal_chars, + "Allow illegal characters in filenames"), + OPT_BOOL('D', "allow-multidot", allow_multidot, + "Allow multiple periods in filenames"), + OPT_BOOL('o', "omit-trailing-period", omit_trailing_period, + "Omit trailing periods in filenames"), + OPT_BOOL('\0', "allow-lowercase", allow_lowercase, + "Allow lowercase characters in filenames"), + OPT_BOOL('\0', "archimedes", archimedes_enabled, + "Enable Archimedes structure"), + OPT_BOOL('\0', "no-trailing-padding", include_padding_areas, + "Include padding areas"), + + OPT_STR('A', "applicationid", "Application Identifier"), + OPT_STR('P', "publisher", "Publisher Identifier"), + OPT_STR('p', "preparer", "Preparer Identifier"), + OPT_STR('L', "label", "Disk Label"), + OPT_STR('V', "volumeid", "Volume Set Identifier"), + OPT_STR('B', "bootimage", "Boot image parameter"), + OPT_STR('G', "generic-bootimage", "Generic boot image param"), + OPT_STR('\0', "bootimagedir", "Boot image directory"), + OPT_STR('\0', "no-emul-boot", "No boot emulation"), + OPT_STR('\0', "no-boot", "No boot support"), + OPT_STR('\0', "hard-disk-boot", "Boot from hard disk"), + OPT_STR('\0', "boot-load-segment", "Boot load segment"), + + { .name = NULL } + }; + + fsopts->fs_specific = diskStructure; + fsopts->fs_options = copy_opts(cd9660_options); + + cd9660_set_defaults(diskStructure); +} + +void +cd9660_cleanup_opts(fsinfo_t *fsopts) +{ + free(fsopts->fs_specific); + free(fsopts->fs_options); +} + +static int +cd9660_arguments_set_string(const char *val, const char *fieldtitle, int length, + char testmode, char * dest) +{ + int len, test; + + if (val == NULL) + warnx("error: The %s requires a string argument", fieldtitle); + else if ((len = strlen(val)) <= length) { + if (testmode == 'd') + test = cd9660_valid_d_chars(val); + else + test = cd9660_valid_a_chars(val); + if (test) { + memcpy(dest, val, len); + if (test == 2) + cd9660_uppercase_characters(dest, len); + return 1; + } else + warnx("error: The %s must be composed of " + "%c-characters", fieldtitle, testmode); + } else + warnx("error: The %s must be at most 32 characters long", + fieldtitle); + return 0; +} + +/* + * Command-line parsing function + */ + +int +cd9660_parse_opts(const char *option, fsinfo_t *fsopts) +{ + int rv, i; + iso9660_disk *diskStructure = fsopts->fs_specific; + option_t *cd9660_options = fsopts->fs_options; + char buf[1024]; + const char *name, *desc; + + assert(option != NULL); + + if (debug & DEBUG_FS_PARSE_OPTS) + printf("%s: got `%s'\n", __func__, option); + + i = set_option(cd9660_options, option, buf, sizeof(buf)); + if (i == -1) + return 0; + + if (cd9660_options[i].name == NULL) + abort(); + + + name = cd9660_options[i].name; + desc = cd9660_options[i].desc; + switch (cd9660_options[i].letter) { + case 'h': + case 'S': + rv = 0; /* this is not handled yet */ + break; + case 'L': + rv = cd9660_arguments_set_string(buf, desc, 32, 'd', + diskStructure->primaryDescriptor.volume_id); + break; + case 'A': + rv = cd9660_arguments_set_string(buf, desc, 128, 'a', + diskStructure->primaryDescriptor.application_id); + break; + case 'P': + rv = cd9660_arguments_set_string(buf, desc, 128, 'a', + diskStructure->primaryDescriptor.publisher_id); + break; + case 'p': + rv = cd9660_arguments_set_string(buf, desc, 128, 'a', + diskStructure->primaryDescriptor.preparer_id); + break; + case 'V': + rv = cd9660_arguments_set_string(buf, desc, 128, 'a', + diskStructure->primaryDescriptor.volume_set_id); + break; + /* Boot options */ + case 'B': + if (buf[0] == '\0') { + warnx("The Boot Image parameter requires a valid boot" + " information string"); + rv = 0; + } else + rv = cd9660_add_boot_disk(diskStructure, buf); + break; + case 'G': + if (buf[0] == '\0') { + warnx("The Generic Boot Image parameter requires a" + " valid boot information string"); + rv = 0; + } else + rv = cd9660_add_generic_bootimage(diskStructure, buf); + break; + default: + if (strcmp(name, "bootimagedir") == 0) { + /* + * XXXfvdl this is unused. + */ + if (buf[0] == '\0') { + warnx("The Boot Image Directory parameter" + " requires a directory name"); + rv = 0; + } else { + diskStructure->boot_image_directory = + emalloc(strlen(buf) + 1); + /* BIG TODO: Add the max length function here */ + rv = cd9660_arguments_set_string(buf, desc, 12, + 'd', diskStructure->boot_image_directory); + } + } else if (strcmp(name, "no-emul-boot") == 0 || + strcmp(name, "no-boot") == 0 || + strcmp(name, "hard-disk-boot") == 0) { + /* RRIP */ + cd9660_eltorito_add_boot_option(diskStructure, name, 0); + rv = 1; + } else if (strcmp(name, "boot-load-segment") == 0) { + if (buf[0] == '\0') { + warnx("Option `%s' doesn't contain a value", + name); + rv = 0; + } else { + cd9660_eltorito_add_boot_option(diskStructure, + name, buf); + rv = 1; + } + } else + rv = 1; + } + return rv; +} + +/* + * Main function for cd9660_makefs + * Builds the ISO image file + * @param const char *image The image filename to create + * @param const char *dir The directory that is being read + * @param struct fsnode *root The root node of the filesystem tree + * @param struct fsinfo_t *fsopts Any options + */ +void +cd9660_makefs(const char *image, const char *dir, fsnode *root, + fsinfo_t *fsopts) +{ + int64_t startoffset; + int numDirectories; + uint64_t pathTableSectors; + int64_t firstAvailableSector; + int64_t totalSpace; + int error; + cd9660node *real_root; + iso9660_disk *diskStructure = fsopts->fs_specific; + + if (diskStructure->verbose_level > 0) + printf("%s: ISO level is %i\n", __func__, + diskStructure->isoLevel); + if (diskStructure->isoLevel < 2 && + diskStructure->allow_multidot) + errx(EXIT_FAILURE, "allow-multidot requires iso level of 2"); + + assert(image != NULL); + assert(dir != NULL); + assert(root != NULL); + + if (diskStructure->displayHelp) { + /* + * Display help here - probably want to put it in + * a separate function + */ + return; + } + + if (diskStructure->verbose_level > 0) + printf("%s: image %s directory %s root %p\n", __func__, + image, dir, root); + + /* Set up some constants. Later, these will be defined with options */ + + /* Counter needed for path tables */ + numDirectories = 0; + + /* Convert tree to our own format */ + /* Actually, we now need to add the REAL root node, at level 0 */ + + real_root = cd9660_allocate_cd9660node(); + real_root->isoDirRecord = emalloc(sizeof(*real_root->isoDirRecord)); + /* Leave filename blank for root */ + memset(real_root->isoDirRecord->name, 0, + ISO_FILENAME_MAXLENGTH_WITH_PADDING); + + real_root->level = 0; + diskStructure->rootNode = real_root; + real_root->type = CD9660_TYPE_DIR; + error = 0; + real_root->node = root; + cd9660_convert_structure(diskStructure, root, real_root, 1, + &numDirectories, &error); + + if (TAILQ_EMPTY(&real_root->cn_children)) { + errx(EXIT_FAILURE, "%s: converted directory is empty. " + "Tree conversion failed", __func__); + } else if (error != 0) { + errx(EXIT_FAILURE, "%s: tree conversion failed", __func__); + } else { + if (diskStructure->verbose_level > 0) + printf("%s: tree converted\n", __func__); + } + + /* Add the dot and dot dot records */ + cd9660_add_dot_records(diskStructure, real_root); + + cd9660_setup_root_node(diskStructure); + + if (diskStructure->verbose_level > 0) + printf("%s: done converting tree\n", __func__); + + /* non-SUSP extensions */ + if (diskStructure->archimedes_enabled) + archimedes_convert_tree(diskStructure->rootNode); + + /* Rock ridge / SUSP init pass */ + if (diskStructure->rock_ridge_enabled) { + cd9660_susp_initialize(diskStructure, diskStructure->rootNode, + diskStructure->rootNode, NULL); + } + + /* Build path table structure */ + diskStructure->pathTableLength = cd9660_generate_path_table( + diskStructure); + + pathTableSectors = CD9660_BLOCKS(diskStructure->sectorSize, + diskStructure->pathTableLength); + + firstAvailableSector = cd9660_setup_volume_descriptors(diskStructure); + if (diskStructure->is_bootable) { + firstAvailableSector = cd9660_setup_boot(diskStructure, + firstAvailableSector); + if (firstAvailableSector < 0) + errx(EXIT_FAILURE, "setup_boot failed"); + } + /* LE first, then BE */ + diskStructure->primaryLittleEndianTableSector = firstAvailableSector; + diskStructure->primaryBigEndianTableSector = + diskStructure->primaryLittleEndianTableSector + pathTableSectors; + + /* Set the secondary ones to -1, not going to use them for now */ + diskStructure->secondaryBigEndianTableSector = -1; + diskStructure->secondaryLittleEndianTableSector = -1; + + diskStructure->dataFirstSector = + diskStructure->primaryBigEndianTableSector + pathTableSectors; + if (diskStructure->verbose_level > 0) + printf("%s: Path table conversion complete. " + "Each table is %i bytes, or %" PRIu64 " sectors.\n", + __func__, + diskStructure->pathTableLength, pathTableSectors); + + startoffset = diskStructure->sectorSize*diskStructure->dataFirstSector; + + totalSpace = cd9660_compute_offsets(diskStructure, real_root, startoffset); + + diskStructure->totalSectors = diskStructure->dataFirstSector + + CD9660_BLOCKS(diskStructure->sectorSize, totalSpace); + + /* Disabled until pass 1 is done */ + if (diskStructure->rock_ridge_enabled) { + diskStructure->susp_continuation_area_start_sector = + diskStructure->totalSectors; + diskStructure->totalSectors += + CD9660_BLOCKS(diskStructure->sectorSize, + diskStructure->susp_continuation_area_size); + cd9660_susp_finalize(diskStructure, diskStructure->rootNode); + } + + + cd9660_finalize_PVD(diskStructure); + + /* Add padding sectors, just for testing purposes right now */ + /* diskStructure->totalSectors+=150; */ + + /* Debugging output */ + if (diskStructure->verbose_level > 0) { + printf("%s: Sectors 0-15 reserved\n", __func__); + printf("%s: Primary path tables starts in sector %" + PRId64 "\n", __func__, + diskStructure->primaryLittleEndianTableSector); + printf("%s: File data starts in sector %" + PRId64 "\n", __func__, diskStructure->dataFirstSector); + printf("%s: Total sectors: %" + PRId64 "\n", __func__, diskStructure->totalSectors); + } + + /* + * Add padding sectors at the end + * TODO: Clean this up and separate padding + */ + if (diskStructure->include_padding_areas) + diskStructure->totalSectors += 150; + + cd9660_write_image(diskStructure, image); + + if (diskStructure->verbose_level > 1) { + debug_print_volume_descriptor_information(diskStructure); + debug_print_tree(diskStructure, real_root, 0); + debug_print_path_tree(real_root); + } + + /* Clean up data structures */ + cd9660_free_structure(real_root); + + if (diskStructure->verbose_level > 0) + printf("%s: done\n", __func__); +} + +/* Generic function pointer - implement later */ +typedef int (*cd9660node_func)(cd9660node *); + +static void +cd9660_finalize_PVD(iso9660_disk *diskStructure) +{ + time_t tim; + + /* root should be a fixed size of 34 bytes since it has no name */ + memcpy(diskStructure->primaryDescriptor.root_directory_record, + diskStructure->rootNode->dot_record->isoDirRecord, 34); + + /* In RRIP, this might be longer than 34 */ + diskStructure->primaryDescriptor.root_directory_record[0] = 34; + + /* Set up all the important numbers in the PVD */ + cd9660_bothendian_dword(diskStructure->totalSectors, + (unsigned char *)diskStructure->primaryDescriptor.volume_space_size); + cd9660_bothendian_word(1, + (unsigned char *)diskStructure->primaryDescriptor.volume_set_size); + cd9660_bothendian_word(1, + (unsigned char *) + diskStructure->primaryDescriptor.volume_sequence_number); + cd9660_bothendian_word(diskStructure->sectorSize, + (unsigned char *) + diskStructure->primaryDescriptor.logical_block_size); + cd9660_bothendian_dword(diskStructure->pathTableLength, + (unsigned char *)diskStructure->primaryDescriptor.path_table_size); + + cd9660_731(diskStructure->primaryLittleEndianTableSector, + (u_char *)diskStructure->primaryDescriptor.type_l_path_table); + cd9660_732(diskStructure->primaryBigEndianTableSector, + (u_char *)diskStructure->primaryDescriptor.type_m_path_table); + + diskStructure->primaryDescriptor.file_structure_version[0] = 1; + + /* Pad all strings with spaces instead of nulls */ + cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_id, 32); + cd9660_pad_string_spaces(diskStructure->primaryDescriptor.system_id, 32); + cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_set_id, + 128); + cd9660_pad_string_spaces(diskStructure->primaryDescriptor.publisher_id, + 128); + cd9660_pad_string_spaces(diskStructure->primaryDescriptor.preparer_id, + 128); + cd9660_pad_string_spaces(diskStructure->primaryDescriptor.application_id, + 128); + cd9660_pad_string_spaces( + diskStructure->primaryDescriptor.copyright_file_id, 37); + cd9660_pad_string_spaces( + diskStructure->primaryDescriptor.abstract_file_id, 37); + cd9660_pad_string_spaces( + diskStructure->primaryDescriptor.bibliographic_file_id, 37); + + /* Setup dates */ + time(&tim); + cd9660_time_8426( + (unsigned char *)diskStructure->primaryDescriptor.creation_date, + tim); + cd9660_time_8426( + (unsigned char *)diskStructure->primaryDescriptor.modification_date, + tim); + + /* + cd9660_set_date(diskStructure->primaryDescriptor.expiration_date, now); + */ + memset(diskStructure->primaryDescriptor.expiration_date, '0' ,16); + diskStructure->primaryDescriptor.expiration_date[16] = 0; + + cd9660_time_8426( + (unsigned char *)diskStructure->primaryDescriptor.effective_date, + tim); +} + +static void +cd9660_populate_iso_dir_record(struct _iso_directory_record_cd9660 *record, + u_char ext_attr_length, u_char flags, + u_char name_len, const char * name) +{ + record->ext_attr_length[0] = ext_attr_length; + record->flags[0] = ISO_FLAG_CLEAR | flags; + record->file_unit_size[0] = 0; + record->interleave[0] = 0; + cd9660_bothendian_word(1, record->volume_sequence_number); + record->name_len[0] = name_len; + memset(record->name, '\0', sizeof (record->name)); + memcpy(record->name, name, name_len); + record->length[0] = 33 + name_len; + + /* Todo : better rounding */ + record->length[0] += (record->length[0] & 1) ? 1 : 0; +} + +static void +cd9660_setup_root_node(iso9660_disk *diskStructure) +{ + cd9660_populate_iso_dir_record(diskStructure->rootNode->isoDirRecord, + 0, ISO_FLAG_DIRECTORY, 1, "\0"); + +} + +/*********** SUPPORT FUNCTIONS ***********/ +static int +cd9660_setup_volume_descriptors(iso9660_disk *diskStructure) +{ + /* Boot volume descriptor should come second */ + int sector = 16; + /* For now, a fixed 2 : PVD and terminator */ + volume_descriptor *temp, *t; + + /* Set up the PVD */ + temp = emalloc(sizeof(*temp)); + temp->volumeDescriptorData = + (unsigned char *)&diskStructure->primaryDescriptor; + temp->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_PVD; + temp->volumeDescriptorData[6] = 1; + temp->sector = sector; + memcpy(temp->volumeDescriptorData + 1, + ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); + diskStructure->firstVolumeDescriptor = temp; + + sector++; + /* Set up boot support if enabled. BVD must reside in sector 17 */ + if (diskStructure->is_bootable) { + t = emalloc(sizeof(*t)); + t->volumeDescriptorData = ecalloc(1, 2048); + temp->next = t; + temp = t; + t->sector = 17; + if (diskStructure->verbose_level > 0) + printf("Setting up boot volume descriptor\n"); + cd9660_setup_boot_volume_descriptor(diskStructure, t); + sector++; + } + + /* Set up the terminator */ + t = emalloc(sizeof(*t)); + t->volumeDescriptorData = ecalloc(1, 2048); + temp->next = t; + t->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_TERMINATOR; + t->next = 0; + t->volumeDescriptorData[6] = 1; + t->sector = sector; + memcpy(t->volumeDescriptorData + 1, + ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); + + sector++; + return sector; +} + +#if 0 +/* + * Populate EAR at some point. Not required, but is used by NetBSD's + * cd9660 support + */ +static int +cd9660_fill_extended_attribute_record(cd9660node *node) +{ + node->isoExtAttributes = emalloc(sizeof(*node->isoExtAttributes)); + return 1; +} +#endif + +static int +cd9660_translate_node_common(iso9660_disk *diskStructure, cd9660node *newnode) +{ + time_t tim; + u_char flag; + char temp[ISO_FILENAME_MAXLENGTH_WITH_PADDING]; + + /* Now populate the isoDirRecord structure */ + memset(temp, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING); + + (void)cd9660_convert_filename(diskStructure, newnode->node->name, + temp, !(S_ISDIR(newnode->node->type))); + + flag = ISO_FLAG_CLEAR; + if (S_ISDIR(newnode->node->type)) + flag |= ISO_FLAG_DIRECTORY; + + cd9660_populate_iso_dir_record(newnode->isoDirRecord, 0, + flag, strlen(temp), temp); + + /* Set the various dates */ + + /* If we want to use the current date and time */ + time(&tim); + + cd9660_time_915(newnode->isoDirRecord->date, tim); + + cd9660_bothendian_dword(newnode->fileDataLength, + newnode->isoDirRecord->size); + /* If the file is a link, we want to set the size to 0 */ + if (S_ISLNK(newnode->node->type)) + newnode->fileDataLength = 0; + + return 1; +} + +/* + * Translate fsnode to cd9660node + * Translate filenames and other metadata, including dates, sizes, + * permissions, etc + * @param struct fsnode * The node generated by makefs + * @param struct cd9660node * The intermediate node to be written to + * @returns int 0 on failure, 1 on success + */ +static int +cd9660_translate_node(iso9660_disk *diskStructure, fsnode *node, + cd9660node *newnode) +{ + if (node == NULL) { + if (diskStructure->verbose_level > 0) + printf("%s: NULL node passed, returning\n", __func__); + return 0; + } + newnode->isoDirRecord = emalloc(sizeof(*newnode->isoDirRecord)); + /* Set the node pointer */ + newnode->node = node; + + /* Set the size */ + if (!(S_ISDIR(node->type))) + newnode->fileDataLength = node->inode->st.st_size; + + if (cd9660_translate_node_common(diskStructure, newnode) == 0) + return 0; + + /* Finally, overwrite some of the values that are set by default */ + cd9660_time_915(newnode->isoDirRecord->date, node->inode->st.st_mtime); + + return 1; +} + +/* + * Compares two ISO filenames + * @param const char * The first file name + * @param const char * The second file name + * @returns : -1 if first is less than second, 0 if they are the same, 1 if + * the second is greater than the first + */ +static int +cd9660_compare_filename(const char *first, const char *second) +{ + /* + * This can be made more optimal once it has been tested + * (the extra character, for example, is for testing) + */ + + int p1 = 0; + int p2 = 0; + char c1, c2; + /* First, on the filename */ + + while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1 + && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1) { + c1 = first[p1]; + c2 = second[p2]; + if (c1 == '.' && c2 =='.') + break; + else if (c1 == '.') { + p2++; + c1 = ' '; + } else if (c2 == '.') { + p1++; + c2 = ' '; + } else { + p1++; + p2++; + } + + if (c1 < c2) + return -1; + else if (c1 > c2) { + return 1; + } + } + + if (first[p1] == '.' && second[p2] == '.') { + p1++; + p2++; + while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1 + && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1) { + c1 = first[p1]; + c2 = second[p2]; + if (c1 == ';' && c2 == ';') + break; + else if (c1 == ';') { + p2++; + c1 = ' '; + } else if (c2 == ';') { + p1++; + c2 = ' '; + } else { + p1++; + p2++; + } + + if (c1 < c2) + return -1; + else if (c1 > c2) + return 1; + } + } + return 0; +} + +/* + * Insert a node into list with ISO sorting rules + * @param cd9660node * The head node of the list + * @param cd9660node * The node to be inserted + */ +static void +cd9660_sorted_child_insert(cd9660node *parent, cd9660node *cn_new) +{ + int compare; + cd9660node *cn; + struct cd9660_children_head *head = &parent->cn_children; + + /* TODO: Optimize? */ + cn_new->parent = parent; + + /* + * first will either be 0, the . or the .. + * if . or .., this means no other entry may be written before first + * if 0, the new node may be inserted at the head + */ + + TAILQ_FOREACH(cn, head, cn_next_child) { + /* + * Dont insert a node twice - + * that would cause an infinite loop + */ + if (cn_new == cn) + return; + + compare = cd9660_compare_filename(cn_new->isoDirRecord->name, + cn->isoDirRecord->name); + + if (compare == 0) + compare = cd9660_compare_filename(cn_new->node->name, + cn->node->name); + + if (compare < 0) + break; + } + if (cn == NULL) + TAILQ_INSERT_TAIL(head, cn_new, cn_next_child); + else + TAILQ_INSERT_BEFORE(cn, cn_new, cn_next_child); +} + +/* + * Called After cd9660_sorted_child_insert + * handles file collisions by suffixing each filname with ~n + * where n represents the files respective place in the ordering + */ +static int +cd9660_handle_collisions(iso9660_disk *diskStructure, cd9660node *colliding, + int past) +{ + cd9660node *iter, *next, *prev; + int skip; + int delete_chars = 0; + int temp_past = past; + int temp_skip; + int flag = 0; + cd9660node *end_of_range; + + for (iter = TAILQ_FIRST(&colliding->cn_children); + iter != NULL && (next = TAILQ_NEXT(iter, cn_next_child)) != NULL;) { + if (strcmp(iter->isoDirRecord->name, + next->isoDirRecord->name) != 0) { + iter = TAILQ_NEXT(iter, cn_next_child); + continue; + } + flag = 1; + temp_skip = skip = cd9660_count_collisions(iter); + end_of_range = iter; + while (temp_skip > 0) { + temp_skip--; + end_of_range = TAILQ_NEXT(end_of_range, cn_next_child); + } + temp_past = past; + while (temp_past > 0) { + if ((next = TAILQ_NEXT(end_of_range, cn_next_child)) != NULL) + end_of_range = next; + else if ((prev = TAILQ_PREV(iter, cd9660_children_head, cn_next_child)) != NULL) + iter = prev; + else + delete_chars++; + temp_past--; + } + skip += past; + iter = cd9660_rename_filename(diskStructure, iter, skip, + delete_chars); + } + return flag; +} + + +static cd9660node * +cd9660_rename_filename(iso9660_disk *diskStructure, cd9660node *iter, int num, + int delete_chars) +{ + int i = 0; + int numbts, dot, semi, digit, digits, temp, powers, multiplier, count; + char *naming; + int maxlength; + char *tmp; + + if (diskStructure->verbose_level > 0) + printf("Rename_filename called\n"); + + /* TODO : A LOT of chanes regarding 8.3 filenames */ + if (diskStructure->isoLevel == 1) + maxlength = 8; + else if (diskStructure->isoLevel == 2) + maxlength = 31; + else + maxlength = ISO_FILENAME_MAXLENGTH_BEFORE_VERSION; + + tmp = emalloc(ISO_FILENAME_MAXLENGTH_WITH_PADDING); + + while (i < num) { + powers = 1; + count = 0; + digits = 1; + multiplier = 1; + while (((int)(i / powers) ) >= 10) { + digits++; + powers = powers * 10; + } + + naming = iter->o_name; + + /* + while ((*naming != '.') && (*naming != ';')) { + naming++; + count++; + } + */ + + dot = -1; + semi = -1; + while (count < maxlength) { + if (*naming == '.') + dot = count; + else if (*naming == ';') { + semi = count; + break; + } + naming++; + count++; + } + + if ((count + digits) < maxlength) + numbts = count; + else + numbts = maxlength - (digits); + numbts -= delete_chars; + + /* 8.3 rules - keep the extension, add before the dot */ + + /* + * This code makes a bunch of assumptions. + * See if you can spot them all :) + */ + +#if 0 + if (diskStructure->isoLevel == 1) { + numbts = 8 - digits - delete_chars; + if (dot < 0) { + + } else { + if (dot < 8) { + memmove(&tmp[numbts],&tmp[dot],4); + } + } + } +#else + __USE(dot); + __USE(semi); + __USE(multiplier); +#endif + + /* (copying just the filename before the '.' */ + memcpy(tmp, (iter->o_name), numbts); + + /* adding the appropriate number following the name */ + temp = i; + while (digits > 0) { + digit = (int)(temp / powers); + temp = temp - digit * powers; + sprintf(&tmp[numbts] , "%d", digit); + digits--; + numbts++; + powers = powers / 10; + } + + while ((*naming != ';') && (numbts < maxlength)) { + tmp[numbts] = (*naming); + naming++; + numbts++; + } + + tmp[numbts] = ';'; + tmp[numbts+1] = '1'; + tmp[numbts+2] = '\0'; + + /* + * now tmp has exactly the identifier + * we want so we'll copy it back to record + */ + memcpy((iter->isoDirRecord->name), tmp, numbts + 3); + + iter = TAILQ_NEXT(iter, cn_next_child); + i++; + } + + free(tmp); + return iter; +} + +/* Todo: Figure out why these functions are nec. */ +static void +cd9660_copy_filenames(iso9660_disk *diskStructure, cd9660node *node) +{ + cd9660node *cn; + + if (TAILQ_EMPTY(&node->cn_children)) + return; + + if (TAILQ_FIRST(&node->cn_children)->isoDirRecord == NULL) { + debug_print_tree(diskStructure, diskStructure->rootNode, 0); + exit(1); + } + + TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) { + cd9660_copy_filenames(diskStructure, cn); + memcpy(cn->o_name, cn->isoDirRecord->name, + ISO_FILENAME_MAXLENGTH_WITH_PADDING); + } +} + +static void +cd9660_sorting_nodes(cd9660node *node) +{ + cd9660node *cn; + + TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) + cd9660_sorting_nodes(cn); + cd9660_sort_nodes(node); +} + +/* XXX Bubble sort. */ +static void +cd9660_sort_nodes(cd9660node *node) +{ + cd9660node *cn, *next; + + do { + TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) { + if ((next = TAILQ_NEXT(cn, cn_next_child)) == NULL) + return; + else if (strcmp(next->isoDirRecord->name, + cn->isoDirRecord->name) >= 0) + continue; + TAILQ_REMOVE(&node->cn_children, next, cn_next_child); + TAILQ_INSERT_BEFORE(cn, next, cn_next_child); + break; + } + } while (cn != NULL); +} + +static int +cd9660_count_collisions(cd9660node *copy) +{ + int count = 0; + cd9660node *iter, *next; + + for (iter = copy; + (next = TAILQ_NEXT(iter, cn_next_child)) != NULL; + iter = next) { + if (cd9660_compare_filename(iter->isoDirRecord->name, + next->isoDirRecord->name) == 0) + count++; + else + return count; + } +#if 0 + if ((next = TAILQ_NEXT(iter, cn_next_child)) != NULL) { + printf("%s: count is %i \n", __func__, count); + compare = cd9660_compare_filename(iter->isoDirRecord->name, + next->isoDirRecord->name); + if (compare == 0) { + count++; + return cd9660_recurse_on_collision(next, count); + } else + return count; + } +#endif + return count; +} + +static cd9660node * +cd9660_rrip_move_directory(iso9660_disk *diskStructure, cd9660node *dir) +{ + char newname[9]; + cd9660node *tfile; + + /* + * This function needs to: + * 1) Create an empty virtual file in place of the old directory + * 2) Point the virtual file to the new directory + * 3) Point the relocated directory to its old parent + * 4) Move the directory specified by dir into rr_moved_dir, + * and rename it to "diskStructure->rock_ridge_move_count" (as a string) + */ + + /* First see if the moved directory even exists */ + if (diskStructure->rr_moved_dir == NULL) { + diskStructure->rr_moved_dir = cd9660_create_directory( + diskStructure, ISO_RRIP_DEFAULT_MOVE_DIR_NAME, + diskStructure->rootNode, dir); + if (diskStructure->rr_moved_dir == NULL) + return 0; + } + + /* Create a file with the same ORIGINAL name */ + tfile = cd9660_create_file(diskStructure, dir->node->name, dir->parent, + dir); + if (tfile == NULL) + return NULL; + + diskStructure->rock_ridge_move_count++; + snprintf(newname, sizeof(newname), "%08i", + diskStructure->rock_ridge_move_count); + + /* Point to old parent */ + dir->rr_real_parent = dir->parent; + + /* Place the placeholder file */ + if (TAILQ_EMPTY(&dir->rr_real_parent->cn_children)) { + TAILQ_INSERT_HEAD(&dir->rr_real_parent->cn_children, tfile, + cn_next_child); + } else { + cd9660_sorted_child_insert(dir->rr_real_parent, tfile); + } + + /* Point to new parent */ + dir->parent = diskStructure->rr_moved_dir; + + /* Point the file to the moved directory */ + tfile->rr_relocated = dir; + + /* Actually move the directory */ + cd9660_sorted_child_insert(diskStructure->rr_moved_dir, dir); + + /* TODO: Inherit permissions / ownership (basically the entire inode) */ + + /* Set the new name */ + memset(dir->isoDirRecord->name, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING); + strncpy(dir->isoDirRecord->name, newname, 8); + dir->isoDirRecord->length[0] = 34 + 8; + dir->isoDirRecord->name_len[0] = 8; + + return dir; +} + +static int +cd9660_add_dot_records(iso9660_disk *diskStructure, cd9660node *root) +{ + struct cd9660_children_head *head = &root->cn_children; + cd9660node *cn; + + TAILQ_FOREACH(cn, head, cn_next_child) { + if ((cn->type & CD9660_TYPE_DIR) == 0) + continue; + /* Recursion first */ + cd9660_add_dot_records(diskStructure, cn); + } + cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOT, root); + cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOTDOT, + root); + return 1; +} + +/* + * Convert node to cd9660 structure + * This function is designed to be called recursively on the root node of + * the filesystem + * Lots of recursion going on here, want to make sure it is efficient + * @param struct fsnode * The root node to be converted + * @param struct cd9660* The parent node (should not be NULL) + * @param int Current directory depth + * @param int* Running count of the number of directories that are being created + */ +static void +cd9660_convert_structure(iso9660_disk *diskStructure, fsnode *root, + cd9660node *parent_node, int level, int *numDirectories, int *error) +{ + fsnode *iterator = root; + cd9660node *this_node; + int working_level; + int add; + int flag = 0; + int counter = 0; + + /* + * Newer, more efficient method, reduces recursion depth + */ + if (root == NULL) { + warnx("%s: root is null", __func__); + return; + } + + /* Test for an empty directory - makefs still gives us the . record */ + if ((S_ISDIR(root->type)) && (root->name[0] == '.') + && (root->name[1] == '\0')) { + root = root->next; + if (root == NULL) + return; + } + if ((this_node = cd9660_allocate_cd9660node()) == NULL) { + CD9660_MEM_ALLOC_ERROR(__func__); + } + + /* + * To reduce the number of recursive calls, we will iterate over + * the next pointers to the right. + */ + while (iterator != NULL) { + add = 1; + /* + * Increment the directory count if this is a directory + * Ignore "." entries. We will generate them later + */ + if (!S_ISDIR(iterator->type) || + strcmp(iterator->name, ".") != 0) { + + /* Translate the node, including its filename */ + this_node->parent = parent_node; + cd9660_translate_node(diskStructure, iterator, + this_node); + this_node->level = level; + + if (S_ISDIR(iterator->type)) { + (*numDirectories)++; + this_node->type = CD9660_TYPE_DIR; + working_level = level + 1; + + /* + * If at level 8, directory would be at 8 + * and have children at 9 which is not + * allowed as per ISO spec + */ + if (level == 8) { + if ((!diskStructure->allow_deep_trees) && + (!diskStructure->rock_ridge_enabled)) { + warnx("error: found entry " + "with depth greater " + "than 8."); + (*error) = 1; + return; + } else if (diskStructure-> + rock_ridge_enabled) { + working_level = 3; + /* + * Moved directory is actually + * at level 2. + */ + this_node->level = + working_level - 1; + if (cd9660_rrip_move_directory( + diskStructure, + this_node) == 0) { + warnx("Failure in " + "cd9660_rrip_" + "move_directory" + ); + (*error) = 1; + return; + } + add = 0; + } + } + + /* Do the recursive call on the children */ + if (iterator->child != 0) { + cd9660_convert_structure(diskStructure, + iterator->child, this_node, + working_level, + numDirectories, error); + + if ((*error) == 1) { + warnx("%s: Error on recursive " + "call", __func__); + return; + } + } + + } else { + /* Only directories should have children */ + assert(iterator->child == NULL); + + this_node->type = CD9660_TYPE_FILE; + } + + /* + * Finally, do a sorted insert + */ + if (add) { + cd9660_sorted_child_insert( + parent_node, this_node); + } + + /*Allocate new temp_node */ + if (iterator->next != 0) { + this_node = cd9660_allocate_cd9660node(); + if (this_node == NULL) + CD9660_MEM_ALLOC_ERROR(__func__); + } + } + iterator = iterator->next; + } + + /* cd9660_handle_collisions(first_node); */ + + /* TODO: need cleanup */ + cd9660_copy_filenames(diskStructure, parent_node); + + do { + flag = cd9660_handle_collisions(diskStructure, parent_node, + counter); + counter++; + cd9660_sorting_nodes(parent_node); + } while ((flag == 1) && (counter < 100)); +} + +/* + * Clean up the cd9660node tree + * This is designed to be called recursively on the root node + * @param struct cd9660node *root The node to free + * @returns void + */ +static void +cd9660_free_structure(cd9660node *root) +{ + cd9660node *cn; + + while ((cn = TAILQ_FIRST(&root->cn_children)) != NULL) { + TAILQ_REMOVE(&root->cn_children, cn, cn_next_child); + cd9660_free_structure(cn); + } + free(root); +} + +/* + * Be a little more memory conservative: + * instead of having the TAILQ_ENTRY as part of the cd9660node, + * just create a temporary structure + */ +struct ptq_entry +{ + TAILQ_ENTRY(ptq_entry) ptq; + cd9660node *node; +} *n; + +#define PTQUEUE_NEW(n,s,r,t){\ + n = emalloc(sizeof(struct s)); \ + if (n == NULL) \ + return r; \ + n->node = t;\ +} + +/* + * Generate the path tables + * The specific implementation of this function is left as an exercise to the + * programmer. It could be done recursively. Make sure you read how the path + * table has to be laid out, it has levels. + * @param struct iso9660_disk *disk The disk image + * @returns int The number of built path tables (between 1 and 4), 0 on failure + */ +static int +cd9660_generate_path_table(iso9660_disk *diskStructure) +{ + cd9660node *cn, *dirNode = diskStructure->rootNode; + cd9660node *last = dirNode; + int pathTableSize = 0; /* computed as we go */ + int counter = 1; /* root gets a count of 0 */ + + TAILQ_HEAD(cd9660_pt_head, ptq_entry) pt_head; + TAILQ_INIT(&pt_head); + + PTQUEUE_NEW(n, ptq_entry, -1, diskStructure->rootNode); + + /* Push the root node */ + TAILQ_INSERT_HEAD(&pt_head, n, ptq); + + /* Breadth-first traversal of file structure */ + while (pt_head.tqh_first != 0) { + n = pt_head.tqh_first; + dirNode = n->node; + TAILQ_REMOVE(&pt_head, pt_head.tqh_first, ptq); + free(n); + + /* Update the size */ + pathTableSize += ISO_PATHTABLE_ENTRY_BASESIZE + + dirNode->isoDirRecord->name_len[0]+ + (dirNode->isoDirRecord->name_len[0] % 2 == 0 ? 0 : 1); + /* includes the padding bit */ + + dirNode->ptnumber=counter; + if (dirNode != last) { + last->ptnext = dirNode; + dirNode->ptprev = last; + } + last = dirNode; + + /* Push children onto queue */ + TAILQ_FOREACH(cn, &dirNode->cn_children, cn_next_child) { + /* + * Dont add the DOT and DOTDOT types to the path + * table. + */ + if ((cn->type != CD9660_TYPE_DOT) + && (cn->type != CD9660_TYPE_DOTDOT)) { + + if (S_ISDIR(cn->node->type)) { + PTQUEUE_NEW(n, ptq_entry, -1, cn); + TAILQ_INSERT_TAIL(&pt_head, n, ptq); + } + } + } + counter++; + } + return pathTableSize; +} + +void +cd9660_compute_full_filename(cd9660node *node, char *buf) +{ + int len; + + len = CD9660MAXPATH + 1; + len = snprintf(buf, len, "%s/%s/%s", node->node->root, + node->node->path, node->node->name); + if (len > CD9660MAXPATH) + errx(EXIT_FAILURE, "Pathname too long."); +} + +/* NEW filename conversion method */ +typedef int(*cd9660_filename_conversion_functor)(iso9660_disk *, const char *, + char *, int); + + +/* + * TODO: These two functions are almost identical. + * Some code cleanup is possible here + * + * XXX bounds checking! + */ +static int +cd9660_level1_convert_filename(iso9660_disk *diskStructure, const char *oldname, + char *newname, int is_file) +{ + /* + * ISO 9660 : 10.1 + * File Name shall not contain more than 8 d or d1 characters + * File Name Extension shall not contain more than 3 d or d1 characters + * Directory Identifier shall not contain more than 8 d or d1 characters + */ + int namelen = 0; + int extlen = 0; + int found_ext = 0; + + while (*oldname != '\0' && extlen < 3) { + /* Handle period first, as it is special */ + if (*oldname == '.') { + if (found_ext) { + *newname++ = '_'; + extlen ++; + } + else { + *newname++ = '.'; + found_ext = 1; + } + } else { + /* cut RISC OS file type off ISO name */ + if (diskStructure->archimedes_enabled && + *oldname == ',' && strlen(oldname) == 4) + break; + + /* Enforce 12.3 / 8 */ + if (namelen == 8 && !found_ext) + break; + + if (islower((unsigned char)*oldname)) + *newname++ = toupper((unsigned char)*oldname); + else if (isupper((unsigned char)*oldname) + || isdigit((unsigned char)*oldname)) + *newname++ = *oldname; + else + *newname++ = '_'; + + if (found_ext) + extlen++; + else + namelen++; + } + oldname++; + } + if (is_file) { + if (!found_ext && !diskStructure->omit_trailing_period) + *newname++ = '.'; + /* Add version */ + sprintf(newname, ";%i", 1); + } + return namelen + extlen + found_ext; +} + +/* XXX bounds checking! */ +static int +cd9660_level2_convert_filename(iso9660_disk *diskStructure, const char *oldname, + char *newname, int is_file) +{ + /* + * ISO 9660 : 7.5.1 + * File name : 0+ d or d1 characters + * separator 1 (.) + * File name extension : 0+ d or d1 characters + * separator 2 (;) + * File version number (5 characters, 1-32767) + * 1 <= Sum of File name and File name extension <= 30 + */ + int namelen = 0; + int extlen = 0; + int found_ext = 0; + + while (*oldname != '\0' && namelen + extlen < 30) { + /* Handle period first, as it is special */ + if (*oldname == '.') { + if (found_ext) { + if (diskStructure->allow_multidot) { + *newname++ = '.'; + } else { + *newname++ = '_'; + } + extlen ++; + } + else { + *newname++ = '.'; + found_ext = 1; + } + } else { + /* cut RISC OS file type off ISO name */ + if (diskStructure->archimedes_enabled && + *oldname == ',' && strlen(oldname) == 4) + break; + + if (islower((unsigned char)*oldname)) + *newname++ = toupper((unsigned char)*oldname); + else if (isupper((unsigned char)*oldname) || + isdigit((unsigned char)*oldname)) + *newname++ = *oldname; + else if (diskStructure->allow_multidot && + *oldname == '.') { + *newname++ = '.'; + } else { + *newname++ = '_'; + } + + if (found_ext) + extlen++; + else + namelen++; + } + oldname ++; + } + if (is_file) { + if (!found_ext && !diskStructure->omit_trailing_period) + *newname++ = '.'; + /* Add version */ + sprintf(newname, ";%i", 1); + } + return namelen + extlen + found_ext; +} + +#if 0 +static int +cd9660_joliet_convert_filename(iso9660_disk *diskStructure, const char *oldname, + char *newname, int is_file) +{ + /* TODO: implement later, move to cd9660_joliet.c ?? */ +} +#endif + + +/* + * Convert a file name to ISO compliant file name + * @param char * oldname The original filename + * @param char ** newname The new file name, in the appropriate character + * set and of appropriate length + * @param int 1 if file, 0 if directory + * @returns int The length of the new string + */ +static int +cd9660_convert_filename(iso9660_disk *diskStructure, const char *oldname, + char *newname, int is_file) +{ + /* NEW */ + cd9660_filename_conversion_functor conversion_function = 0; + if (diskStructure->isoLevel == 1) + conversion_function = &cd9660_level1_convert_filename; + else if (diskStructure->isoLevel == 2) + conversion_function = &cd9660_level2_convert_filename; + return (*conversion_function)(diskStructure, oldname, newname, is_file); +} + +int +cd9660_compute_record_size(iso9660_disk *diskStructure, cd9660node *node) +{ + int size = node->isoDirRecord->length[0]; + + if (diskStructure->rock_ridge_enabled) + size += node->susp_entry_size; + size += node->su_tail_size; + size += size & 1; /* Ensure length of record is even. */ + assert(size <= 254); + return size; +} + +static void +cd9660_populate_dot_records(iso9660_disk *diskStructure, cd9660node *node) +{ + node->dot_record->fileDataSector = node->fileDataSector; + memcpy(node->dot_record->isoDirRecord,node->isoDirRecord, 34); + node->dot_record->isoDirRecord->name_len[0] = 1; + node->dot_record->isoDirRecord->name[0] = 0; + node->dot_record->isoDirRecord->name[1] = 0; + node->dot_record->isoDirRecord->length[0] = 34; + node->dot_record->fileRecordSize = + cd9660_compute_record_size(diskStructure, node->dot_record); + + if (node == diskStructure->rootNode) { + node->dot_dot_record->fileDataSector = node->fileDataSector; + memcpy(node->dot_dot_record->isoDirRecord,node->isoDirRecord, + 34); + } else { + node->dot_dot_record->fileDataSector = + node->parent->fileDataSector; + memcpy(node->dot_dot_record->isoDirRecord, + node->parent->isoDirRecord,34); + } + node->dot_dot_record->isoDirRecord->name_len[0] = 1; + node->dot_dot_record->isoDirRecord->name[0] = 1; + node->dot_dot_record->isoDirRecord->name[1] = 0; + node->dot_dot_record->isoDirRecord->length[0] = 34; + node->dot_dot_record->fileRecordSize = + cd9660_compute_record_size(diskStructure, node->dot_dot_record); +} + +/* + * @param struct cd9660node *node The node + * @param int The offset (in bytes) - SHOULD align to the beginning of a sector + * @returns int The total size of files and directory entries (should be + * a multiple of sector size) +*/ +static int64_t +cd9660_compute_offsets(iso9660_disk *diskStructure, cd9660node *node, + int64_t startOffset) +{ + /* + * This function needs to compute the size of directory records and + * runs, file lengths, and set the appropriate variables both in + * cd9660node and isoDirEntry + */ + int64_t used_bytes = 0; + int64_t current_sector_usage = 0; + cd9660node *child; + fsinode *inode; + int64_t r; + + assert(node != NULL); + + + /* + * NOTE : There needs to be some special case detection for + * the "real root" node, since for it, node->node is undefined + */ + + node->fileDataSector = -1; + + if (node->type & CD9660_TYPE_DIR) { + node->fileRecordSize = cd9660_compute_record_size( + diskStructure, node); + /*Set what sector this directory starts in*/ + node->fileDataSector = + CD9660_BLOCKS(diskStructure->sectorSize,startOffset); + + cd9660_bothendian_dword(node->fileDataSector, + node->isoDirRecord->extent); + + /* + * First loop over children, need to know the size of + * their directory records + */ + node->fileSectorsUsed = 1; + TAILQ_FOREACH(child, &node->cn_children, cn_next_child) { + node->fileDataLength += + cd9660_compute_record_size(diskStructure, child); + if ((cd9660_compute_record_size(diskStructure, child) + + current_sector_usage) >= + diskStructure->sectorSize) { + current_sector_usage = 0; + node->fileSectorsUsed++; + } + + current_sector_usage += + cd9660_compute_record_size(diskStructure, child); + } + + cd9660_bothendian_dword(node->fileSectorsUsed * + diskStructure->sectorSize,node->isoDirRecord->size); + + /* + * This should point to the sector after the directory + * record (or, the first byte in that sector) + */ + used_bytes += node->fileSectorsUsed * diskStructure->sectorSize; + + for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child); + child != NULL; child = TAILQ_NEXT(child, cn_next_child)) { + /* Directories need recursive call */ + if (S_ISDIR(child->node->type)) { + r = cd9660_compute_offsets(diskStructure, child, + used_bytes + startOffset); + + if (r != -1) + used_bytes += r; + else + return -1; + } + } + + /* Explicitly set the . and .. records */ + cd9660_populate_dot_records(diskStructure, node); + + /* Finally, do another iteration to write the file data*/ + for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child); + child != NULL; + child = TAILQ_NEXT(child, cn_next_child)) { + /* Files need extent set */ + if (S_ISDIR(child->node->type)) + continue; + child->fileRecordSize = + cd9660_compute_record_size(diskStructure, child); + + child->fileSectorsUsed = + CD9660_BLOCKS(diskStructure->sectorSize, + child->fileDataLength); + + inode = child->node->inode; + if ((inode->flags & FI_ALLOCATED) == 0) { + inode->ino = + CD9660_BLOCKS(diskStructure->sectorSize, + used_bytes + startOffset); + inode->flags |= FI_ALLOCATED; + used_bytes += child->fileSectorsUsed * + diskStructure->sectorSize; + } else { + INODE_WARNX(("%s: already allocated inode %d " + "data sectors at %" PRIu32, __func__, + (int)inode->st.st_ino, inode->ino)); + } + child->fileDataSector = inode->ino; + cd9660_bothendian_dword(child->fileDataSector, + child->isoDirRecord->extent); + } + } + + return used_bytes; +} + +#if 0 +/* Might get rid of this func */ +static int +cd9660_copy_stat_info(cd9660node *from, cd9660node *to, int file) +{ + to->node->inode->st.st_dev = 0; + to->node->inode->st.st_ino = 0; + to->node->inode->st.st_size = 0; + to->node->inode->st.st_blksize = from->node->inode->st.st_blksize; + to->node->inode->st.st_atime = from->node->inode->st.st_atime; + to->node->inode->st.st_mtime = from->node->inode->st.st_mtime; + to->node->inode->st.st_ctime = from->node->inode->st.st_ctime; + to->node->inode->st.st_uid = from->node->inode->st.st_uid; + to->node->inode->st.st_gid = from->node->inode->st.st_gid; + to->node->inode->st.st_mode = from->node->inode->st.st_mode; + /* Clear out type */ + to->node->inode->st.st_mode = to->node->inode->st.st_mode & ~(S_IFMT); + if (file) + to->node->inode->st.st_mode |= S_IFREG; + else + to->node->inode->st.st_mode |= S_IFDIR; + return 1; +} +#endif + +static cd9660node * +cd9660_create_virtual_entry(iso9660_disk *diskStructure, const char *name, + cd9660node *parent, int file, int insert) +{ + cd9660node *temp; + fsnode * tfsnode; + + assert(parent != NULL); + + temp = cd9660_allocate_cd9660node(); + if (temp == NULL) + return NULL; + + tfsnode = emalloc(sizeof(*tfsnode)); + tfsnode->name = estrdup(name); + temp->isoDirRecord = emalloc(sizeof(*temp->isoDirRecord)); + + cd9660_convert_filename(diskStructure, tfsnode->name, + temp->isoDirRecord->name, file); + + temp->node = tfsnode; + temp->parent = parent; + + if (insert) { + if (temp->parent != NULL) { + temp->level = temp->parent->level + 1; + if (!TAILQ_EMPTY(&temp->parent->cn_children)) + cd9660_sorted_child_insert(temp->parent, temp); + else + TAILQ_INSERT_HEAD(&temp->parent->cn_children, + temp, cn_next_child); + } + } + + if (parent->node != NULL) { + tfsnode->type = parent->node->type; + } + + /* Clear out file type bits */ + tfsnode->type &= ~(S_IFMT); + if (file) + tfsnode->type |= S_IFREG; + else + tfsnode->type |= S_IFDIR; + + /* Indicate that there is no spec entry (inode) */ + tfsnode->flags &= ~(FSNODE_F_HASSPEC); +#if 0 + cd9660_copy_stat_info(parent, temp, file); +#endif + return temp; +} + +static cd9660node * +cd9660_create_file(iso9660_disk *diskStructure, const char *name, + cd9660node *parent, cd9660node *me) +{ + cd9660node *temp; + + temp = cd9660_create_virtual_entry(diskStructure, name, parent, 1, 1); + if (temp == NULL) + return NULL; + + temp->fileDataLength = 0; + + temp->type = CD9660_TYPE_FILE | CD9660_TYPE_VIRTUAL; + + temp->node->inode = ecalloc(1, sizeof(*temp->node->inode)); + *temp->node->inode = *me->node->inode; + + if (cd9660_translate_node_common(diskStructure, temp) == 0) + return NULL; + return temp; +} + +/* + * Create a new directory which does not exist on disk + * @param const char * name The name to assign to the directory + * @param const char * parent Pointer to the parent directory + * @returns cd9660node * Pointer to the new directory + */ +static cd9660node * +cd9660_create_directory(iso9660_disk *diskStructure, const char *name, + cd9660node *parent, cd9660node *me) +{ + cd9660node *temp; + + temp = cd9660_create_virtual_entry(diskStructure, name, parent, 0, 1); + if (temp == NULL) + return NULL; + temp->node->type |= S_IFDIR; + + temp->type = CD9660_TYPE_DIR | CD9660_TYPE_VIRTUAL; + + temp->node->inode = ecalloc(1, sizeof(*temp->node->inode)); + *temp->node->inode = *me->node->inode; + + if (cd9660_translate_node_common(diskStructure, temp) == 0) + return NULL; + return temp; +} + +static cd9660node * +cd9660_create_special_directory(iso9660_disk *diskStructure, u_char type, + cd9660node *parent) +{ + cd9660node *temp, *first; + char na[2]; + + assert(parent != NULL); + + if (type == CD9660_TYPE_DOT) + na[0] = 0; + else if (type == CD9660_TYPE_DOTDOT) + na[0] = 1; + else + return 0; + + na[1] = 0; + if ((temp = cd9660_create_virtual_entry(diskStructure, na, parent, + 0, 0)) == NULL) + return NULL; + + temp->parent = parent; + temp->type = type; + temp->isoDirRecord->length[0] = 34; + /* Dot record is always first */ + if (type == CD9660_TYPE_DOT) { + parent->dot_record = temp; + TAILQ_INSERT_HEAD(&parent->cn_children, temp, cn_next_child); + /* DotDot should be second */ + } else if (type == CD9660_TYPE_DOTDOT) { + parent->dot_dot_record = temp; + /* + * If the first child is the dot record, insert + * this second. Otherwise, insert it at the head. + */ + if ((first = TAILQ_FIRST(&parent->cn_children)) == NULL || + (first->type & CD9660_TYPE_DOT) == 0) { + TAILQ_INSERT_HEAD(&parent->cn_children, temp, + cn_next_child); + } else { + TAILQ_INSERT_AFTER(&parent->cn_children, first, temp, + cn_next_child); + } + } + + return temp; +} + +static int +cd9660_add_generic_bootimage(iso9660_disk *diskStructure, const char *bootimage) +{ + struct stat stbuf; + + assert(bootimage != NULL); + + if (*bootimage == '\0') { + warnx("Error: Boot image must be a filename"); + return 0; + } + + diskStructure->generic_bootimage = estrdup(bootimage); + + /* Get information about the file */ + if (lstat(diskStructure->generic_bootimage, &stbuf) == -1) + err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__, + diskStructure->generic_bootimage); + + if (stbuf.st_size > 32768) { + warnx("Error: Boot image must be no greater than 32768 bytes"); + return 0; + } + + if (diskStructure->verbose_level > 0) { + printf("Generic boot image image has size %lld\n", + (long long)stbuf.st_size); + } + + diskStructure->has_generic_bootimage = 1; + + return 1; +} diff --git a/vendor/bdj-sdk/host/src/makefs_termux/cd9660.h b/vendor/bdj-sdk/host/src/makefs_termux/cd9660.h new file mode 100644 index 0000000..ef9f44f --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/cd9660.h @@ -0,0 +1,357 @@ +/* $NetBSD: cd9660.h,v 1.20 2013/01/29 15:52:25 christos Exp $ */ + +/* + * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan + * Perez-Rathke and Ram Vedam. All rights reserved. + * + * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys, + * Alan Perez-Rathke and Ram Vedam. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 DANIEL WATT, WALTER DEIGNAN, RYAN + * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``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 DANIEL WATT, WALTER DEIGNAN, RYAN + * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM 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. + */ + +#ifndef _MAKEFS_CD9660_H +#define _MAKEFS_CD9660_H + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "makefs.h" +#include "iso.h" +#include "iso_rrip.h" +#include "cd9660/cd9660_eltorito.h" + +#ifdef DEBUG +#define INODE_WARNX(__x) warnx __x +#else /* DEBUG */ +#define INODE_WARNX(__x) +#endif /* DEBUG */ + +#define CD9660MAXPATH 4096 + +#define ISO_STRING_FILTER_NONE = 0x00 +#define ISO_STRING_FILTER_DCHARS = 0x01 +#define ISO_STRING_FILTER_ACHARS = 0x02 + +/* +Extended preferences type, in the spirit of what makefs gives us (only ints) +*/ +typedef struct { + const char *shortName; /* Short option */ + const char *name; /* option name */ + char *value; /* where to stuff the value */ + int minLength; /* minimum for value */ + int maxLength; /* maximum for value */ + const char *desc; /* option description */ + int filterFlags; +} string_option_t; + +/******** STRUCTURES **********/ + +/*Defaults*/ +#define ISO_DEFAULT_VOLUMEID "MAKEFS_CD9660_IMAGE" +#define ISO_DEFAULT_APPID "MAKEFS" +#define ISO_DEFAULT_PUBLISHER "MAKEFS" +#define ISO_DEFAULT_PREPARER "MAKEFS" + +#define ISO_VOLUME_DESCRIPTOR_STANDARD_ID "CD001" +#define ISO_VOLUME_DESCRIPTOR_BOOT 0 +#define ISO_VOLUME_DESCRIPTOR_PVD 1 +#define ISO_VOLUME_DESCRIPTOR_TERMINATOR 255 + +/*30 for name and extension, as well as version number and padding bit*/ +#define ISO_FILENAME_MAXLENGTH_BEFORE_VERSION 30 +#define ISO_FILENAME_MAXLENGTH 36 +#define ISO_FILENAME_MAXLENGTH_WITH_PADDING 37 + +#define ISO_FLAG_CLEAR 0x00 +#define ISO_FLAG_HIDDEN 0x01 +#define ISO_FLAG_DIRECTORY 0x02 +#define ISO_FLAG_ASSOCIATED 0x04 +#define ISO_FLAG_PERMISSIONS 0x08 +#define ISO_FLAG_RESERVED5 0x10 +#define ISO_FLAG_RESERVED6 0x20 +#define ISO_FLAG_FINAL_RECORD 0x40 + +#define ISO_PATHTABLE_ENTRY_BASESIZE 8 + +#define ISO_RRIP_DEFAULT_MOVE_DIR_NAME "RR_MOVED" +#define RRIP_DEFAULT_MOVE_DIR_NAME ".rr_moved" + +#define CD9660_BLOCKS(__sector_size, __bytes) \ + howmany((__bytes), (__sector_size)) + +#define CD9660_MEM_ALLOC_ERROR(_F) \ + err(EXIT_FAILURE, "%s, %s l. %d", _F, __FILE__, __LINE__) + +#define CD9660_TYPE_FILE 0x01 +#define CD9660_TYPE_DIR 0x02 +#define CD9660_TYPE_DOT 0x04 +#define CD9660_TYPE_DOTDOT 0x08 +#define CD9660_TYPE_VIRTUAL 0x80 + +#define CD9660_INODE_HASH_SIZE 1024 +#define CD9660_SECTOR_SIZE 2048 + +#define CD9660_END_PADDING 150 + +/* Slight modification of the ISO structure in iso.h */ +typedef struct _iso_directory_record_cd9660 { + u_char length [ISODCL (1, 1)]; /* 711 */ + u_char ext_attr_length [ISODCL (2, 2)]; /* 711 */ + u_char extent [ISODCL (3, 10)]; /* 733 */ + u_char size [ISODCL (11, 18)]; /* 733 */ + u_char date [ISODCL (19, 25)]; /* 7 by 711 */ + u_char flags [ISODCL (26, 26)]; + u_char file_unit_size [ISODCL (27, 27)]; /* 711 */ + u_char interleave [ISODCL (28, 28)]; /* 711 */ + u_char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ + u_char name_len [ISODCL (33, 33)]; /* 711 */ + char name [ISO_FILENAME_MAXLENGTH_WITH_PADDING]; +} iso_directory_record_cd9660; + +/* TODO: Lots of optimization of this structure */ +typedef struct _cd9660node { + u_char type;/* Used internally */ + /* Tree structure */ + struct _cd9660node *parent; /* parent (NULL if root) */ + TAILQ_HEAD(cd9660_children_head, _cd9660node) cn_children; + TAILQ_ENTRY(_cd9660node) cn_next_child; + + struct _cd9660node *dot_record; /* For directories, used mainly in RRIP */ + struct _cd9660node *dot_dot_record; + + fsnode *node; /* pointer to fsnode */ + struct _iso_directory_record_cd9660 *isoDirRecord; + struct iso_extended_attributes *isoExtAttributes; + + /***** SIZE CALCULATION *****/ + /*already stored in isoDirRecord, but this is an int version, and will be + copied to isoDirRecord on writing*/ + uint32_t fileDataSector; + + /* + * same thing, though some notes: + * If a file, this is the file size + * If a directory, this is the size of all its children's + * directory records + * plus necessary padding + */ + int64_t fileDataLength; + + int64_t fileSectorsUsed; + int fileRecordSize;/*copy of a variable, int for quicker calculations*/ + + /* Old name, used for renaming - needs to be optimized but low priority */ + char o_name [ISO_FILENAME_MAXLENGTH_WITH_PADDING]; + + /***** SPACE RESERVED FOR EXTENSIONS *****/ + /* For memory efficiency's sake - we should move this to a separate struct + and point to null if not needed */ + /* For Rock Ridge */ + struct _cd9660node *rr_real_parent, *rr_relocated; + + int64_t susp_entry_size; + int64_t susp_dot_entry_size; + int64_t susp_dot_dot_entry_size; + + /* Continuation area stuff */ + int64_t susp_entry_ce_start; + int64_t susp_dot_ce_start; + int64_t susp_dot_dot_ce_start; + + int64_t susp_entry_ce_length; + int64_t susp_dot_ce_length; + int64_t susp_dot_dot_ce_length; + + /* Data to put at the end of the System Use field */ + int64_t su_tail_size; + char *su_tail_data; + + /*** PATH TABLE STUFF ***/ + int level; /*depth*/ + int ptnumber; + struct _cd9660node *ptnext, *ptprev, *ptlast; + + /* SUSP entries */ + TAILQ_HEAD(susp_linked_list, ISO_SUSP_ATTRIBUTES) head; +} cd9660node; + +typedef struct _path_table_entry +{ + u_char length[ISODCL (1, 1)]; + u_char extended_attribute_length[ISODCL (2, 2)]; + u_char first_sector[ISODCL (3, 6)]; + u_char parent_number[ISODCL (7, 8)]; + u_char name[ISO_FILENAME_MAXLENGTH_WITH_PADDING]; +} path_table_entry; + +typedef struct _volume_descriptor +{ + u_char *volumeDescriptorData; /*ALWAYS 2048 bytes long*/ + int64_t sector; + struct _volume_descriptor *next; +} volume_descriptor; + +typedef struct _iso9660_disk { + int sectorSize; + struct iso_primary_descriptor primaryDescriptor; + struct iso_supplementary_descriptor supplementaryDescriptor; + + volume_descriptor *firstVolumeDescriptor; + + cd9660node *rootNode; + + /* Important sector numbers here */ + /* primaryDescriptor.type_l_path_table*/ + int64_t primaryBigEndianTableSector; + + /* primaryDescriptor.type_m_path_table*/ + int64_t primaryLittleEndianTableSector; + + /* primaryDescriptor.opt_type_l_path_table*/ + int64_t secondaryBigEndianTableSector; + + /* primaryDescriptor.opt_type_m_path_table*/ + int64_t secondaryLittleEndianTableSector; + + /* primaryDescriptor.path_table_size*/ + int pathTableLength; + int64_t dataFirstSector; + + int64_t totalSectors; + /* OPTIONS GO HERE */ + int isoLevel; + + int include_padding_areas; + + int follow_sym_links; + int verbose_level; + int displayHelp; + int keep_bad_images; + + /* SUSP options and variables */ + int64_t susp_continuation_area_start_sector; + int64_t susp_continuation_area_size; + int64_t susp_continuation_area_current_free; + + int rock_ridge_enabled; + /* Other Rock Ridge Variables */ + char *rock_ridge_renamed_dir_name; + int rock_ridge_move_count; + cd9660node *rr_moved_dir; + + int archimedes_enabled; + int chrp_boot; + + /* Spec breaking options */ + u_char allow_deep_trees; + u_char allow_start_dot; + u_char allow_max_name; /* Allow 37 char filenames*/ + u_char allow_illegal_chars; /* ~, !, # */ + u_char allow_lowercase; + u_char allow_multidot; + u_char omit_trailing_period; + + /* BOOT INFORMATION HERE */ + int has_generic_bootimage; /* Default to 0 */ + char *generic_bootimage; + + int is_bootable;/* Default to 0 */ + int64_t boot_catalog_sector; + boot_volume_descriptor *boot_descriptor; + char * boot_image_directory; + + TAILQ_HEAD(boot_image_list,cd9660_boot_image) boot_images; + int image_serialno; + LIST_HEAD(boot_catalog_entries,boot_catalog_entry) boot_entries; + +} iso9660_disk; + +/************ FUNCTIONS **************/ +int cd9660_valid_a_chars(const char *); +int cd9660_valid_d_chars(const char *); +void cd9660_uppercase_characters(char *, int); + +/* ISO Data Types */ +void cd9660_721(uint16_t, unsigned char *); +void cd9660_731(uint32_t, unsigned char *); +void cd9660_722(uint16_t, unsigned char *); +void cd9660_732(uint32_t, unsigned char *); +void cd9660_bothendian_dword(uint32_t dw, unsigned char *); +void cd9660_bothendian_word(uint16_t dw, unsigned char *); +void cd9660_set_date(char *, time_t); +void cd9660_time_8426(unsigned char *, time_t); +void cd9660_time_915(unsigned char *, time_t); + +/*** Boot Functions ***/ +int cd9660_write_generic_bootimage(FILE *); +int cd9660_write_boot(iso9660_disk *, FILE *); +int cd9660_add_boot_disk(iso9660_disk *, const char *); +int cd9660_eltorito_add_boot_option(iso9660_disk *, const char *, + const char *); +int cd9660_setup_boot(iso9660_disk *, int); +int cd9660_setup_boot_volume_descriptor(iso9660_disk *, + volume_descriptor *); + + +/*** Write Functions ***/ +int cd9660_write_image(iso9660_disk *, const char *image); +int cd9660_copy_file(iso9660_disk *, FILE *, off_t, const char *); + +void cd9660_compute_full_filename(cd9660node *, char *); +int cd9660_compute_record_size(iso9660_disk *, cd9660node *); + +/* Debugging functions */ +void debug_print_tree(iso9660_disk *, cd9660node *,int); +void debug_print_path_tree(cd9660node *); +void debug_print_volume_descriptor_information(iso9660_disk *); +void debug_dump_to_xml_ptentry(path_table_entry *,int, int); +void debug_dump_to_xml_path_table(FILE *, off_t, int, int); +void debug_dump_to_xml(FILE *); +int debug_get_encoded_number(unsigned char *, int); +void debug_dump_integer(const char *, char *,int); +void debug_dump_string(const char *,unsigned char *,int); +void debug_dump_directory_record_9_1(unsigned char *); +void debug_dump_to_xml_volume_descriptor(unsigned char *,int); + +void cd9660_pad_string_spaces(char *, int); + +#endif diff --git a/vendor/bdj-sdk/host/src/makefs_termux/chfs.c b/vendor/bdj-sdk/host/src/makefs_termux/chfs.c new file mode 100644 index 0000000..de14246 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/chfs.c @@ -0,0 +1,222 @@ +/*- + * Copyright (c) 2012 Department of Software Engineering, + * University of Szeged, Hungary + * Copyright (c) 2012 Tamas Toth + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by the Department of Software Engineering, University of Szeged, Hungary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR ``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 AUTHOR 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. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "makefs.h" +#include "chfs_makefs.h" + +#include "chfs/chfs_mkfs.h" + +static void chfs_validate(const char *, fsnode *, fsinfo_t *); +static int chfs_create_image(const char *, fsinfo_t *); +static int chfs_populate_dir(const char *, fsnode *, fsnode *, fsinfo_t *); + + +void +chfs_prep_opts(fsinfo_t *fsopts) +{ + chfs_opt_t *chfs_opts = ecalloc(1, sizeof(*chfs_opts)); + + const option_t chfs_options[] = { + { 'p', "pagesize", &chfs_opts->pagesize, OPT_INT32, + 1, INT_MAX, "page size" }, + { 'e', "eraseblock", &chfs_opts->eraseblock, OPT_INT32, + 1, INT_MAX, "eraseblock size" }, + { 'm', "mediatype", &chfs_opts->mediatype, OPT_INT32, + 0, 1, "type of the media, 0 (nor) or 1 (nand)" }, + { .name = NULL } + }; + + chfs_opts->pagesize = -1; + chfs_opts->eraseblock = -1; + chfs_opts->mediatype = -1; + + fsopts->size = 0; + fsopts->fs_specific = chfs_opts; + fsopts->fs_options = copy_opts(chfs_options); +} + +void +chfs_cleanup_opts(fsinfo_t *fsopts) +{ + free(fsopts->fs_specific); + free(fsopts->fs_options); +} + +int +chfs_parse_opts(const char *option, fsinfo_t *fsopts) +{ + + assert(option != NULL); + assert(fsopts != NULL); + + return set_option(fsopts->fs_options, option, NULL, 0) != -1; +} + +void +chfs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) +{ + struct timeval start; + + assert(image != NULL); + assert(dir != NULL); + assert(root != NULL); + assert(fsopts != NULL); + + TIMER_START(start); + chfs_validate(dir, root, fsopts); + TIMER_RESULTS(start, "chfs_validate"); + + printf("Creating `%s'\n", image); + TIMER_START(start); + if (chfs_create_image(image, fsopts) == -1) { + errx(EXIT_FAILURE, "Image file `%s' not created", image); + } + TIMER_RESULTS(start, "chfs_create_image"); + + fsopts->curinode = CHFS_ROOTINO; + root->inode->ino = CHFS_ROOTINO; + + printf("Populating `%s'\n", image); + TIMER_START(start); + write_eb_header(fsopts); + if (!chfs_populate_dir(dir, root, root, fsopts)) { + errx(EXIT_FAILURE, "Image file `%s' not populated", image); + } + TIMER_RESULTS(start, "chfs_populate_dir"); + + padblock(fsopts); + + if (close(fsopts->fd) == -1) { + err(EXIT_FAILURE, "Closing `%s'", image); + } + fsopts->fd = -1; + + printf("Image `%s' complete\n", image); +} + +static void +chfs_validate(const char* dir, fsnode *root, fsinfo_t *fsopts) +{ + chfs_opt_t *chfs_opts; + assert(dir != NULL); + assert(root != NULL); + assert(fsopts != NULL); + + chfs_opts = fsopts->fs_specific; + + if (chfs_opts->pagesize == -1) { + chfs_opts->pagesize = DEFAULT_PAGESIZE; + } + if (chfs_opts->eraseblock == -1) { + chfs_opts->eraseblock = DEFAULT_ERASEBLOCK; + } + if (chfs_opts->mediatype == -1) { + chfs_opts->mediatype = DEFAULT_MEDIATYPE; + } +} + +static int +chfs_create_image(const char *image, fsinfo_t *fsopts) +{ + assert(image != NULL); + assert(fsopts != NULL); + + if ((fsopts->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { + warn("Can't open `%s' for writing", image); + return -1; + } + + return fsopts->fd; +} + +static int +chfs_populate_dir(const char *dir, fsnode *root, fsnode *parent, + fsinfo_t *fsopts) +{ + fsnode *cur; + char path[MAXPATHLEN + 1]; + + assert(dir != NULL); + assert(root != NULL); + assert(fsopts != NULL); + + for (cur = root->next; cur != NULL; cur = cur->next) { + if ((cur->inode->flags & FI_ALLOCATED) == 0) { + cur->inode->flags |= FI_ALLOCATED; + if (cur != root) { + fsopts->curinode++; + cur->inode->ino = fsopts->curinode; + cur->parent = parent; + } + } + + if (cur->inode->flags & FI_WRITTEN) { + continue; // hard link + } + cur->inode->flags |= FI_WRITTEN; + + write_vnode(fsopts, cur); + write_dirent(fsopts, cur); + if (!S_ISDIR(cur->type & S_IFMT)) { + write_file(fsopts, cur, dir); + } + } + + for (cur = root; cur != NULL; cur = cur->next) { + if (cur->child == NULL) { + continue; + } + if ((size_t)snprintf(path, sizeof(path), "%s/%s", dir, + cur->name) >= sizeof(path)) { + errx(EXIT_FAILURE, "Pathname too long"); + } + if (!chfs_populate_dir(path, cur->child, cur, fsopts)) { + return 0; + } + } + + return 1; +} + diff --git a/vendor/bdj-sdk/host/src/makefs_termux/chfs_makefs.h b/vendor/bdj-sdk/host/src/makefs_termux/chfs_makefs.h new file mode 100644 index 0000000..e722a9f --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/chfs_makefs.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2012 Department of Software Engineering, + * University of Szeged, Hungary + * Copyright (c) 2012 Tamas Toth + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by the Department of Software Engineering, University of Szeged, Hungary + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _CHFS_MAKEFS_H +#define _CHFS_MAKEFS_H + +#define TYPE_NOR 0 +#define TYPE_NAND 1 + +#define DEFAULT_PAGESIZE 2048 +#define DEFAULT_ERASEBLOCK 131072 +#define DEFAULT_MEDIATYPE TYPE_NAND + +typedef struct { + int pagesize; /* page size */ + int eraseblock; /* eraseblock size */ + int mediatype; /* type of the media, 0 (nor) or 1 (nand) */ +} chfs_opt_t; + +#endif diff --git a/vendor/bdj-sdk/host/src/makefs_termux/extern.h b/vendor/bdj-sdk/host/src/makefs_termux/extern.h new file mode 100644 index 0000000..0bf4302 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/extern.h @@ -0,0 +1,93 @@ +/* $NetBSD: extern.h,v 1.5 2011/07/27 15:31:00 seb Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#include "mtree.h" + +#if 0 +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#else +#define HAVE_STRUCT_STAT_ST_FLAGS 1 +#endif +#endif + +// #include +#if HAVE_ERR_H +#include +#endif +#if HAVE_FTS_H +#include +#endif + +#if HAVE_NETDB_H +/* For MAXHOSTNAMELEN on some platforms. */ +#if HAVE_NETDB_H +#include +#endif +#endif + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif + +void addtag(slist_t *, char *); +int check_excludes(const char *, const char *); +int compare(NODE *, FTSENT *); +int crc(int, uint32_t *, uint32_t *); +void cwalk(void); +void dump_nodes(const char *, NODE *, int); +void init_excludes(void); +int matchtags(NODE *); +void mtree_err(const char *, ...) + __attribute__((__format__(__printf__, 1, 2))); +const char *nodetype(u_int); +u_int parsekey(const char *, int *); +void parsetags(slist_t *, char *); +u_int parsetype(const char *); +void read_excludes_file(const char *); +const char *rlink(const char *); +int verify(void); + +extern int dflag, eflag, iflag, lflag, mflag, rflag, sflag, tflag, uflag; +extern int mtree_Mflag, mtree_Wflag; +extern size_t mtree_lineno; +extern uint32_t crc_total; +extern int ftsoptions, keys; +extern char fullpath[]; +extern slist_t includetags, excludetags; + + +#include "stat_flags.h" diff --git a/vendor/bdj-sdk/host/src/makefs_termux/ffs.c b/vendor/bdj-sdk/host/src/makefs_termux/ffs.c new file mode 100644 index 0000000..44f1519 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/ffs.c @@ -0,0 +1,1155 @@ +/* $NetBSD: ffs.c,v 1.64 2015/01/12 19:50:25 christos Exp $ */ + +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Luke Mewburn for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ +/* + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)ffs_alloc.c 8.19 (Berkeley) 7/13/95 + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if defined(__RCSID) && !defined(__lint) +__RCSID("$NetBSD: ffs.c,v 1.64 2015/01/12 19:50:25 christos Exp $"); +#endif /* !__lint */ + +#include + +#if !HAVE_NBTOOL_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "makefs.h" +#include "ffs.h" + +#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS +#include +#endif + +#include +#include +#include +#include + +#include "ffs/ufs_inode.h" +#include "ffs/newfs_extern.h" +#include "ffs/ffs_extern.h" + +#undef DIP +#define DIP(dp, field) \ + ((ffs_opts->version == 1) ? \ + (dp)->ffs1_din.di_##field : (dp)->ffs2_din.di_##field) + +/* + * Various file system defaults (cribbed from newfs(8)). + */ +#define DFL_FRAGSIZE 1024 /* fragment size */ +#define DFL_BLKSIZE 8192 /* block size */ +#define DFL_SECSIZE 512 /* sector size */ +#define DFL_CYLSPERGROUP 65536 /* cylinders per group */ +#define DFL_FRAGSPERINODE 4 /* fragments per inode */ +#define DFL_ROTDELAY 0 /* rotational delay */ +#define DFL_NRPOS 1 /* rotational positions */ +#define DFL_RPM 3600 /* rpm of disk */ +#define DFL_NSECTORS 64 /* # of sectors */ +#define DFL_NTRACKS 16 /* # of tracks */ + + +typedef struct { + u_char *buf; /* buf for directory */ + doff_t size; /* full size of buf */ + doff_t cur; /* offset of current entry */ +} dirbuf_t; + + +static int ffs_create_image(const char *, fsinfo_t *); +static void ffs_dump_fsinfo(fsinfo_t *); +static void ffs_dump_dirbuf(dirbuf_t *, const char *, int); +static void ffs_make_dirbuf(dirbuf_t *, const char *, fsnode *, int); +static int ffs_populate_dir(const char *, fsnode *, fsinfo_t *); +static void ffs_size_dir(fsnode *, fsinfo_t *); +static void ffs_validate(const char *, fsnode *, fsinfo_t *); +static void ffs_write_file(union dinode *, uint32_t, void *, fsinfo_t *); +static void ffs_write_inode(union dinode *, uint32_t, const fsinfo_t *); +static void *ffs_build_dinode1(struct ufs1_dinode *, dirbuf_t *, fsnode *, + fsnode *, fsinfo_t *); +static void *ffs_build_dinode2(struct ufs2_dinode *, dirbuf_t *, fsnode *, + fsnode *, fsinfo_t *); + + + + /* publically visible functions */ +void +ffs_prep_opts(fsinfo_t *fsopts) +{ + ffs_opt_t *ffs_opts = ecalloc(1, sizeof(*ffs_opts)); + + const option_t ffs_options[] = { + { 'b', "bsize", &ffs_opts->bsize, OPT_INT32, + 1, INT_MAX, "block size" }, + { 'f', "fsize", &ffs_opts->fsize, OPT_INT32, + 1, INT_MAX, "fragment size" }, + { 'd', "density", &ffs_opts->density, OPT_INT32, + 1, INT_MAX, "bytes per inode" }, + { 'm', "minfree", &ffs_opts->minfree, OPT_INT32, + 0, 99, "minfree" }, + { 'M', "maxbpg", &ffs_opts->maxbpg, OPT_INT32, + 1, INT_MAX, "max blocks per file in a cg" }, + { 'a', "avgfilesize", &ffs_opts->avgfilesize, OPT_INT32, + 1, INT_MAX, "expected average file size" }, + { 'n', "avgfpdir", &ffs_opts->avgfpdir, OPT_INT32, + 1, INT_MAX, "expected # of files per directory" }, + { 'x', "extent", &ffs_opts->maxbsize, OPT_INT32, + 1, INT_MAX, "maximum # extent size" }, + { 'g', "maxbpcg", &ffs_opts->maxblkspercg, OPT_INT32, + 1, INT_MAX, "max # of blocks per group" }, + { 'v', "version", &ffs_opts->version, OPT_INT32, + 1, 2, "UFS version" }, + { 'o', "optimization", NULL, OPT_STRBUF, + 0, 0, "Optimization (time|space)" }, + { 'l', "label", ffs_opts->label, OPT_STRARRAY, + 1, sizeof(ffs_opts->label), "UFS label" }, + { .name = NULL } + }; + + ffs_opts->bsize= -1; + ffs_opts->fsize= -1; + ffs_opts->cpg= -1; + ffs_opts->density= -1; + ffs_opts->minfree= -1; + ffs_opts->optimization= -1; + ffs_opts->maxcontig= -1; + ffs_opts->maxbpg= -1; + ffs_opts->avgfilesize= -1; + ffs_opts->avgfpdir= -1; + ffs_opts->version = 1; + + fsopts->fs_specific = ffs_opts; + fsopts->fs_options = copy_opts(ffs_options); +} + +void +ffs_cleanup_opts(fsinfo_t *fsopts) +{ + free(fsopts->fs_specific); + free(fsopts->fs_options); +} + +int +ffs_parse_opts(const char *option, fsinfo_t *fsopts) +{ + ffs_opt_t *ffs_opts = fsopts->fs_specific; + option_t *ffs_options = fsopts->fs_options; + char buf[1024]; + + int rv; + + assert(option != NULL); + assert(fsopts != NULL); + assert(ffs_opts != NULL); + + if (debug & DEBUG_FS_PARSE_OPTS) + printf("ffs_parse_opts: got `%s'\n", option); + + rv = set_option(ffs_options, option, buf, sizeof(buf)); + if (rv == -1) + return 0; + + if (ffs_options[rv].name == NULL) + abort(); + + switch (ffs_options[rv].letter) { + case 'o': + if (strcmp(buf, "time") == 0) { + ffs_opts->optimization = FS_OPTTIME; + } else if (strcmp(buf, "space") == 0) { + ffs_opts->optimization = FS_OPTSPACE; + } else { + warnx("Invalid optimization `%s'", buf); + return 0; + } + break; + default: + break; + } + return 1; +} + + +void +ffs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) +{ + struct fs *superblock; + struct timeval start; + + assert(image != NULL); + assert(dir != NULL); + assert(root != NULL); + assert(fsopts != NULL); + + if (debug & DEBUG_FS_MAKEFS) + printf("ffs_makefs: image %s directory %s root %p\n", + image, dir, root); + + /* validate tree and options */ + TIMER_START(start); + ffs_validate(dir, root, fsopts); + TIMER_RESULTS(start, "ffs_validate"); + + printf("Calculated size of `%s': %lld bytes, %lld inodes\n", + image, (long long)fsopts->size, (long long)fsopts->inodes); + + /* create image */ + TIMER_START(start); + if (ffs_create_image(image, fsopts) == -1) + errx(1, "Image file `%s' not created.", image); + TIMER_RESULTS(start, "ffs_create_image"); + + fsopts->curinode = UFS_ROOTINO; + + if (debug & DEBUG_FS_MAKEFS) + putchar('\n'); + + /* populate image */ + printf("Populating `%s'\n", image); + TIMER_START(start); + if (! ffs_populate_dir(dir, root, fsopts)) + errx(1, "Image file `%s' not populated.", image); + TIMER_RESULTS(start, "ffs_populate_dir"); + + /* ensure no outstanding buffers remain */ + if (debug & DEBUG_FS_MAKEFS) + bcleanup(); + + /* update various superblock parameters */ + superblock = fsopts->superblock; + superblock->fs_fmod = 0; + superblock->fs_old_cstotal.cs_ndir = superblock->fs_cstotal.cs_ndir; + superblock->fs_old_cstotal.cs_nbfree = superblock->fs_cstotal.cs_nbfree; + superblock->fs_old_cstotal.cs_nifree = superblock->fs_cstotal.cs_nifree; + superblock->fs_old_cstotal.cs_nffree = superblock->fs_cstotal.cs_nffree; + + /* write out superblock; image is now complete */ + ffs_write_superblock(fsopts->superblock, fsopts); + if (close(fsopts->fd) == -1) + err(1, "Closing `%s'", image); + fsopts->fd = -1; + printf("Image `%s' complete\n", image); +} + + /* end of public functions */ + + +static void +ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts) +{ + int32_t ncg = 1; +#if notyet + int32_t spc, nspf, ncyl, fssize; +#endif + ffs_opt_t *ffs_opts = fsopts->fs_specific; + + assert(dir != NULL); + assert(root != NULL); + assert(fsopts != NULL); + assert(ffs_opts != NULL); + + if (debug & DEBUG_FS_VALIDATE) { + printf("ffs_validate: before defaults set:\n"); + ffs_dump_fsinfo(fsopts); + } + + /* set FFS defaults */ + if (fsopts->sectorsize == -1) + fsopts->sectorsize = DFL_SECSIZE; + if (ffs_opts->fsize == -1) + ffs_opts->fsize = MAX(DFL_FRAGSIZE, fsopts->sectorsize); + if (ffs_opts->bsize == -1) + ffs_opts->bsize = MIN(DFL_BLKSIZE, 8 * ffs_opts->fsize); + if (ffs_opts->cpg == -1) + ffs_opts->cpg = DFL_CYLSPERGROUP; + else + ffs_opts->cpgflg = 1; + /* fsopts->density is set below */ + if (ffs_opts->nsectors == -1) + ffs_opts->nsectors = DFL_NSECTORS; + if (ffs_opts->minfree == -1) + ffs_opts->minfree = MINFREE; + if (ffs_opts->optimization == -1) + ffs_opts->optimization = DEFAULTOPT; + if (ffs_opts->maxcontig == -1) + ffs_opts->maxcontig = + MAX(1, MIN(MAXPHYS, FFS_MAXBSIZE) / ffs_opts->bsize); + /* XXX ondisk32 */ + if (ffs_opts->maxbpg == -1) + ffs_opts->maxbpg = ffs_opts->bsize / sizeof(int32_t); + if (ffs_opts->avgfilesize == -1) + ffs_opts->avgfilesize = AVFILESIZ; + if (ffs_opts->avgfpdir == -1) + ffs_opts->avgfpdir = AFPDIR; + + /* calculate size of tree */ + ffs_size_dir(root, fsopts); + fsopts->inodes += UFS_ROOTINO; /* include first two inodes */ + + if (debug & DEBUG_FS_VALIDATE) + printf("ffs_validate: size of tree: %lld bytes, %lld inodes\n", + (long long)fsopts->size, (long long)fsopts->inodes); + + /* add requested slop */ + fsopts->size += fsopts->freeblocks; + fsopts->inodes += fsopts->freefiles; + if (fsopts->freefilepc > 0) + fsopts->inodes = + fsopts->inodes * (100 + fsopts->freefilepc) / 100; + if (fsopts->freeblockpc > 0) + fsopts->size = + fsopts->size * (100 + fsopts->freeblockpc) / 100; + + /* add space needed for superblocks */ + /* + * The old SBOFF (SBLOCK_UFS1) is used here because makefs is + * typically used for small filesystems where space matters. + * XXX make this an option. + */ + fsopts->size += (SBLOCK_UFS1 + SBLOCKSIZE) * ncg; + /* add space needed to store inodes, x3 for blockmaps, etc */ + if (ffs_opts->version == 1) + fsopts->size += ncg * DINODE1_SIZE * + roundup(fsopts->inodes / ncg, + ffs_opts->bsize / DINODE1_SIZE); + else + fsopts->size += ncg * DINODE2_SIZE * + roundup(fsopts->inodes / ncg, + ffs_opts->bsize / DINODE2_SIZE); + + /* add minfree */ + if (ffs_opts->minfree > 0) + fsopts->size = + fsopts->size * (100 + ffs_opts->minfree) / 100; + /* + * XXX any other fs slop to add, such as csum's, bitmaps, etc ?? + */ + + if (fsopts->size < fsopts->minsize) /* ensure meets minimum size */ + fsopts->size = fsopts->minsize; + + /* round up to the next block */ + fsopts->size = roundup(fsopts->size, ffs_opts->bsize); + + /* calculate density if necessary */ + if (ffs_opts->density == -1) + ffs_opts->density = fsopts->size / fsopts->inodes + 1; + + if (debug & DEBUG_FS_VALIDATE) { + printf("ffs_validate: after defaults set:\n"); + ffs_dump_fsinfo(fsopts); + printf("ffs_validate: dir %s; %lld bytes, %lld inodes\n", + dir, (long long)fsopts->size, (long long)fsopts->inodes); + } + /* now check calculated sizes vs requested sizes */ + if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) { + errx(1, "`%s' size of %lld is larger than the maxsize of %lld.", + dir, (long long)fsopts->size, (long long)fsopts->maxsize); + } +} + + +static void +ffs_dump_fsinfo(fsinfo_t *f) +{ + + ffs_opt_t *fs = f->fs_specific; + + printf("fsopts at %p\n", f); + + printf("\tsize %lld, inodes %lld, curinode %u\n", + (long long)f->size, (long long)f->inodes, f->curinode); + + printf("\tminsize %lld, maxsize %lld\n", + (long long)f->minsize, (long long)f->maxsize); + printf("\tfree files %lld, freefile %% %d\n", + (long long)f->freefiles, f->freefilepc); + printf("\tfree blocks %lld, freeblock %% %d\n", + (long long)f->freeblocks, f->freeblockpc); + printf("\tneedswap %d, sectorsize %d\n", f->needswap, f->sectorsize); + + printf("\tbsize %d, fsize %d, cpg %d, density %d\n", + fs->bsize, fs->fsize, fs->cpg, fs->density); + printf("\tnsectors %d, rpm %d, minfree %d\n", + fs->nsectors, fs->rpm, fs->minfree); + printf("\tmaxcontig %d, maxbpg %d\n", + fs->maxcontig, fs->maxbpg); + printf("\toptimization %s\n", + fs->optimization == FS_OPTSPACE ? "space" : "time"); +} + + +static int +ffs_create_image(const char *image, fsinfo_t *fsopts) +{ +#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS + struct statvfs sfs; +#endif + struct fs *fs; + char *buf; + int i, bufsize; + off_t bufrem; + int oflags = O_RDWR | O_CREAT; + + assert (image != NULL); + assert (fsopts != NULL); + + /* create image */ + if (fsopts->offset == 0) + oflags |= O_TRUNC; + if ((fsopts->fd = open(image, oflags, 0666)) == -1) { + warn("Can't open `%s' for writing", image); + return (-1); + } + + /* zero image */ +#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS + if (fstatvfs(fsopts->fd, &sfs) == -1) { +#endif + bufsize = 8192; +#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS + warn("can't fstatvfs `%s', using default %d byte chunk", + image, bufsize); + } else + bufsize = sfs.f_iosize; +#endif + bufrem = fsopts->size; + + if (fsopts->sparse) { + if (ftruncate(fsopts->fd, bufrem) == -1) { + printf ("ERROR in truncate. Sparse option disabled\n"); + fsopts->sparse = 0; + } else { + bufrem = 0; /* File truncated at bufrem. Remaining is 0 */ + buf = NULL; + } + } + + if (fsopts->offset != 0) + if (lseek(fsopts->fd, fsopts->offset, SEEK_SET) == -1) { + warn("can't seek"); + return -1; + } + + if ((debug & DEBUG_FS_CREATE_IMAGE) && fsopts->sparse == 0) + printf( + "zero-ing image `%s', %lld sectors, using %d byte chunks\n", + image, (long long)bufrem, bufsize); + if (bufrem > 0) + buf = ecalloc(1, bufsize); + while (bufrem > 0) { + i = write(fsopts->fd, buf, MIN(bufsize, bufrem)); + if (i == -1) { + warn("zeroing image, %lld bytes to go", + (long long)bufrem); + free(buf); + return (-1); + } + bufrem -= i; + } + if (buf) + free(buf); + + /* make the file system */ + if (debug & DEBUG_FS_CREATE_IMAGE) + printf("calling mkfs(\"%s\", ...)\n", image); + fs = ffs_mkfs(image, fsopts); + fsopts->superblock = (void *)fs; + if (debug & DEBUG_FS_CREATE_IMAGE) { + time_t t; + + t = (time_t)((struct fs *)fsopts->superblock)->fs_time; + printf("mkfs returned %p; fs_time %s", + fsopts->superblock, ctime(&t)); + printf("fs totals: nbfree %lld, nffree %lld, nifree %lld, ndir %lld\n", + (long long)fs->fs_cstotal.cs_nbfree, + (long long)fs->fs_cstotal.cs_nffree, + (long long)fs->fs_cstotal.cs_nifree, + (long long)fs->fs_cstotal.cs_ndir); + } + + if ((off_t)(fs->fs_cstotal.cs_nifree + UFS_ROOTINO) < fsopts->inodes) { + warnx( + "Image file `%s' has %lld free inodes; %lld are required.", + image, + (long long)(fs->fs_cstotal.cs_nifree + UFS_ROOTINO), + (long long)fsopts->inodes); + return (-1); + } + return (fsopts->fd); +} + + +static void +ffs_size_dir(fsnode *root, fsinfo_t *fsopts) +{ + struct direct tmpdir; + fsnode * node; + int curdirsize, this; + ffs_opt_t *ffs_opts = fsopts->fs_specific; + + /* node may be NULL (empty directory) */ + assert(fsopts != NULL); + assert(ffs_opts != NULL); + + if (debug & DEBUG_FS_SIZE_DIR) + printf("ffs_size_dir: entry: bytes %lld inodes %lld\n", + (long long)fsopts->size, (long long)fsopts->inodes); + +#define ADDDIRENT(e) do { \ + tmpdir.d_namlen = strlen((e)); \ + this = UFS_DIRSIZ(0, &tmpdir, 0); \ + if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT) \ + printf("ADDDIRENT: was: %s (%d) this %d cur %d\n", \ + e, tmpdir.d_namlen, this, curdirsize); \ + if (this + curdirsize > roundup(curdirsize, UFS_DIRBLKSIZ)) \ + curdirsize = roundup(curdirsize, UFS_DIRBLKSIZ); \ + curdirsize += this; \ + if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT) \ + printf("ADDDIRENT: now: %s (%d) this %d cur %d\n", \ + e, tmpdir.d_namlen, this, curdirsize); \ +} while (0); + + /* + * XXX this needs to take into account extra space consumed + * by indirect blocks, etc. + */ +#define ADDSIZE(x) do { \ + fsopts->size += roundup((x), ffs_opts->fsize); \ +} while (0); + + curdirsize = 0; + for (node = root; node != NULL; node = node->next) { + ADDDIRENT(node->name); + if (node == root) { /* we're at "." */ + assert(strcmp(node->name, ".") == 0); + ADDDIRENT(".."); + } else if ((node->inode->flags & FI_SIZED) == 0) { + /* don't count duplicate names */ + node->inode->flags |= FI_SIZED; + if (debug & DEBUG_FS_SIZE_DIR_NODE) + printf("ffs_size_dir: `%s' size %lld\n", + node->name, + (long long)node->inode->st.st_size); + fsopts->inodes++; + if (node->type == S_IFREG) + ADDSIZE(node->inode->st.st_size); + if (node->type == S_IFLNK) { + size_t slen; + + slen = strlen(node->symlink) + 1; + if (slen >= (ffs_opts->version == 1 ? + UFS1_MAXSYMLINKLEN : + UFS2_MAXSYMLINKLEN)) + ADDSIZE(slen); + } + } + if (node->type == S_IFDIR) + ffs_size_dir(node->child, fsopts); + } + ADDSIZE(curdirsize); + + if (debug & DEBUG_FS_SIZE_DIR) + printf("ffs_size_dir: exit: size %lld inodes %lld\n", + (long long)fsopts->size, (long long)fsopts->inodes); +} + +static void * +ffs_build_dinode1(struct ufs1_dinode *dinp, dirbuf_t *dbufp, fsnode *cur, + fsnode *root, fsinfo_t *fsopts) +{ + size_t slen; + void *membuf; + + memset(dinp, 0, sizeof(*dinp)); + dinp->di_mode = cur->inode->st.st_mode; + dinp->di_nlink = cur->inode->nlink; + dinp->di_size = cur->inode->st.st_size; + dinp->di_atime = cur->inode->st.st_atime; + dinp->di_mtime = cur->inode->st.st_mtime; + dinp->di_ctime = cur->inode->st.st_ctime; +#if HAVE_STRUCT_STAT_ST_MTIMENSEC + dinp->di_atimensec = cur->inode->st.st_atimensec; + dinp->di_mtimensec = cur->inode->st.st_mtimensec; + dinp->di_ctimensec = cur->inode->st.st_ctimensec; +#endif +#if HAVE_STRUCT_STAT_ST_FLAGS + dinp->di_flags = cur->inode->st.st_flags; +#endif +#if HAVE_STRUCT_STAT_ST_GEN + dinp->di_gen = cur->inode->st.st_gen; +#endif + dinp->di_uid = cur->inode->st.st_uid; + dinp->di_gid = cur->inode->st.st_gid; + /* not set: di_db, di_ib, di_blocks, di_spare */ + + membuf = NULL; + if (cur == root) { /* "."; write dirbuf */ + membuf = dbufp->buf; + dinp->di_size = dbufp->size; + } else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) { + dinp->di_size = 0; /* a device */ + dinp->di_rdev = + ufs_rw32(cur->inode->st.st_rdev, fsopts->needswap); + } else if (S_ISLNK(cur->type)) { /* symlink */ + slen = strlen(cur->symlink); + if (slen < UFS1_MAXSYMLINKLEN) { /* short link */ + memcpy(dinp->di_db, cur->symlink, slen); + } else + membuf = cur->symlink; + dinp->di_size = slen; + } + return membuf; +} + +static void * +ffs_build_dinode2(struct ufs2_dinode *dinp, dirbuf_t *dbufp, fsnode *cur, + fsnode *root, fsinfo_t *fsopts) +{ + size_t slen; + void *membuf; + + memset(dinp, 0, sizeof(*dinp)); + dinp->di_mode = cur->inode->st.st_mode; + dinp->di_nlink = cur->inode->nlink; + dinp->di_size = cur->inode->st.st_size; + dinp->di_atime = cur->inode->st.st_atime; + dinp->di_mtime = cur->inode->st.st_mtime; + dinp->di_ctime = cur->inode->st.st_ctime; +#if HAVE_STRUCT_STAT_ST_MTIMENSEC + dinp->di_atimensec = cur->inode->st.st_atimensec; + dinp->di_mtimensec = cur->inode->st.st_mtimensec; + dinp->di_ctimensec = cur->inode->st.st_ctimensec; +#endif +#if HAVE_STRUCT_STAT_ST_FLAGS + dinp->di_flags = cur->inode->st.st_flags; +#endif +#if HAVE_STRUCT_STAT_ST_GEN + dinp->di_gen = cur->inode->st.st_gen; +#endif +#if HAVE_STRUCT_STAT_BIRTHTIME + dinp->di_birthtime = cur->inode->st.st_birthtime; + dinp->di_birthnsec = cur->inode->st.st_birthtimensec; +#endif + dinp->di_uid = cur->inode->st.st_uid; + dinp->di_gid = cur->inode->st.st_gid; + /* not set: di_db, di_ib, di_blocks, di_spare */ + + membuf = NULL; + if (cur == root) { /* "."; write dirbuf */ + membuf = dbufp->buf; + dinp->di_size = dbufp->size; + } else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) { + dinp->di_size = 0; /* a device */ + dinp->di_rdev = + ufs_rw64(cur->inode->st.st_rdev, fsopts->needswap); + } else if (S_ISLNK(cur->type)) { /* symlink */ + slen = strlen(cur->symlink); + if (slen < UFS2_MAXSYMLINKLEN) { /* short link */ + memcpy(dinp->di_db, cur->symlink, slen); + } else + membuf = cur->symlink; + dinp->di_size = slen; + } + return membuf; +} + +static int +ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts) +{ + fsnode *cur; + dirbuf_t dirbuf; + union dinode din; + void *membuf; + char path[MAXPATHLEN + 1]; + ffs_opt_t *ffs_opts = fsopts->fs_specific; + + assert(dir != NULL); + assert(root != NULL); + assert(fsopts != NULL); + assert(ffs_opts != NULL); + + (void)memset(&dirbuf, 0, sizeof(dirbuf)); + + if (debug & DEBUG_FS_POPULATE) + printf("ffs_populate_dir: PASS 1 dir %s node %p\n", dir, root); + + /* + * pass 1: allocate inode numbers, build directory `file' + */ + for (cur = root; cur != NULL; cur = cur->next) { + if ((cur->inode->flags & FI_ALLOCATED) == 0) { + cur->inode->flags |= FI_ALLOCATED; + if (cur == root && cur->parent != NULL) + cur->inode->ino = cur->parent->inode->ino; + else { + cur->inode->ino = fsopts->curinode; + fsopts->curinode++; + } + } + ffs_make_dirbuf(&dirbuf, cur->name, cur, fsopts->needswap); + if (cur == root) { /* we're at "."; add ".." */ + ffs_make_dirbuf(&dirbuf, "..", + cur->parent == NULL ? cur : cur->parent->first, + fsopts->needswap); + root->inode->nlink++; /* count my parent's link */ + } else if (cur->child != NULL) + root->inode->nlink++; /* count my child's link */ + + /* + * XXX possibly write file and long symlinks here, + * ensuring that blocks get written before inodes? + * otoh, this isn't a real filesystem, so who + * cares about ordering? :-) + */ + } + if (debug & DEBUG_FS_POPULATE_DIRBUF) + ffs_dump_dirbuf(&dirbuf, dir, fsopts->needswap); + + /* + * pass 2: write out dirbuf, then non-directories at this level + */ + if (debug & DEBUG_FS_POPULATE) + printf("ffs_populate_dir: PASS 2 dir %s\n", dir); + for (cur = root; cur != NULL; cur = cur->next) { + if (cur->inode->flags & FI_WRITTEN) + continue; /* skip hard-linked entries */ + cur->inode->flags |= FI_WRITTEN; + + if ((size_t)snprintf(path, sizeof(path), "%s/%s/%s", cur->root, + cur->path, cur->name) >= sizeof(path)) + errx(1, "Pathname too long."); + + if (cur->child != NULL) + continue; /* child creates own inode */ + + /* build on-disk inode */ + if (ffs_opts->version == 1) + membuf = ffs_build_dinode1(&din.ffs1_din, &dirbuf, cur, + root, fsopts); + else + membuf = ffs_build_dinode2(&din.ffs2_din, &dirbuf, cur, + root, fsopts); + + if (debug & DEBUG_FS_POPULATE_NODE) { + printf("ffs_populate_dir: writing ino %d, %s", + cur->inode->ino, inode_type(cur->type)); + if (cur->inode->nlink > 1) + printf(", nlink %d", cur->inode->nlink); + putchar('\n'); + } + + if (membuf != NULL) { + ffs_write_file(&din, cur->inode->ino, membuf, fsopts); + } else if (S_ISREG(cur->type)) { + ffs_write_file(&din, cur->inode->ino, path, fsopts); + } else { + assert (! S_ISDIR(cur->type)); + ffs_write_inode(&din, cur->inode->ino, fsopts); + } + } + + /* + * pass 3: write out sub-directories + */ + if (debug & DEBUG_FS_POPULATE) + printf("ffs_populate_dir: PASS 3 dir %s\n", dir); + for (cur = root; cur != NULL; cur = cur->next) { + if (cur->child == NULL) + continue; + if ((size_t)snprintf(path, sizeof(path), "%s/%s", dir, + cur->name) >= sizeof(path)) + errx(1, "Pathname too long."); + if (! ffs_populate_dir(path, cur->child, fsopts)) + return (0); + } + + if (debug & DEBUG_FS_POPULATE) + printf("ffs_populate_dir: DONE dir %s\n", dir); + + /* cleanup */ + if (dirbuf.buf != NULL) + free(dirbuf.buf); + return (1); +} + + +static void +ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts) +{ + int isfile, ffd; + char *fbuf, *p; + off_t bufleft, chunk, offset; + ssize_t nread; + struct inode in; + struct buf * bp; + ffs_opt_t *ffs_opts = fsopts->fs_specific; + struct vnode vp = { fsopts, NULL }; + + assert (din != NULL); + assert (buf != NULL); + assert (fsopts != NULL); + assert (ffs_opts != NULL); + + isfile = S_ISREG(DIP(din, mode)); + fbuf = NULL; + ffd = -1; + p = NULL; + + in.i_fs = (struct fs *)fsopts->superblock; + in.i_devvp = &vp; + + if (debug & DEBUG_FS_WRITE_FILE) { + printf( + "ffs_write_file: ino %u, din %p, isfile %d, %s, size %lld", + ino, din, isfile, inode_type(DIP(din, mode) & S_IFMT), + (long long)DIP(din, size)); + if (isfile) + printf(", file '%s'\n", (char *)buf); + else + printf(", buffer %p\n", buf); + } + + in.i_number = ino; + in.i_size = DIP(din, size); + if (ffs_opts->version == 1) + memcpy(&in.i_din.ffs1_din, &din->ffs1_din, + sizeof(in.i_din.ffs1_din)); + else + memcpy(&in.i_din.ffs2_din, &din->ffs2_din, + sizeof(in.i_din.ffs2_din)); + + if (DIP(din, size) == 0) + goto write_inode_and_leave; /* mmm, cheating */ + + if (isfile) { + fbuf = emalloc(ffs_opts->bsize); + if ((ffd = open((char *)buf, O_RDONLY, 0444)) == -1) { + warn("Can't open `%s' for reading", (char *)buf); + goto leave_ffs_write_file; + } + } else { + p = buf; + } + + chunk = 0; + for (bufleft = DIP(din, size); bufleft > 0; bufleft -= chunk) { + chunk = MIN(bufleft, ffs_opts->bsize); + if (!isfile) + ; + else if ((nread = read(ffd, fbuf, chunk)) == -1) + err(EXIT_FAILURE, "Reading `%s', %lld bytes to go", + (char *)buf, (long long)bufleft); + else if (nread != chunk) + errx(EXIT_FAILURE, "Reading `%s', %lld bytes to go, " + "read %zd bytes, expected %ju bytes, does " + "metalog size= attribute mismatch source size?", + (char *)buf, (long long)bufleft, nread, + (uintmax_t)chunk); + else + p = fbuf; + offset = DIP(din, size) - bufleft; + if (debug & DEBUG_FS_WRITE_FILE_BLOCK) + printf( + "ffs_write_file: write %p offset %lld size %lld left %lld\n", + p, (long long)offset, + (long long)chunk, (long long)bufleft); + /* + * XXX if holey support is desired, do the check here + * + * XXX might need to write out last bit in fragroundup + * sized chunk. however, ffs_balloc() handles this for us + */ + errno = ffs_balloc(&in, offset, chunk, &bp); + bad_ffs_write_file: + if (errno != 0) + err(1, + "Writing inode %d (%s), bytes %lld + %lld", + ino, + isfile ? (char *)buf : + inode_type(DIP(din, mode) & S_IFMT), + (long long)offset, (long long)chunk); + memcpy(bp->b_data, p, chunk); + errno = bwrite(bp); + if (errno != 0) + goto bad_ffs_write_file; + if (!isfile) + p += chunk; + } + + write_inode_and_leave: + ffs_write_inode(&in.i_din, in.i_number, fsopts); + + leave_ffs_write_file: + if (fbuf) + free(fbuf); + if (ffd != -1) + close(ffd); +} + + +static void +ffs_dump_dirbuf(dirbuf_t *dbuf, const char *dir, int needswap) +{ + doff_t i; + struct direct *de; + uint16_t reclen; + + assert (dbuf != NULL); + assert (dir != NULL); + printf("ffs_dump_dirbuf: dir %s size %d cur %d\n", + dir, dbuf->size, dbuf->cur); + + for (i = 0; i < dbuf->size; ) { + de = (struct direct *)(dbuf->buf + i); + reclen = ufs_rw16(de->d_reclen, needswap); + printf( + " inode %4d %7s offset %4d reclen %3d namlen %3d name %s\n", + ufs_rw32(de->d_fileno, needswap), + inode_type(DTTOIF(de->d_type)), i, reclen, + de->d_namlen, de->d_name); + i += reclen; + assert(reclen > 0); + } +} + +static void +ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap) +{ + struct direct de, *dp; + uint16_t llen, reclen; + u_char *newbuf; + + assert (dbuf != NULL); + assert (name != NULL); + assert (node != NULL); + /* create direct entry */ + (void)memset(&de, 0, sizeof(de)); + de.d_fileno = ufs_rw32(node->inode->ino, needswap); + de.d_type = IFTODT(node->type); + de.d_namlen = (uint8_t)strlen(name); + strcpy(de.d_name, name); + reclen = UFS_DIRSIZ(0, &de, needswap); + de.d_reclen = ufs_rw16(reclen, needswap); + + dp = (struct direct *)(dbuf->buf + dbuf->cur); + llen = 0; + if (dp != NULL) + llen = UFS_DIRSIZ(0, dp, needswap); + + if (debug & DEBUG_FS_MAKE_DIRBUF) + printf( + "ffs_make_dirbuf: dbuf siz %d cur %d lastlen %d\n" + " ino %d type %d reclen %d namlen %d name %.30s\n", + dbuf->size, dbuf->cur, llen, + ufs_rw32(de.d_fileno, needswap), de.d_type, reclen, + de.d_namlen, de.d_name); + + if (reclen + dbuf->cur + llen > roundup(dbuf->size, UFS_DIRBLKSIZ)) { + if (debug & DEBUG_FS_MAKE_DIRBUF) + printf("ffs_make_dirbuf: growing buf to %d\n", + dbuf->size + UFS_DIRBLKSIZ); + newbuf = erealloc(dbuf->buf, dbuf->size + UFS_DIRBLKSIZ); + dbuf->buf = newbuf; + dbuf->size += UFS_DIRBLKSIZ; + memset(dbuf->buf + dbuf->size - UFS_DIRBLKSIZ, 0, UFS_DIRBLKSIZ); + dbuf->cur = dbuf->size - UFS_DIRBLKSIZ; + } else if (dp) { /* shrink end of previous */ + dp->d_reclen = ufs_rw16(llen,needswap); + dbuf->cur += llen; + } + dp = (struct direct *)(dbuf->buf + dbuf->cur); + memcpy(dp, &de, reclen); + dp->d_reclen = ufs_rw16(dbuf->size - dbuf->cur, needswap); +} + +/* + * cribbed from sys/ufs/ffs/ffs_alloc.c + */ +static void +ffs_write_inode(union dinode *dp, uint32_t ino, const fsinfo_t *fsopts) +{ + char *buf; + struct ufs1_dinode *dp1; + struct ufs2_dinode *dp2, *dip; + struct cg *cgp; + struct fs *fs; + int cg, cgino, i; + daddr_t d; + char sbbuf[FFS_MAXBSIZE]; + uint32_t initediblk; + ffs_opt_t *ffs_opts = fsopts->fs_specific; + + assert (dp != NULL); + assert (ino > 0); + assert (fsopts != NULL); + assert (ffs_opts != NULL); + + fs = (struct fs *)fsopts->superblock; + cg = ino_to_cg(fs, ino); + cgino = ino % fs->fs_ipg; + if (debug & DEBUG_FS_WRITE_INODE) + printf("ffs_write_inode: din %p ino %u cg %d cgino %d\n", + dp, ino, cg, cgino); + + ffs_rdfs(FFS_FSBTODB(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf, + fsopts); + cgp = (struct cg *)sbbuf; + if (!cg_chkmagic(cgp, fsopts->needswap)) + errx(1, "ffs_write_inode: cg %d: bad magic number", cg); + + assert (isclr(cg_inosused(cgp, fsopts->needswap), cgino)); + + buf = emalloc(fs->fs_bsize); + dp1 = (struct ufs1_dinode *)buf; + dp2 = (struct ufs2_dinode *)buf; + + if (fs->fs_cstotal.cs_nifree == 0) + errx(1, "ffs_write_inode: fs out of inodes for ino %u", + ino); + if (fs->fs_cs(fs, cg).cs_nifree == 0) + errx(1, + "ffs_write_inode: cg %d out of inodes for ino %u", + cg, ino); + setbit(cg_inosused(cgp, fsopts->needswap), cgino); + ufs_add32(cgp->cg_cs.cs_nifree, -1, fsopts->needswap); + fs->fs_cstotal.cs_nifree--; + fs->fs_cs(fs, cg).cs_nifree--; + if (S_ISDIR(DIP(dp, mode))) { + ufs_add32(cgp->cg_cs.cs_ndir, 1, fsopts->needswap); + fs->fs_cstotal.cs_ndir++; + fs->fs_cs(fs, cg).cs_ndir++; + } + + /* + * Initialize inode blocks on the fly for UFS2. + */ + initediblk = ufs_rw32(cgp->cg_initediblk, fsopts->needswap); + if (ffs_opts->version == 2 && + (uint32_t)(cgino + FFS_INOPB(fs)) > initediblk && + initediblk < ufs_rw32(cgp->cg_niblk, fsopts->needswap)) { + memset(buf, 0, fs->fs_bsize); + dip = (struct ufs2_dinode *)buf; + srandom(time(NULL)); + for (i = 0; i < FFS_INOPB(fs); i++) { + dip->di_gen = random() / 2 + 1; + dip++; + } + ffs_wtfs(FFS_FSBTODB(fs, ino_to_fsba(fs, + cg * fs->fs_ipg + initediblk)), + fs->fs_bsize, buf, fsopts); + initediblk += FFS_INOPB(fs); + cgp->cg_initediblk = ufs_rw32(initediblk, fsopts->needswap); + } + + + ffs_wtfs(FFS_FSBTODB(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf, + fsopts); + + /* now write inode */ + d = FFS_FSBTODB(fs, ino_to_fsba(fs, ino)); + ffs_rdfs(d, fs->fs_bsize, buf, fsopts); + if (fsopts->needswap) { + if (ffs_opts->version == 1) + ffs_dinode1_swap(&dp->ffs1_din, + &dp1[ino_to_fsbo(fs, ino)]); + else + ffs_dinode2_swap(&dp->ffs2_din, + &dp2[ino_to_fsbo(fs, ino)]); + } else { + if (ffs_opts->version == 1) + dp1[ino_to_fsbo(fs, ino)] = dp->ffs1_din; + else + dp2[ino_to_fsbo(fs, ino)] = dp->ffs2_din; + } + ffs_wtfs(d, fs->fs_bsize, buf, fsopts); + free(buf); +} + +void +panic(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); + exit(1); +} diff --git a/vendor/bdj-sdk/host/src/makefs_termux/ffs.h b/vendor/bdj-sdk/host/src/makefs_termux/ffs.h new file mode 100644 index 0000000..79223bd --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/ffs.h @@ -0,0 +1,68 @@ +/* $NetBSD: ffs.h,v 1.2 2011/10/09 21:33:43 christos Exp $ */ + +/* + * Copyright (c) 2001-2003 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Luke Mewburn for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ + +#ifndef _FFS_H +#define _FFS_H + +#include +#include + +typedef struct { + char label[MAXVOLLEN]; /* volume name/label */ + int bsize; /* block size */ + int fsize; /* fragment size */ + int cpg; /* cylinders per group */ + int cpgflg; /* cpg was specified by user */ + int density; /* bytes per inode */ + int ntracks; /* number of tracks */ + int nsectors; /* number of sectors */ + int rpm; /* rpm */ + int minfree; /* free space threshold */ + int optimization; /* optimization (space or time) */ + int maxcontig; /* max contiguous blocks to allocate */ + int rotdelay; /* rotational delay between blocks */ + int maxbpg; /* maximum blocks per file in a cyl group */ + int nrpos; /* # of distinguished rotational positions */ + int avgfilesize; /* expected average file size */ + int avgfpdir; /* expected # of files per directory */ + int version; /* filesystem version (1 = FFS, 2 = UFS2) */ + int maxbsize; /* maximum extent size */ + int maxblkspercg; /* max # of blocks per cylinder group */ + /* XXX: support `old' file systems ? */ +} ffs_opt_t; + +#endif /* _FFS_H */ diff --git a/vendor/bdj-sdk/host/src/makefs_termux/getid.c b/vendor/bdj-sdk/host/src/makefs_termux/getid.c new file mode 100644 index 0000000..769b230 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/getid.c @@ -0,0 +1,457 @@ +/* $NetBSD: getid.c,v 1.4 2008/11/06 02:14:52 jschauma Exp $ */ +/* from: NetBSD: getpwent.c,v 1.48 2000/10/03 03:22:26 enami Exp */ +/* from: NetBSD: getgrent.c,v 1.41 2002/01/12 23:51:30 lukem Exp */ + +/* + * Copyright (c) 1987, 1988, 1989, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if HAVE_SYS_PARAM_H +#include +#endif + +#if HAVE_GRP_H +#include +#endif +#if HAVE_LIMITS_H +#include +#endif +#if HAVE_PWD_H +#include +#endif +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_STDIO_H +#include +#endif +#if HAVE_STRING_H +#include +#endif +#if HAVE_TIME_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif + +#include "extern.h" + +static struct group * gi_getgrnam(const char *); +static struct group * gi_getgrgid(gid_t); +static int gi_setgroupent(int); +static void gi_endgrent(void); +static int grstart(void); +static int grscan(int, gid_t, const char *); +static int grmatchline(int, gid_t, const char *); + +static struct passwd * gi_getpwnam(const char *); +static struct passwd * gi_getpwuid(uid_t); +static int gi_setpassent(int); +static void gi_endpwent(void); +static int pwstart(void); +static int pwscan(int, uid_t, const char *); +static int pwmatchline(int, uid_t, const char *); + +#define MAXGRP 200 +#define MAXLINELENGTH 1024 + +static FILE *_gr_fp; +static struct group _gr_group; +static int _gr_stayopen; +static int _gr_filesdone; +static FILE *_pw_fp; +static struct passwd _pw_passwd; /* password structure */ +static int _pw_stayopen; /* keep fd's open */ +static int _pw_filesdone; + +static char grfile[MAXPATHLEN]; +static char pwfile[MAXPATHLEN]; + +static char *members[MAXGRP]; +static char grline[MAXLINELENGTH]; +static char pwline[MAXLINELENGTH]; + +int +setup_getid(const char *dir) +{ + if (dir == NULL) + return (0); + + /* close existing databases */ + gi_endgrent(); + gi_endpwent(); + + /* build paths to new databases */ + snprintf(grfile, sizeof(grfile), "%s/group", dir); + snprintf(pwfile, sizeof(pwfile), "%s/master.passwd", dir); + + /* try to open new databases */ + if (!grstart() || !pwstart()) + return (0); + + /* switch pwcache(3) lookup functions */ + if (pwcache_groupdb(gi_setgroupent, gi_endgrent, + gi_getgrnam, gi_getgrgid) == -1 + || pwcache_userdb(gi_setpassent, gi_endpwent, + gi_getpwnam, gi_getpwuid) == -1) + return (0); + + return (1); +} + + +/* + * group lookup functions + */ + +static struct group * +gi_getgrnam(const char *name) +{ + int rval; + + if (!grstart()) + return NULL; + rval = grscan(1, 0, name); + if (!_gr_stayopen) + endgrent(); + return (rval) ? &_gr_group : NULL; +} + +static struct group * +gi_getgrgid(gid_t gid) +{ + int rval; + + if (!grstart()) + return NULL; + rval = grscan(1, gid, NULL); + if (!_gr_stayopen) + endgrent(); + return (rval) ? &_gr_group : NULL; +} + +static int +gi_setgroupent(int stayopen) +{ + + if (!grstart()) + return 0; + _gr_stayopen = stayopen; + return 1; +} + +static void +gi_endgrent(void) +{ + + _gr_filesdone = 0; + if (_gr_fp) { + (void)fclose(_gr_fp); + _gr_fp = NULL; + } +} + +static int +grstart(void) +{ + + _gr_filesdone = 0; + if (_gr_fp) { + rewind(_gr_fp); + return 1; + } + if (grfile[0] == '\0') /* sanity check */ + return 0; + return (_gr_fp = fopen(grfile, "r")) ? 1 : 0; +} + + +static int +grscan(int search, gid_t gid, const char *name) +{ + + if (_gr_filesdone) + return 0; + for (;;) { + if (!fgets(grline, sizeof(grline), _gr_fp)) { + if (!search) + _gr_filesdone = 1; + return 0; + } + /* skip lines that are too big */ + if (!strchr(grline, '\n')) { + int ch; + + while ((ch = getc(_gr_fp)) != '\n' && ch != EOF) + ; + continue; + } + if (grmatchline(search, gid, name)) + return 1; + } + /* NOTREACHED */ +} + +static int +grmatchline(int search, gid_t gid, const char *name) +{ + unsigned long id; + char **m; + char *cp, *bp, *ep; + + /* name may be NULL if search is nonzero */ + + bp = grline; + memset(&_gr_group, 0, sizeof(_gr_group)); + _gr_group.gr_name = strsep(&bp, ":\n"); + if (search && name && strcmp(_gr_group.gr_name, name)) + return 0; + _gr_group.gr_passwd = strsep(&bp, ":\n"); + if (!(cp = strsep(&bp, ":\n"))) + return 0; + id = strtoul(cp, &ep, 10); + if (id > GID_MAX || *ep != '\0') + return 0; + _gr_group.gr_gid = (gid_t)id; + if (search && name == NULL && _gr_group.gr_gid != gid) + return 0; + cp = NULL; + if (bp == NULL) + return 0; + for (_gr_group.gr_mem = m = members;; bp++) { + if (m == &members[MAXGRP - 1]) + break; + if (*bp == ',') { + if (cp) { + *bp = '\0'; + *m++ = cp; + cp = NULL; + } + } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { + if (cp) { + *bp = '\0'; + *m++ = cp; + } + break; + } else if (cp == NULL) + cp = bp; + } + *m = NULL; + return 1; +} + + +/* + * user lookup functions + */ + +static struct passwd * +gi_getpwnam(const char *name) +{ + int rval; + + if (!pwstart()) + return NULL; + rval = pwscan(1, 0, name); + if (!_pw_stayopen) + endpwent(); + return (rval) ? &_pw_passwd : NULL; +} + +static struct passwd * +gi_getpwuid(uid_t uid) +{ + int rval; + + if (!pwstart()) + return NULL; + rval = pwscan(1, uid, NULL); + if (!_pw_stayopen) + endpwent(); + return (rval) ? &_pw_passwd : NULL; +} + +static int +gi_setpassent(int stayopen) +{ + + if (!pwstart()) + return 0; + _pw_stayopen = stayopen; + return 1; +} + +static void +gi_endpwent(void) +{ + + _pw_filesdone = 0; + if (_pw_fp) { + (void)fclose(_pw_fp); + _pw_fp = NULL; + } +} + +static int +pwstart(void) +{ + + _pw_filesdone = 0; + if (_pw_fp) { + rewind(_pw_fp); + return 1; + } + if (pwfile[0] == '\0') /* sanity check */ + return 0; + return (_pw_fp = fopen(pwfile, "r")) ? 1 : 0; +} + + +static int +pwscan(int search, uid_t uid, const char *name) +{ + + if (_pw_filesdone) + return 0; + for (;;) { + if (!fgets(pwline, sizeof(pwline), _pw_fp)) { + if (!search) + _pw_filesdone = 1; + return 0; + } + /* skip lines that are too big */ + if (!strchr(pwline, '\n')) { + int ch; + + while ((ch = getc(_pw_fp)) != '\n' && ch != EOF) + ; + continue; + } + if (pwmatchline(search, uid, name)) + return 1; + } + /* NOTREACHED */ +} + +static int +pwmatchline(int search, uid_t uid, const char *name) +{ + unsigned long id; + char *cp, *bp, *ep; + + /* name may be NULL if search is nonzero */ + + bp = pwline; + memset(&_pw_passwd, 0, sizeof(_pw_passwd)); + _pw_passwd.pw_name = strsep(&bp, ":\n"); /* name */ + if (search && name && strcmp(_pw_passwd.pw_name, name)) + return 0; + + _pw_passwd.pw_passwd = strsep(&bp, ":\n"); /* passwd */ + + if (!(cp = strsep(&bp, ":\n"))) /* uid */ + return 0; + id = strtoul(cp, &ep, 10); + if (id > UID_MAX || *ep != '\0') + return 0; + _pw_passwd.pw_uid = (uid_t)id; + if (search && name == NULL && _pw_passwd.pw_uid != uid) + return 0; + + if (!(cp = strsep(&bp, ":\n"))) /* gid */ + return 0; + id = strtoul(cp, &ep, 10); + if (id > GID_MAX || *ep != '\0') + return 0; + _pw_passwd.pw_gid = (gid_t)id; + + if (!(ep = strsep(&bp, ":"))) /* class */ + return 0; + if (!(ep = strsep(&bp, ":"))) /* change */ + return 0; + if (!(ep = strsep(&bp, ":"))) /* expire */ + return 0; + + if (!(_pw_passwd.pw_gecos = strsep(&bp, ":\n"))) /* gecos */ + return 0; + if (!(_pw_passwd.pw_dir = strsep(&bp, ":\n"))) /* directory */ + return 0; + if (!(_pw_passwd.pw_shell = strsep(&bp, ":\n"))) /* shell */ + return 0; + + if (strchr(bp, ':') != NULL) + return 0; + + return 1; +} + diff --git a/vendor/bdj-sdk/host/src/makefs_termux/makefs b/vendor/bdj-sdk/host/src/makefs_termux/makefs new file mode 100755 index 0000000..e5f218c Binary files /dev/null and b/vendor/bdj-sdk/host/src/makefs_termux/makefs differ diff --git a/vendor/bdj-sdk/host/src/makefs_termux/makefs.8 b/vendor/bdj-sdk/host/src/makefs_termux/makefs.8 new file mode 100644 index 0000000..92f8fb4 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/makefs.8 @@ -0,0 +1,460 @@ +.\" $NetBSD: makefs.8,v 1.53 2013/08/06 20:16:54 wiz Exp $ +.\" +.\" Copyright (c) 2001-2003 Wasabi Systems, Inc. +.\" All rights reserved. +.\" +.\" Written by Luke Mewburn for Wasabi Systems, Inc. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. 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. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed for the NetBSD Project by +.\" Wasabi Systems, Inc. +.\" 4. The name of Wasabi Systems, Inc. may not be used to endorse +.\" or promote products derived from this software without specific prior +.\" written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC +.\" 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. +.\" +.Dd August 6, 2013 +.Dt MAKEFS 8 +.Os +.Sh NAME +.Nm makefs +.Nd create a file system image from a directory tree +.Sh SYNOPSIS +.Nm +.Op Fl rxZ +.Op Fl B Ar endian +.Op Fl b Ar free-blocks +.Op Fl d Ar debug-mask +.Op Fl F Ar mtree-specfile +.Op Fl f Ar free-files +.Op Fl M Ar minimum-size +.Op Fl m Ar maximum-size +.Op Fl N Ar userdb-dir +.Op Fl O Ar offset +.Op Fl o Ar fs-options +.Op Fl S Ar sector-size +.Op Fl s Ar image-size +.Op Fl t Ar fs-type +.Ar image-file +.Ar directory +.Op Ar extra-directory ... +.Sh DESCRIPTION +The utility +.Nm +creates a file system image into +.Ar image-file +from the directory tree +.Ar directory . +If any optional directory trees are passed in the +.Ar extra-directory +arguments, then the directory tree of each argument will be merged +into the +.Ar directory +first before creating +.Ar image-file . +No special devices or privileges are required to perform this task. +.Pp +The options are as follows: +.Bl -tag -width flag +.It Fl B Ar endian +Set the byte order of the image to +.Ar endian . +Valid byte orders are +.Ql 4321 , +.Ql big , +or +.Ql be +for big endian, and +.Ql 1234 , +.Ql little , +or +.Ql le +for little endian. +Some file systems may have a fixed byte order; in those cases this +argument will be ignored. +.It Fl b Ar free-blocks +Ensure that a minimum of +.Ar free-blocks +free blocks exist in the image. +An optional +.Ql % +suffix may be provided to indicate that +.Ar free-blocks +indicates a percentage of the calculated image size. +.It Fl d Ar debug-mask +Enable various levels of debugging, depending upon which bits are +set in +.Ar debug-mask . +XXX: document these +.It Fl F Ar mtree-specfile +Use +.Ar mtree-specfile +as an +.Xr mtree 8 +.Sq specfile +specification. +.Pp +If a specfile entry exists in the underlying file system, its +permissions and modification time will be used unless specifically +overridden by the specfile. +An error will be raised if the type of entry in the specfile +conflicts with that of an existing entry. +.Pp +In the opposite case (where a specfile entry does not have an entry +in the underlying file system) the following occurs: +If the specfile entry is marked +.Sy optional , +the specfile entry is ignored. +Otherwise, the entry will be created in the image, and it is +necessary to specify at least the following parameters in the +specfile: +.Sy type , +.Sy mode , +.Sy gname , +or +.Sy gid , +and +.Sy uname +or +.Sy uid , +.Sy device +(in the case of block or character devices), and +.Sy link +(in the case of symbolic links). +If +.Sy time +isn't provided, the current time will be used. +If +.Sy flags +isn't provided, the current file flags will be used. +Missing regular file entries will be created as zero-length files. +.It Fl f Ar free-files +Ensure that a minimum of +.Ar free-files +free files (inodes) exist in the image. +An optional +.Ql % +suffix may be provided to indicate that +.Ar free-files +indicates a percentage of the calculated image size. +.It Fl M Ar minimum-size +Set the minimum size of the file system image to +.Ar minimum-size . +.It Fl m Ar maximum-size +Set the maximum size of the file system image to +.Ar maximum-size . +An error will be raised if the target file system needs to be larger +than this to accommodate the provided directory tree. +.It Fl N Ar userdb-dir +Use the user database text file +.Pa master.passwd +and group database text file +.Pa group +from +.Ar userdb-dir , +rather than using the results from the system's +.Xr getpwnam 3 +and +.Xr getgrnam 3 +(and related) library calls. +.It Fl O Ar offset +Instead of creating the filesystem at the beginning of the file, start +at offset. +Valid only for +.Sy ffs +and +.Sy msdos . +.It Fl o Ar fs-options +Set file system specific options. +.Ar fs-options +is a comma separated list of options. +Valid file system specific options are detailed below. +.It Fl r +When merging multiple directories replace duplicate files with the last found. +.It Fl S Ar sector-size +Set the file system sector size to +.Ar sector-size . +.\" XXX: next line also true for cd9660? +Defaults to 512. +.It Fl s Ar image-size +Set the size of the file system image to +.Ar image-size . +.It Fl t Ar fs-type +Create an +.Ar fs-type +file system image. +The following file system types are supported: +.Bl -tag -width cd9660 -offset indent +.It Sy ffs +BSD fast file system (default). +.It Sy cd9660 +ISO 9660 file system. +.It Sy chfs +Chip flash file system. +.It Sy msdos +FAT12, FAT16, or FAT32 file system. +.It Sy v7fs +7th Edition(V7) file system. +.It Sy udf +ISO/Ecma UDF file system. +.El +.It Fl x +Exclude file system nodes not explicitly listed in the specfile. +.It Fl Z +Create a sparse file for +.Sy ffs . +This is useful for virtual machine images. +.El +.Pp +Where sizes are specified, a decimal number of bytes is expected. +Two or more numbers may be separated by an +.Dq x +to indicate a product. +Each number may have one of the following optional suffixes: +.Bl -tag -width 3n -offset indent -compact +.It b +Block; multiply by 512 +.It k +Kibi; multiply by 1024 (1 KiB) +.It m +Mebi; multiply by 1048576 (1 MiB) +.It g +Gibi; multiply by 1073741824 (1 GiB) +.It t +Tebi; multiply by 1099511627776 (1 TiB) +.It w +Word; multiply by the number of bytes in an integer +.El +.\" +.\" +.Ss FFS-specific options +.Sy ffs +images have ffs-specific optional parameters that may be provided. +Each of the options consists of a keyword, an equal sign +.Pq Ql = , +and a value. +The following keywords are supported: +.Pp +.Bl -tag -width optimization -offset indent -compact +.It Sy avgfilesize +Expected average file size. +.It Sy avgfpdir +Expected number of files per directory. +.It Sy bsize +Block size. +.It Sy density +Bytes per inode. +.It Sy fsize +Fragment size. +.It Sy label +Label name of the image. +.It Sy maxbpg +Maximum blocks per file in a cylinder group. +.It Sy minfree +Minimum % free. +.It Sy optimization +Optimization preference; one of +.Ql space +or +.Ql time . +.It Sy extent +Maximum extent size. +.It Sy maxbpcg +Maximum total number of blocks in a cylinder group. +.It Sy version +UFS version. +1 for FFS (default), 2 for UFS2. +.El +.Ss CD9660-specific options +.Sy cd9660 +images have ISO9660-specific optional parameters that may be +provided. +The arguments consist of a keyword and, optionally, an equal sign +.Pq Ql = , +and a value. +The following keywords are supported: +.Pp +.Bl -tag -width omit-trailing-period -offset indent -compact +.It Sy allow-deep-trees +Allow the directory structure to exceed the maximum specified in +the spec. +.\" .It Sy allow-illegal-chars +.\" Unknown +.\" .It Sy allow-lowercase +.\" Unknown +.It Sy allow-max-name +Allow 37 instead of 33 characters for filenames by omitting the +version id. +.It Sy allow-multidot +Allow multiple dots in a filename. +.It Sy applicationid +Application ID of the image. +.It Sy archimedes +Use the +.Ql ARCHIMEDES +extension to encode +.Tn RISC OS +metadata. +.It Sy chrp-boot +Write an MBR partition table to the image to allow older CHRP hardware to +boot. +.It Sy boot-load-segment +Set load segment for the boot image. +.It Sy bootimage +Filename of a boot image in the format +.Dq sysid;filename , +where +.Dq sysid +is one of +.Ql i386 , +.Ql mac68k , +.Ql macppc , +or +.Ql powerpc . +.It Sy generic-bootimage +Load a generic boot image into the first 32K of the cd9660 image. +.It Sy hard-disk-boot +Boot image is a hard disk image. +.It Sy keep-bad-images +Don't throw away images whose write was aborted due to an error. +For debugging purposes. +.It Sy label +Label name of the image. +.It Sy no-boot +Boot image is not bootable. +.It Sy no-emul-boot +Boot image is a +.Dq no emulation +ElTorito image. +.It Sy no-trailing-padding +Do not pad the image (apparently Linux needs the padding). +.\" .It Sy omit-trailing-period +.\" Unknown +.It Sy preparer +Preparer ID of the image. +.It Sy publisher +Publisher ID of the image. +.It Sy rockridge +Use RockRidge extensions (for longer filenames, etc.). +.It Sy volumeid +Volume set identifier of the image. +.El +.Ss CHFS-specific options +.Sy chfs +images have chfs-specific optional parameters that may be provided. +Each of the options consists of a keyword, an equal sign +.Pq Ql = , +and a value. +The following keywords are supported: +.Pp +.Bl -tag -width optimization -offset indent -compact +.It Sy pagesize +Pagesize. +.It Sy erasesize +Erase block size of the media. +.It Sy mediatype +Type of the media. +NOR: 0 or NAND: 1. +.El +.Ss msdos-specific options +See +.Xr newfs_msdos 8 +for fs specific options. +.Ss V7FS-specific options +The following keywords are supported: +.Pp +.Bl -tag -width optimization -offset indent -compact +.It Sy pdp +PDP endian. +.It Sy progress +Display a progress meter for the file system construction and file +population. +.El +.Ss UDF-specific options +.Sy udf +images have udf-specific optional parameters that may be provided. +Each of the options consists of a keyword, an equal sign +.Pq Ql = , +and a value. +The following keywords are supported: +.Pp +.Bl -tag -width optimization -compact +.It Sy disctype +This can have the following values: +.Bl -tag -width cdromXdvdromXbdromXXX -compact +.It Sy cdrom , Sy dvdrom , Sy bdrom +create a read-only fs +.It Sy dvdram , Sy bdre , Sy disk +create a rewritable fs without sparing for defective sectors +.It Sy cdr , Sy dvdr , Sy bdr +create a rewritable fs on once recordable media using a VAT +.It Sy cdrw , Sy dvdrw +create a rewritable fs with sparing for defective sectors +.El +When an optical media is selected here, the sectorsize and the default disc +size is assumed unless given explicitly. +For rom images the disc size is the minimum needed. +.It Sy loglabel +Set the logical volume label of the disc to the specified argument. +.It Sy discid +Set the physical volume label of the disc to the specified argument. +Prepend the physical volume label with a volumeset label separated +with a ':' if wanted. +For strict conformance and interchange, don't set the volumeset label +manually unless it has an unique hex number in the first 8 character +positions. +.It Sy minver +Set the minimum UDF version to be used. +Choose UDF version numbers from 0x102, 0x150, 0x200, and 0x201. +Versions 0x250 and 0x260 are currently not supported +in +.Nm . +.El +.Sh SEE ALSO +.Xr strsuftoll 3 , +.Xr installboot 8 , +.Xr mtree 8 , +.Xr newfs 8 +.Sh HISTORY +The +.Nm +utility appeared in +.Nx 1.6 . +.Sh AUTHORS +.An Luke Mewburn +.Aq lukem@NetBSD.org +(original program), +.An Daniel Watt , +.An Walter Deignan , +.An Ryan Gabrys , +.An Alan Perez-Rathke , +.An Ram Vedam +(cd9660 support), +.An UCHIYAMA Yasushi +(v7fs support), +.An Tamas Toth +(chfs support). +.An Christos Zoulas +(msdos support). +.An Reinoud Zandijk +(udf support). diff --git a/vendor/bdj-sdk/host/src/makefs_termux/makefs.c b/vendor/bdj-sdk/host/src/makefs_termux/makefs.c new file mode 100644 index 0000000..d9f0d5d --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/makefs.c @@ -0,0 +1,446 @@ +/* $NetBSD: makefs.c,v 1.50 2013/08/05 14:41:57 reinoud Exp $ */ + +/* + * Copyright (c) 2001-2003 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Luke Mewburn for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if defined(__RCSID) && !defined(__lint) +__RCSID("$NetBSD: makefs.c,v 1.50 2013/08/05 14:41:57 reinoud Exp $"); +#endif /* !__lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" + +#include + +#include "makefs.h" +#include "mtree.h" +//#include "cd9660.h" + +long long strsuftoll(const char *desc, const char *val, long long min, + long long max); + +/* + * list of supported file systems and dispatch functions + */ +typedef struct { + const char *type; + void (*prepare_options)(fsinfo_t *); + int (*parse_options)(const char *, fsinfo_t *); + void (*cleanup_options)(fsinfo_t *); + void (*make_fs)(const char *, const char *, fsnode *, + fsinfo_t *); +} fstype_t; + +static fstype_t fstypes[] = { +#define ENTRY(name) { \ + # name, name ## _prep_opts, name ## _parse_opts, \ + name ## _cleanup_opts, name ## _makefs \ +} +#if 0 + ENTRY(ffs), + ENTRY(cd9660), + ENTRY(chfs), + ENTRY(v7fs), + ENTRY(msdos), +#endif + ENTRY(udf), + { .type = NULL }, +}; + +u_int debug; +struct timespec start_time; + +static fstype_t *get_fstype(const char *); +static void usage(fstype_t *, fsinfo_t *); + +int +main(int argc, char *argv[]) +{ + struct timeval start; + fstype_t *fstype; + fsinfo_t fsoptions; + fsnode *root; + int ch, i, len; + char *specfile; + + setprogname(argv[0]); + + debug = 0; + if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL) + errx(1, "Unknown default fs type `%s'.", DEFAULT_FSTYPE); + + /* set default fsoptions */ + (void)memset(&fsoptions, 0, sizeof(fsoptions)); + fsoptions.fd = -1; + fsoptions.sectorsize = -1; + + if (fstype->prepare_options) + fstype->prepare_options(&fsoptions); + + specfile = NULL; + if (gettimeofday(&start, NULL) == -1) + err(1, "Unable to get system time"); + + start_time.tv_sec = start.tv_sec; + start_time.tv_nsec = start.tv_usec * 1000; + + while ((ch = getopt(argc, argv, "B:b:d:f:F:M:m:N:O:o:rs:S:t:xZ")) != -1) { + switch (ch) { + + case 'B': + if (strcmp(optarg, "be") == 0 || + strcmp(optarg, "4321") == 0 || + strcmp(optarg, "big") == 0) { +#if BYTE_ORDER == LITTLE_ENDIAN + fsoptions.needswap = 1; +#endif + } else if (strcmp(optarg, "le") == 0 || + strcmp(optarg, "1234") == 0 || + strcmp(optarg, "little") == 0) { +#if BYTE_ORDER == BIG_ENDIAN + fsoptions.needswap = 1; +#endif + } else { + warnx("Invalid endian `%s'.", optarg); + usage(fstype, &fsoptions); + } + break; + + case 'b': + len = strlen(optarg) - 1; + if (optarg[len] == '%') { + optarg[len] = '\0'; + fsoptions.freeblockpc = + strsuftoll("free block percentage", + optarg, 0LL, 99); + } else { + fsoptions.freeblocks = + strsuftoll("free blocks", + optarg, 0LL, LLONG_MAX); + } + break; + + case 'd': + debug = strtoll(optarg, NULL, 0); + break; + + case 'f': + len = strlen(optarg) - 1; + if (optarg[len] == '%') { + optarg[len] = '\0'; + fsoptions.freefilepc = + strsuftoll("free file percentage", + optarg, 0, 99); + } else { + fsoptions.freefiles = + strsuftoll("free files", + optarg, 0, LLONG_MAX); + } + break; + + case 'F': + specfile = optarg; + break; + + case 'M': + fsoptions.minsize = + strsuftoll("minimum size", optarg, 1LL, LLONG_MAX); + break; + + case 'N': + // if (! setup_getid(optarg)) + errx(1, + "Unable to use user and group databases in `%s'", + optarg); + break; + + case 'm': + fsoptions.maxsize = + strsuftoll("maximum size", optarg, 1LL, LLONG_MAX); + break; + + case 'O': + fsoptions.offset = + strsuftoll("offset", optarg, 0LL, LLONG_MAX); + break; + + case 'o': + { + char *p; + + while ((p = strsep(&optarg, ",")) != NULL) { + if (*p == '\0') + errx(1, "Empty option"); + if (! fstype->parse_options(p, &fsoptions)) + usage(fstype, &fsoptions); + } + break; + } + + case 'r': + fsoptions.replace = 1; + break; + + case 's': + fsoptions.minsize = fsoptions.maxsize = + strsuftoll("size", optarg, 1LL, LLONG_MAX); + break; + + case 'S': + fsoptions.sectorsize = + (int)strsuftoll("sector size", optarg, + 1LL, INT_MAX); + break; + + case 't': + /* Check current one and cleanup if necessary. */ + if (fstype->cleanup_options) + fstype->cleanup_options(&fsoptions); + fsoptions.fs_specific = NULL; + if ((fstype = get_fstype(optarg)) == NULL) + errx(1, "Unknown fs type `%s'.", optarg); + fstype->prepare_options(&fsoptions); + break; + + case 'x': + fsoptions.onlyspec = 1; + break; + + case 'Z': + fsoptions.sparse = 1; + break; + + case '?': + default: + usage(fstype, &fsoptions); + /* NOTREACHED */ + + } + } + if (debug) { + printf("debug mask: 0x%08x\n", debug); + printf("start time: %ld.%ld, %s", + (long)start_time.tv_sec, (long)start_time.tv_nsec, + ctime(&start_time.tv_sec)); + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(fstype, &fsoptions); + + /* -x must be accompanied by -F */ + if (fsoptions.onlyspec != 0 && specfile == NULL) + errx(1, "-x requires -F mtree-specfile."); + + /* walk the tree */ + TIMER_START(start); + root = walk_dir(argv[1], ".", NULL, NULL, fsoptions.replace); + TIMER_RESULTS(start, "walk_dir"); + + /* append extra directory */ + for (i = 2; i < argc; i++) { + struct stat sb; + if (stat(argv[i], &sb) == -1) + err(1, "Can't stat `%s'", argv[i]); + if (!S_ISDIR(sb.st_mode)) + errx(1, "%s: not a directory", argv[i]); + TIMER_START(start); + root = walk_dir(argv[i], ".", NULL, root, fsoptions.replace); + TIMER_RESULTS(start, "walk_dir2"); + } + + if (specfile) { /* apply a specfile */ + TIMER_START(start); + // apply_specfile(specfile, argv[1], root, fsoptions.onlyspec); + TIMER_RESULTS(start, "apply_specfile"); + } + + if (debug & DEBUG_DUMP_FSNODES) { + printf("\nparent: %s\n", argv[1]); + dump_fsnodes(root); + putchar('\n'); + } + + /* build the file system */ + TIMER_START(start); + fstype->make_fs(argv[0], argv[1], root, &fsoptions); + TIMER_RESULTS(start, "make_fs"); + + free_fsnodes(root); + + exit(0); + /* NOTREACHED */ +} + +int +set_option(const option_t *options, const char *option, char *buf, size_t len) +{ + char *var, *val; + int retval; + + assert(option != NULL); + + var = strdup(option); + for (val = var; *val; val++) + if (*val == '=') { + *val++ = '\0'; + break; + } + retval = set_option_var(options, var, val, buf, len); + free(var); + return retval; +} + +int +set_option_var(const option_t *options, const char *var, const char *val, + char *buf, size_t len) +{ + char *s; + size_t i; + +#define NUM(type) \ + if (!*val) { \ + *(type *)options[i].value = 1; \ + break; \ + } \ + *(type *)options[i].value = (type)strsuftoll(options[i].desc, val, \ + options[i].minimum, options[i].maximum); break + + for (i = 0; options[i].name != NULL; i++) { + if (var[1] == '\0') { + if (options[i].letter != var[0]) + continue; + } else if (strcmp(options[i].name, var) != 0) + continue; + switch (options[i].type) { + case OPT_BOOL: + *(bool *)options[i].value = 1; + break; + case OPT_STRARRAY: + strlcpy((void *)options[i].value, val, (size_t) + options[i].maximum); + break; + case OPT_STRPTR: + s = strdup(val); + *(char **)options[i].value = s; + break; + case OPT_STRBUF: + if (buf == NULL) + abort(); + strlcpy(buf, val, len); + break; + case OPT_INT64: + NUM(uint64_t); + case OPT_INT32: + NUM(uint32_t); + case OPT_INT16: + NUM(uint16_t); + case OPT_INT8: + NUM(uint8_t); + default: + warnx("Unknown type %d in option %s", options[i].type, + val); + return 0; + } + return i; + } + warnx("Unknown option `%s'", var); + return -1; +} + + +static fstype_t * +get_fstype(const char *type) +{ + int i; + + for (i = 0; fstypes[i].type != NULL; i++) + if (strcmp(fstypes[i].type, type) == 0) + return (&fstypes[i]); + return (NULL); +} + +option_t * +copy_opts(const option_t *o) +{ + size_t i; + for (i = 0; o[i].name; i++) + continue; + i++; + return memcpy(calloc(i, sizeof(*o)), o, i * sizeof(*o)); +} + +static void +usage(fstype_t *fstype, fsinfo_t *fsoptions) +{ + const char *prog; + + prog = getprogname(); + fprintf(stderr, +"Usage: %s [-rxZ] [-B endian] [-b free-blocks] [-d debug-mask]\n" +"\t[-F mtree-specfile] [-f free-files] [-M minimum-size] [-m maximum-size]\n" +"\t[-N userdb-dir] [-O offset] [-o fs-options] [-S sector-size]\n" +"\t[-s image-size] [-t fs-type] image-file directory [extra-directory ...]\n", + ""); + + if (fstype) { + size_t i; + option_t *o = fsoptions->fs_options; + + fprintf(stderr, "\n%s specific options:\n", fstype->type); + for (i = 0; o[i].name != NULL; i++) + fprintf(stderr, "\t%c%c%20.20s\t%s\n", + o[i].letter ? o[i].letter : ' ', + o[i].letter ? ',' : ' ', + o[i].name, o[i].desc); + } + exit(1); +} diff --git a/vendor/bdj-sdk/host/src/makefs_termux/makefs.h b/vendor/bdj-sdk/host/src/makefs_termux/makefs.h new file mode 100644 index 0000000..efc1fe5 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/makefs.h @@ -0,0 +1,267 @@ +/* $NetBSD: makefs.h,v 1.35 2013/08/05 14:41:57 reinoud Exp $ */ + +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Luke Mewburn for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ + +#ifndef _MAKEFS_H +#define _MAKEFS_H + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#else +#define HAVE_STRUCT_STAT_ST_FLAGS 1 +#define HAVE_STRUCT_STAT_ST_GEN 1 +#define HAVE_STRUCT_STAT_ST_MTIMENSEC 1 +#define HAVE_STRUCT_STATVFS_F_IOSIZE 1 +#define HAVE_STRUCT_STAT_BIRTHTIME 1 +#define HAVE_FSTATVFS 1 +#endif + +#include +#include + +/* + * fsnode - + * a component of the tree; contains a filename, a pointer to + * fsinode, optional symlink name, and tree pointers + * + * fsinode - + * equivalent to an inode, containing target file system inode number, + * refcount (nlink), and stat buffer + * + * A tree of fsnodes looks like this: + * + * name "." "bin" "netbsd" + * type S_IFDIR S_IFDIR S_IFREG + * next > > NULL + * parent NULL NULL NULL + * child NULL v + * + * name "." "ls" + * type S_IFDIR S_IFREG + * next > NULL + * parent ^ ^ (to "bin") + * child NULL NULL + * + * Notes: + * - first always points to first entry, at current level, which + * must be "." when the tree has been built; during build it may + * not be if "." hasn't yet been found by readdir(2). + */ + +enum fi_flags { + FI_SIZED = 1<<0, /* inode sized */ + FI_ALLOCATED = 1<<1, /* fsinode->ino allocated */ + FI_WRITTEN = 1<<2, /* inode written */ +}; + +typedef struct { + uint32_t ino; /* inode number used on target fs */ + uint32_t nlink; /* number of links to this entry */ + enum fi_flags flags; /* flags used by fs specific code */ + struct stat st; /* stat entry */ + void *fsuse; /* for storing FS dependent info */ +} fsinode; + +typedef struct _fsnode { + struct _fsnode *parent; /* parent (NULL if root) */ + struct _fsnode *child; /* child (if type == S_IFDIR) */ + struct _fsnode *next; /* next */ + struct _fsnode *first; /* first node of current level (".") */ + uint32_t type; /* type of entry */ + fsinode *inode; /* actual inode data */ + char *symlink; /* symlink target */ + const char *root; /* root path */ + char *path; /* directory name */ + char *name; /* file name */ + int flags; /* misc flags */ +} fsnode; + +#define FSNODE_F_HASSPEC 0x01 /* fsnode has a spec entry */ + +/* + * option_t - contains option name, description, pointer to location to store + * result, and range checks for the result. Used to simplify fs specific + * option setting + */ +typedef enum { + OPT_STRARRAY, + OPT_STRPTR, + OPT_STRBUF, + OPT_BOOL, + OPT_INT8, + OPT_INT16, + OPT_INT32, + OPT_INT64 +} opttype_t; + +typedef struct { + char letter; /* option letter NUL for none */ + const char *name; /* option name */ + void *value; /* where to stuff the value */ + opttype_t type; /* type of entry */ + long long minimum; /* minimum for value */ + long long maximum; /* maximum for value */ + const char *desc; /* option description */ +} option_t; + +/* + * fsinfo_t - contains various settings and parameters pertaining to + * the image, including current settings, global options, and fs + * specific options + */ +typedef struct makefs_fsinfo { + /* current settings */ + off_t size; /* total size */ + off_t inodes; /* number of inodes */ + uint32_t curinode; /* current inode */ + + /* image settings */ + int fd; /* file descriptor of image */ + void *superblock; /* superblock */ + int onlyspec; /* only add entries in specfile */ + + + /* global options */ + off_t minsize; /* minimum size image should be */ + off_t maxsize; /* maximum size image can be */ + off_t freefiles; /* free file entries to leave */ + off_t freeblocks; /* free blocks to leave */ + off_t offset; /* offset from start of file */ + int freefilepc; /* free file % */ + int freeblockpc; /* free block % */ + int needswap; /* non-zero if byte swapping needed */ + int sectorsize; /* sector size */ + int sparse; /* sparse image, don't fill it with zeros */ + int replace; /* replace files when merging */ + + void *fs_specific; /* File system specific additions. */ + option_t *fs_options; /* File system specific options */ +} fsinfo_t; + + + + +void apply_specfile(const char *, const char *, fsnode *, int); +void dump_fsnodes(fsnode *); +const char * inode_type(mode_t); +int set_option(const option_t *, const char *, char *, size_t); +int set_option_var(const option_t *, const char *, const char *, + char *, size_t); +fsnode * walk_dir(const char *, const char *, fsnode *, fsnode *, int); +void free_fsnodes(fsnode *); +option_t * copy_opts(const option_t *); + +#define DECLARE_FUN(fs) \ +void fs ## _prep_opts(fsinfo_t *); \ +int fs ## _parse_opts(const char *, fsinfo_t *); \ +void fs ## _cleanup_opts(fsinfo_t *); \ +void fs ## _makefs(const char *, const char *, fsnode *, fsinfo_t *) + +DECLARE_FUN(ffs); +DECLARE_FUN(cd9660); +DECLARE_FUN(chfs); +DECLARE_FUN(v7fs); +DECLARE_FUN(msdos); +DECLARE_FUN(udf); + +extern u_int debug; +extern struct timespec start_time; + +/* + * If -x is specified, we want to exclude nodes which do not appear + * in the spec file. + */ +#define FSNODE_EXCLUDE_P(opts, fsnode) \ + ((opts)->onlyspec != 0 && ((fsnode)->flags & FSNODE_F_HASSPEC) == 0) + +#define DEBUG_TIME 0x00000001 + /* debug bits 1..3 unused at this time */ +#define DEBUG_WALK_DIR 0x00000010 +#define DEBUG_WALK_DIR_NODE 0x00000020 +#define DEBUG_WALK_DIR_LINKCHECK 0x00000040 +#define DEBUG_DUMP_FSNODES 0x00000080 +#define DEBUG_DUMP_FSNODES_VERBOSE 0x00000100 +#define DEBUG_FS_PARSE_OPTS 0x00000200 +#define DEBUG_FS_MAKEFS 0x00000400 +#define DEBUG_FS_VALIDATE 0x00000800 +#define DEBUG_FS_CREATE_IMAGE 0x00001000 +#define DEBUG_FS_SIZE_DIR 0x00002000 +#define DEBUG_FS_SIZE_DIR_NODE 0x00004000 +#define DEBUG_FS_SIZE_DIR_ADD_DIRENT 0x00008000 +#define DEBUG_FS_POPULATE 0x00010000 +#define DEBUG_FS_POPULATE_DIRBUF 0x00020000 +#define DEBUG_FS_POPULATE_NODE 0x00040000 +#define DEBUG_FS_WRITE_FILE 0x00080000 +#define DEBUG_FS_WRITE_FILE_BLOCK 0x00100000 +#define DEBUG_FS_MAKE_DIRBUF 0x00200000 +#define DEBUG_FS_WRITE_INODE 0x00400000 +#define DEBUG_BUF_BREAD 0x00800000 +#define DEBUG_BUF_BWRITE 0x01000000 +#define DEBUG_BUF_GETBLK 0x02000000 +#define DEBUG_APPLY_SPECFILE 0x04000000 +#define DEBUG_APPLY_SPECENTRY 0x08000000 +#define DEBUG_APPLY_SPECONLY 0x10000000 + + +#define TIMER_START(x) \ + if (debug & DEBUG_TIME) \ + gettimeofday(&(x), NULL) + +#define TIMER_RESULTS(x,d) \ + if (debug & DEBUG_TIME) { \ + struct timeval end, td; \ + gettimeofday(&end, NULL); \ + timersub(&end, &(x), &td); \ + printf("%s took %lld.%06ld seconds\n", \ + (d), (long long)td.tv_sec, \ + (long)td.tv_usec); \ + } + + +#ifndef DEFAULT_FSTYPE +#define DEFAULT_FSTYPE "udf" +#endif + + +/* + * ffs specific settings + * --------------------- + */ + +#define FFS_EI /* for opposite endian support in ffs headers */ + + +#endif /* _MAKEFS_H */ diff --git a/vendor/bdj-sdk/host/src/makefs_termux/misc.c b/vendor/bdj-sdk/host/src/makefs_termux/misc.c new file mode 100644 index 0000000..25e6eab --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/misc.c @@ -0,0 +1,326 @@ +/* $NetBSD: misc.c,v 1.3 2008/11/06 02:14:52 jschauma Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)misc.c 8.1 (Berkeley) 6/6/93 + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +// #include +#if HAVE_SYS_CDEFS_H +#include +#endif +#if defined(__RCSID) && !defined(lint) +__RCSID("$NetBSD: misc.c,v 1.3 2008/11/06 02:14:52 jschauma Exp $"); +#endif /* not lint */ + +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif + +#if HAVE_STDARG_H +#include +#endif +#if HAVE_STDIO_H +#include +#endif +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_STRING_H +#include +#endif + +#include "extern.h" + +typedef struct _key { + const char *name; /* key name */ + u_int val; /* value */ + +#define NEEDVALUE 0x01 + u_int flags; +} KEY; +#if 1 +/* NB: the following tables must be sorted lexically. */ +static KEY keylist[] = { + {"cksum", F_CKSUM, NEEDVALUE}, + {"device", F_DEV, NEEDVALUE}, + {"flags", F_FLAGS, NEEDVALUE}, + {"gid", F_GID, NEEDVALUE}, + {"gname", F_GNAME, NEEDVALUE}, + {"ignore", F_IGN, 0}, + {"link", F_SLINK, NEEDVALUE}, + {"md5", F_MD5, NEEDVALUE}, + {"md5digest", F_MD5, NEEDVALUE}, + {"mode", F_MODE, NEEDVALUE}, + {"nlink", F_NLINK, NEEDVALUE}, + {"optional", F_OPT, 0}, + {"rmd160", F_RMD160, NEEDVALUE}, + {"rmd160digest",F_RMD160, NEEDVALUE}, + {"sha1", F_SHA1, NEEDVALUE}, + {"sha1digest", F_SHA1, NEEDVALUE}, + {"sha256", F_SHA256, NEEDVALUE}, + {"sha256digest",F_SHA256, NEEDVALUE}, + {"sha384", F_SHA384, NEEDVALUE}, + {"sha384digest",F_SHA384, NEEDVALUE}, + {"sha512", F_SHA512, NEEDVALUE}, + {"sha512digest",F_SHA512, NEEDVALUE}, + {"size", F_SIZE, NEEDVALUE}, + {"tags", F_TAGS, NEEDVALUE}, + {"time", F_TIME, NEEDVALUE}, + {"type", F_TYPE, NEEDVALUE}, + {"uid", F_UID, NEEDVALUE}, + {"uname", F_UNAME, NEEDVALUE} +}; +#endif +static KEY typelist[] = { + {"block", F_BLOCK, 0}, + {"char", F_CHAR, 0}, + {"dir", F_DIR, 0}, +#ifdef S_IFDOOR + {"door", F_DOOR, 0}, +#endif + {"fifo", F_FIFO, 0}, + {"file", F_FILE, 0}, + {"link", F_LINK, 0}, + {"socket", F_SOCK, 0}, +}; + +slist_t excludetags, includetags; +int keys = KEYDEFAULT; + + +int keycompare(const void *, const void *); + +u_int +parsekey(const char *name, int *needvaluep) +{ + static int allbits; + KEY *k, tmp; + + if (allbits == 0) { + int i; + + for (i = 0; i < sizeof(keylist) / sizeof(KEY); i++) + allbits |= keylist[i].val; + } + tmp.name = name; + if (strcmp(name, "all") == 0) + return (allbits); + k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY), + sizeof(KEY), keycompare); + if (k == NULL) + mtree_err("unknown keyword `%s'", name); + + if (needvaluep) + *needvaluep = k->flags & NEEDVALUE ? 1 : 0; + + return (k->val); +} + +u_int +parsetype(const char *name) +{ + KEY *k, tmp; + + tmp.name = name; + k = (KEY *)bsearch(&tmp, typelist, sizeof(typelist) / sizeof(KEY), + sizeof(KEY), keycompare); + if (k == NULL) + mtree_err("unknown file type `%s'", name); + + return (k->val); +} + +int +keycompare(const void *a, const void *b) +{ + + return (strcmp(((const KEY *)a)->name, ((const KEY *)b)->name)); +} + +void +mtree_err(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); + if (mtree_lineno) + warnx("failed at line %lu of the specification", + (u_long) mtree_lineno); + exit(1); + /* NOTREACHED */ +} + +void +addtag(slist_t *list, char *elem) +{ + +#define TAG_CHUNK 20 + + if ((list->count % TAG_CHUNK) == 0) { + char **new; + + new = (char **)realloc(list->list, (list->count + TAG_CHUNK) + * sizeof(char *)); + if (new == NULL) + mtree_err("memory allocation error"); + list->list = new; + } + list->list[list->count] = elem; + list->count++; +} + +void +parsetags(slist_t *list, char *args) +{ + char *p, *e; + int len; + + if (args == NULL) { + addtag(list, NULL); + return; + } + while ((p = strsep(&args, ",")) != NULL) { + if (*p == '\0') + continue; + len = strlen(p) + 3; /* "," + p + ",\0" */ + if ((e = malloc(len)) == NULL) + mtree_err("memory allocation error"); + snprintf(e, len, ",%s,", p); + addtag(list, e); + } +} + +/* + * matchtags + * returns 0 if there's a match from the exclude list in the node's tags, + * or there's an include list and no match. + * return 1 otherwise. + */ +int +matchtags(NODE *node) +{ + int i; + + if (node->tags) { + for (i = 0; i < excludetags.count; i++) + if (strstr(node->tags, excludetags.list[i])) + break; + if (i < excludetags.count) + return (0); + + for (i = 0; i < includetags.count; i++) + if (strstr(node->tags, includetags.list[i])) + break; + if (i > 0 && i == includetags.count) + return (0); + } else if (includetags.count > 0) { + return (0); + } + return (1); +} + +u_int +nodetoino(u_int type) +{ + + switch (type) { + case F_BLOCK: + return S_IFBLK; + case F_CHAR: + return S_IFCHR; + case F_DIR: + return S_IFDIR; + case F_FIFO: + return S_IFIFO; + case F_FILE: + return S_IFREG; + case F_LINK: + return S_IFLNK; +#ifdef S_IFSOCK + case F_SOCK: + return S_IFSOCK; +#endif + default: + printf("unknown type %d", type); + abort(); + } + /* NOTREACHED */ +} + +const char * +nodetype(u_int type) +{ + + return (inotype(nodetoino(type))); +} + + +const char * +inotype(u_int type) +{ + + switch (type & S_IFMT) { + case S_IFBLK: + return ("block"); + case S_IFCHR: + return ("char"); + case S_IFDIR: + return ("dir"); + case S_IFIFO: + return ("fifo"); + case S_IFREG: + return ("file"); + case S_IFLNK: + return ("link"); +#ifdef S_IFSOCK + case S_IFSOCK: + return ("socket"); +#endif +#ifdef S_IFDOOR + case S_IFDOOR: + return ("door"); +#endif + default: + return ("unknown"); + } + /* NOTREACHED */ +} diff --git a/vendor/bdj-sdk/host/src/makefs_termux/msdos.c b/vendor/bdj-sdk/host/src/makefs_termux/msdos.c new file mode 100644 index 0000000..a445f43 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/msdos.c @@ -0,0 +1,254 @@ +/* $NetBSD: msdos.c,v 1.15 2015/10/16 16:40:02 christos Exp $ */ + +/*- + * Copyright (c) 2013 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if defined(__RCSID) && !defined(__lint) +__RCSID("$NetBSD: msdos.c,v 1.15 2015/10/16 16:40:02 christos Exp $"); +#endif /* !__lint */ + +#include + +#if !HAVE_NBTOOL_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "makefs.h" +#include "msdos.h" +#include "mkfs_msdos.h" + +static int msdos_populate_dir(const char *, struct denode *, fsnode *, + fsnode *, fsinfo_t *); + +void +msdos_prep_opts(fsinfo_t *fsopts) +{ + struct msdos_options *msdos_opt = ecalloc(1, sizeof(*msdos_opt)); + const option_t msdos_options[] = { +#define AOPT(_opt, _type, _name, _min, _desc) { \ + .letter = _opt, \ + .name = # _name, \ + .type = _min == -1 ? OPT_STRPTR : \ + (_min == -2 ? OPT_BOOL : \ + (sizeof(_type) == 1 ? OPT_INT8 : \ + (sizeof(_type) == 2 ? OPT_INT16 : \ + (sizeof(_type) == 4 ? OPT_INT32 : OPT_INT64)))), \ + .value = &msdos_opt->_name, \ + .minimum = _min, \ + .maximum = sizeof(_type) == 1 ? 0xff : \ + (sizeof(_type) == 2 ? 0xffff : \ + (sizeof(_type) == 4 ? 0xffffffff : 0xffffffffffffffffLL)), \ + .desc = _desc, \ +}, +ALLOPTS +#undef AOPT + { .name = NULL } + }; + + fsopts->fs_specific = msdos_opt; + fsopts->fs_options = copy_opts(msdos_options); +} + +void +msdos_cleanup_opts(fsinfo_t *fsopts) +{ + free(fsopts->fs_specific); + free(fsopts->fs_options); +} + +int +msdos_parse_opts(const char *option, fsinfo_t *fsopts) +{ + struct msdos_options *msdos_opt = fsopts->fs_specific; + option_t *msdos_options = fsopts->fs_options; + + int rv; + + assert(option != NULL); + assert(fsopts != NULL); + assert(msdos_opt != NULL); + + if (debug & DEBUG_FS_PARSE_OPTS) + printf("msdos_parse_opts: got `%s'\n", option); + + rv = set_option(msdos_options, option, NULL, 0); + if (rv == -1) + return rv; + + if (strcmp(msdos_options[rv].name, "volume_id") == 0) + msdos_opt->volume_id_set = 1; + else if (strcmp(msdos_options[rv].name, "media_descriptor") == 0) + msdos_opt->media_descriptor_set = 1; + else if (strcmp(msdos_options[rv].name, "hidden_sectors") == 0) + msdos_opt->hidden_sectors_set = 1; + return 1; +} + + +void +msdos_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) +{ + struct msdos_options *msdos_opt = fsopts->fs_specific; + struct vnode vp, rootvp; + struct timeval start; + struct msdosfsmount *pmp; + + assert(image != NULL); + assert(dir != NULL); + assert(root != NULL); + assert(fsopts != NULL); + + /* + * XXX: pick up other options from the msdos specific ones? + * Is minsize right here? + */ + msdos_opt->create_size = MAX(msdos_opt->create_size, fsopts->minsize); + msdos_opt->offset = fsopts->offset; + if (msdos_opt->bytes_per_sector == 0) { + if (fsopts->sectorsize == -1) + fsopts->sectorsize = 512; + msdos_opt->bytes_per_sector = fsopts->sectorsize; + } else if (fsopts->sectorsize == -1) { + fsopts->sectorsize = msdos_opt->bytes_per_sector; + } else if (fsopts->sectorsize != msdos_opt->bytes_per_sector) { + err(1, "inconsistent sectorsize -S %u" + "!= -o bytes_per_sector %u", + fsopts->sectorsize, msdos_opt->bytes_per_sector); + } + + /* create image */ + printf("Creating `%s'\n", image); + TIMER_START(start); + if (mkfs_msdos(image, NULL, msdos_opt) == -1) + return; + TIMER_RESULTS(start, "mkfs_msdos"); + + fsopts->fd = open(image, O_RDWR); + vp.fs = fsopts; + + if ((pmp = msdosfs_mount(&vp, 0)) == NULL) + err(1, "msdosfs_mount"); + + if (msdosfs_root(pmp, &rootvp) != 0) + err(1, "msdosfs_root"); + + if (debug & DEBUG_FS_MAKEFS) + printf("msdos_makefs: image %s directory %s root %p\n", + image, dir, root); + + /* populate image */ + printf("Populating `%s'\n", image); + TIMER_START(start); + if (msdos_populate_dir(dir, VTODE(&rootvp), root, root, fsopts) == -1) + errx(1, "Image file `%s' not created.", image); + TIMER_RESULTS(start, "msdos_populate_dir"); + + if (debug & DEBUG_FS_MAKEFS) + putchar('\n'); + + /* ensure no outstanding buffers remain */ + if (debug & DEBUG_FS_MAKEFS) + bcleanup(); + + printf("Image `%s' complete\n", image); +} + +static int +msdos_populate_dir(const char *path, struct denode *dir, fsnode *root, + fsnode *parent, fsinfo_t *fsopts) +{ + fsnode *cur; + char pbuf[MAXPATHLEN]; + + assert(dir != NULL); + assert(root != NULL); + assert(fsopts != NULL); + + for (cur = root->next; cur != NULL; cur = cur->next) { + if ((size_t)snprintf(pbuf, sizeof(pbuf), "%s/%s", path, + cur->name) >= sizeof(pbuf)) { + warnx("path %s too long", pbuf); + return -1; + } + + if ((cur->inode->flags & FI_ALLOCATED) == 0) { + cur->inode->flags |= FI_ALLOCATED; + if (cur != root) { + fsopts->curinode++; + cur->inode->ino = fsopts->curinode; + cur->parent = parent; + } + } + + if (cur->inode->flags & FI_WRITTEN) { + continue; // hard link + } + cur->inode->flags |= FI_WRITTEN; + + if (cur->child) { + struct denode *de; + if ((de = msdosfs_mkdire(pbuf, dir, cur)) == NULL) { + warn("msdosfs_mkdire %s", pbuf); + return -1; + } + if (msdos_populate_dir(pbuf, de, cur->child, cur, + fsopts) == -1) { + warn("msdos_populate_dir %s", pbuf); + return -1; + } + continue; + } else if (!S_ISREG(cur->type)) { + warnx("skipping non-regular file %s/%s", cur->path, + cur->name); + continue; + } + if (msdosfs_mkfile(pbuf, dir, cur) == NULL) { + warn("msdosfs_mkfile %s", pbuf); + return -1; + } + } + return 0; +} diff --git a/vendor/bdj-sdk/host/src/makefs_termux/msdos.h b/vendor/bdj-sdk/host/src/makefs_termux/msdos.h new file mode 100644 index 0000000..0357f6d --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/msdos.h @@ -0,0 +1,39 @@ +/* $NetBSD: msdos.h,v 1.3 2015/10/16 16:40:02 christos Exp $ */ + +/*- + * Copyright (c) 2013 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +struct vnode; +struct denode; + +struct msdosfsmount *msdosfs_mount(struct vnode *, int); +int msdosfs_root(struct msdosfsmount *, struct vnode *); + +struct denode *msdosfs_mkfile(const char *, struct denode *, fsnode *); +struct denode *msdosfs_mkdire(const char *, struct denode *, fsnode *); diff --git a/vendor/bdj-sdk/host/src/makefs_termux/mtree.h b/vendor/bdj-sdk/host/src/makefs_termux/mtree.h new file mode 100644 index 0000000..4675a87 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/mtree.h @@ -0,0 +1,140 @@ +/* $NetBSD: mtree.h,v 1.3 2008/11/06 02:14:52 jschauma Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)mtree.h 8.1 (Berkeley) 6/6/93 + */ + +#ifndef _MTREE_H_ +#define _MTREE_H_ + +#define KEYDEFAULT (F_GID | F_MODE | F_NLINK | F_SIZE | F_SLINK | \ + F_TIME | F_TYPE | F_UID | F_FLAGS) + +#define MISMATCHEXIT 2 + +/* Max. length of hash -- update this if needed when adding a new algorithm. */ +#define MAXHASHLEN 128 /* SHA512 */ + +typedef struct _node { + struct _node *parent, *child; /* up, down */ + struct _node *prev, *next; /* left, right */ + off_t st_size; /* size */ + struct timespec st_mtimespec; /* last modification time */ + char *slink; /* symbolic link reference */ + uid_t st_uid; /* uid */ + gid_t st_gid; /* gid */ +#define MBITS (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO) + mode_t st_mode; /* mode */ + dev_t st_rdev; /* device type */ + u_long st_flags; /* flags */ + nlink_t st_nlink; /* link count */ + u_long cksum; /* check sum */ + char *md5digest; /* MD5 digest */ + char *rmd160digest; /* RMD-160 digest */ + char *sha1digest; /* SHA1 digest */ + char *sha256digest; /* SHA256 digest */ + char *sha384digest; /* SHA384 digest */ + char *sha512digest; /* SHA512 digest */ + char *tags; /* tags, comma delimited */ + size_t lineno; /* line # entry came from */ + +#define F_CKSUM 0x00000001 /* cksum(1) check sum */ +#define F_DEV 0x00000002 /* device type */ +#define F_DONE 0x00000004 /* directory done */ +#define F_FLAGS 0x00000008 /* file flags */ +#define F_GID 0x00000010 /* gid */ +#define F_GNAME 0x00000020 /* group name */ +#define F_IGN 0x00000040 /* ignore */ +#define F_MAGIC 0x00000080 /* name has magic chars */ +#define F_MD5 0x00000100 /* MD5 digest */ +#define F_MODE 0x00000200 /* mode */ +#define F_NLINK 0x00000400 /* number of links */ +#define F_OPT 0x00000800 /* existence optional */ +#define F_RMD160 0x00001000 /* RMD-160 digest */ +#define F_SHA1 0x00002000 /* SHA1 digest */ +#define F_SIZE 0x00004000 /* size */ +#define F_SLINK 0x00008000 /* symbolic link */ +#define F_TAGS 0x00010000 /* tags */ +#define F_TIME 0x00020000 /* modification time */ +#define F_TYPE 0x00040000 /* file type */ +#define F_UID 0x00080000 /* uid */ +#define F_UNAME 0x00100000 /* user name */ +#define F_VISIT 0x00200000 /* file visited */ +#define F_SHA256 0x00800000 /* SHA256 digest */ +#define F_SHA384 0x01000000 /* SHA384 digest */ +#define F_SHA512 0x02000000 /* SHA512 digest */ + + int flags; /* items set */ + +#define F_BLOCK 0x001 /* block special */ +#define F_CHAR 0x002 /* char special */ +#define F_DIR 0x004 /* directory */ +#define F_FIFO 0x008 /* fifo */ +#define F_FILE 0x010 /* regular file */ +#define F_LINK 0x020 /* symbolic link */ +#define F_SOCK 0x040 /* socket */ +#define F_DOOR 0x080 /* door */ + int type; /* file type */ + + char name[1]; /* file name (must be last) */ +} NODE; + + +typedef struct { + char **list; + int count; +} slist_t; + + +/* + * prototypes for functions published to other programs which want to use + * the specfile parser but don't want to pull in all of "extern.h" + */ +const char *inotype(u_int); +u_int nodetoino(u_int); +int setup_getid(const char *); +NODE *spec(FILE *); +void free_nodes(NODE *); +char *vispath(const char *); + + +#define RP(p) \ + ((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \ + (p)->fts_path + 2 : (p)->fts_path) + +#define UF_MASK ((UF_NODUMP | UF_IMMUTABLE | \ + UF_APPEND | UF_OPAQUE) \ + & UF_SETTABLE) /* user settable flags */ +#define SF_MASK ((SF_ARCHIVED | SF_IMMUTABLE | \ + SF_APPEND) & SF_SETTABLE) /* root settable flags */ +#define CH_MASK (UF_MASK | SF_MASK) /* all settable flags */ +#define SP_FLGS (SF_IMMUTABLE | SF_APPEND) /* special flags */ + +#endif /* _MTREE_H_ */ diff --git a/vendor/bdj-sdk/host/src/makefs_termux/nbcompat.h b/vendor/bdj-sdk/host/src/makefs_termux/nbcompat.h new file mode 100644 index 0000000..c763221 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/nbcompat.h @@ -0,0 +1,134 @@ +/* $NetBSD: nbcompat.h,v 1.43 2009/04/13 11:30:46 joerg Exp $ */ + +/*- + * Copyright (c) 2003 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 + +#include +#include +#include +#include +#include + +#if HAVE_ERRNO_H +#include +#endif + +#if HAVE_STDARG_H +#include +#endif + +#if HAVE_STDDEF_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_NBCOMPAT_POLL +# if HAVE_POLL_H +# undef HAVE_POLL_H +# endif +# if HAVE_SYS_POLL_H +# undef HAVE_SYS_POLL_H +# endif +# include +#endif + +#if HAVE_NBCOMPAT_FTS +# if HAVE_FTS_H +# undef HAVE_FTS_H +# endif +# include +#endif + +#if HAVE_NBCOMPAT_GLOB +# if HAVE_GLOB_H +# undef HAVE_GLOB_H +# endif +# include +#endif + +#if HAVE_NBCOMPAT_REGEX +# if HAVE_REGEX_H +# undef HAVE_REGEX_H +# endif +# include +#endif + +#if HAVE_NBCOMPAT_MD5INIT +# if HAVE_MD5_H +# undef HAVE_MD5_H +# endif +#endif + +#if HAVE_NBCOMPAT_MD5 +# if HAVE_MD5_H +# undef HAVE_MD5_H +# endif +#endif + +#if HAVE_NBCOMPAT_RMD160 +# if HAVE_RMD160_H +# undef HAVE_RMD160_H +# endif +#endif + +#if HAVE_NBCOMPAT_SHA1 +# if HAVE_SHA1_H +# undef HAVE_SHA1_H +# endif +#endif + +#if HAVE_NBCOMPAT_VIS +# if HAVE_VIS_H +# undef HAVE_VIS_H +# endif +# include +#endif + +#if !HAVE_GETOPT_H || !HAVE_STRUCT_OPTION +# undef HAVE_GETOPT_H +# include +#endif diff --git a/vendor/bdj-sdk/host/src/makefs_termux/pack_dev.c b/vendor/bdj-sdk/host/src/makefs_termux/pack_dev.c new file mode 100644 index 0000000..f91e894 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/pack_dev.c @@ -0,0 +1,317 @@ +/* $NetBSD: pack_dev.c,v 1.5 2008/11/06 02:14:52 jschauma Exp $ */ + +/*- + * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if HAVE_SYS_CDEFS_H +#include +#endif +#if !defined(lint) +__RCSID("$NetBSD: pack_dev.c,v 1.5 2008/11/06 02:14:52 jschauma Exp $"); +#endif /* not lint */ + +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif + +#if HAVE_LIMITS_H +#include +#endif +#if HAVE_STDIO_H +#include +#endif +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_STRING_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif + +#include "pack_dev.h" + +static pack_t pack_netbsd; +static pack_t pack_freebsd; +static pack_t pack_8_8; +static pack_t pack_12_20; +static pack_t pack_14_18; +static pack_t pack_8_24; +static pack_t pack_bsdos; +static int compare_format(const void *, const void *); + +static const char iMajorError[] = "invalid major number"; +static const char iMinorError[] = "invalid minor number"; +static const char tooManyFields[] = "too many fields for format"; + + /* exported */ +portdev_t +pack_native(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev(numbers[0], numbers[1]); + if (major(dev) != numbers[0]) + *error = iMajorError; + else if (minor(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +static portdev_t +pack_netbsd(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_netbsd(numbers[0], numbers[1]); + if (major_netbsd(dev) != numbers[0]) + *error = iMajorError; + else if (minor_netbsd(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_freebsd(x) ((int32_t)(((x) & 0x0000ff00) >> 8)) +#define minor_freebsd(x) ((int32_t)(((x) & 0xffff00ff) >> 0)) +#define makedev_freebsd(x,y) ((portdev_t)((((x) << 8) & 0x0000ff00) | \ + (((y) << 0) & 0xffff00ff))) + +static portdev_t +pack_freebsd(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_freebsd(numbers[0], numbers[1]); + if (major_freebsd(dev) != numbers[0]) + *error = iMajorError; + if (minor_freebsd(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_8_8(x) ((int32_t)(((x) & 0x0000ff00) >> 8)) +#define minor_8_8(x) ((int32_t)(((x) & 0x000000ff) >> 0)) +#define makedev_8_8(x,y) ((portdev_t)((((x) << 8) & 0x0000ff00) | \ + (((y) << 0) & 0x000000ff))) + +static portdev_t +pack_8_8(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_8_8(numbers[0], numbers[1]); + if (major_8_8(dev) != numbers[0]) + *error = iMajorError; + if (minor_8_8(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_12_20(x) ((int32_t)(((x) & 0xfff00000) >> 20)) +#define minor_12_20(x) ((int32_t)(((x) & 0x000fffff) >> 0)) +#define makedev_12_20(x,y) ((portdev_t)((((x) << 20) & 0xfff00000) | \ + (((y) << 0) & 0x000fffff))) + +static portdev_t +pack_12_20(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_12_20(numbers[0], numbers[1]); + if (major_12_20(dev) != numbers[0]) + *error = iMajorError; + if (minor_12_20(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_14_18(x) ((int32_t)(((x) & 0xfffc0000) >> 18)) +#define minor_14_18(x) ((int32_t)(((x) & 0x0003ffff) >> 0)) +#define makedev_14_18(x,y) ((portdev_t)((((x) << 18) & 0xfffc0000) | \ + (((y) << 0) & 0x0003ffff))) + +static portdev_t +pack_14_18(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_14_18(numbers[0], numbers[1]); + if (major_14_18(dev) != numbers[0]) + *error = iMajorError; + if (minor_14_18(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_8_24(x) ((int32_t)(((x) & 0xff000000) >> 24)) +#define minor_8_24(x) ((int32_t)(((x) & 0x00ffffff) >> 0)) +#define makedev_8_24(x,y) ((portdev_t)((((x) << 24) & 0xff000000) | \ + (((y) << 0) & 0x00ffffff))) + +static portdev_t +pack_8_24(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_8_24(numbers[0], numbers[1]); + if (major_8_24(dev) != numbers[0]) + *error = iMajorError; + if (minor_8_24(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_12_12_8(x) ((int32_t)(((x) & 0xfff00000) >> 20)) +#define unit_12_12_8(x) ((int32_t)(((x) & 0x000fff00) >> 8)) +#define subunit_12_12_8(x) ((int32_t)(((x) & 0x000000ff) >> 0)) +#define makedev_12_12_8(x,y,z) ((portdev_t)((((x) << 20) & 0xfff00000) | \ + (((y) << 8) & 0x000fff00) | \ + (((z) << 0) & 0x000000ff))) + +static portdev_t +pack_bsdos(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_12_20(numbers[0], numbers[1]); + if (major_12_20(dev) != numbers[0]) + *error = iMajorError; + if (minor_12_20(dev) != numbers[1]) + *error = iMinorError; + } else if (n == 3) { + dev = makedev_12_12_8(numbers[0], numbers[1], numbers[2]); + if (major_12_12_8(dev) != numbers[0]) + *error = iMajorError; + if (unit_12_12_8(dev) != numbers[1]) + *error = "invalid unit number"; + if (subunit_12_12_8(dev) != numbers[2]) + *error = "invalid subunit number"; + } else + *error = tooManyFields; + return (dev); +} + + + /* list of formats and pack functions */ + /* this list must be sorted lexically */ +struct format { + const char *name; + pack_t *pack; +} formats[] = { + {"386bsd", pack_8_8}, + {"4bsd", pack_8_8}, + {"bsdos", pack_bsdos}, + {"freebsd", pack_freebsd}, + {"hpux", pack_8_24}, + {"isc", pack_8_8}, + {"linux", pack_8_8}, + {"native", pack_native}, + {"netbsd", pack_netbsd}, + {"osf1", pack_12_20}, + {"sco", pack_8_8}, + {"solaris", pack_14_18}, + {"sunos", pack_8_8}, + {"svr3", pack_8_8}, + {"svr4", pack_14_18}, + {"ultrix", pack_8_8}, +}; + +static int +compare_format(const void *key, const void *element) +{ + const char *name; + const struct format *format; + + name = key; + format = element; + + return (strcmp(name, format->name)); +} + + +pack_t * +pack_find(const char *name) +{ + struct format *format; + + format = bsearch(name, formats, + sizeof(formats)/sizeof(formats[0]), + sizeof(formats[0]), compare_format); + if (format == 0) + return (NULL); + return (format->pack); +} diff --git a/vendor/bdj-sdk/host/src/makefs_termux/pack_dev.h b/vendor/bdj-sdk/host/src/makefs_termux/pack_dev.h new file mode 100644 index 0000000..7398b12 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/pack_dev.h @@ -0,0 +1,59 @@ +/* $NetBSD: pack_dev.h,v 1.4 2008/11/06 02:14:52 jschauma Exp $ */ + +/*- + * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#ifndef _PACK_DEV_H +#define _PACK_DEV_H + +#ifdef __CYGWIN__ +typedef __dev32_t portdev_t; +#else +typedef dev_t portdev_t; +#endif +typedef portdev_t pack_t(int, u_long [], const char **); + +pack_t *pack_find(const char *); +pack_t pack_native; + +#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8))) +#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \ + (((x) & 0x000000ff) >> 0))) +#define makedev_netbsd(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \ + (((y) << 12) & 0xfff00000) | \ + (((y) << 0) & 0x000000ff))) + +#endif /* _PACK_DEV_H */ diff --git a/vendor/bdj-sdk/host/src/makefs_termux/spec.c b/vendor/bdj-sdk/host/src/makefs_termux/spec.c new file mode 100644 index 0000000..cee838e --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/spec.c @@ -0,0 +1,701 @@ +/* $NetBSD: spec.c,v 1.5 2008/11/06 02:14:52 jschauma Exp $ */ + +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +/*- + * Copyright (c) 2001-2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +//#include +#if HAVE_SYS_CDEFS_H +#include +#endif +#if defined(__RCSID) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)spec.c 8.2 (Berkeley) 4/28/95"; +#else +__RCSID("$NetBSD: spec.c,v 1.5 2008/11/06 02:14:52 jschauma Exp $"); +#endif +#endif /* not lint */ + +#if HAVE_SYS_PARAM_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif + +#if HAVE_CTYPE_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_GRP_H +#include +#endif +#if HAVE_PWD_H +#include +#endif +#if HAVE_STDIO_H +#include +#endif +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_STRING_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_VIS_H +#include +#endif +#if HAVE_UTIL_H +#include +#endif + +#include "extern.h" +#include "pack_dev.h" + +size_t mtree_lineno; /* Current spec line number */ +int mtree_Mflag; /* Merge duplicate entries */ +int mtree_Wflag; /* Don't "whack" permissions */ + +static dev_t parsedev(char *); +static void replacenode(NODE *, NODE *); +static void set(char *, NODE *); +static void unset(char *, NODE *); + +#define REPLACEPTR(x,v) do { if ((x)) free((x)); (x) = (v); } while (0) + +NODE * +spec(FILE *fp) +{ + NODE *centry, *last, *pathparent, *cur; + char *p, *e, *next; + NODE ginfo, *root; + char *buf, *tname, *ntname; + size_t tnamelen, plen; + + root = NULL; + centry = last = NULL; + tname = NULL; + tnamelen = 0; + memset(&ginfo, 0, sizeof(ginfo)); + for (mtree_lineno = 0; + (buf = fparseln(fp, NULL, &mtree_lineno, NULL, + FPARSELN_UNESCCOMM)); + free(buf)) { + /* Skip leading whitespace. */ + for (p = buf; *p && isspace((unsigned char)*p); ++p) + continue; + + /* If nothing but whitespace, continue. */ + if (!*p) + continue; + +#ifdef DEBUG + fprintf(stderr, "line %lu: {%s}\n", + (u_long)mtree_lineno, p); +#endif + /* Grab file name, "$", "set", or "unset". */ + next = buf; + while ((p = strsep(&next, " \t")) != NULL && *p == '\0') + continue; + if (p == NULL) + mtree_err("missing field"); + + if (p[0] == '/') { + if (strcmp(p + 1, "set") == 0) + set(next, &ginfo); + else if (strcmp(p + 1, "unset") == 0) + unset(next, &ginfo); + else + mtree_err("invalid specification `%s'", p); + continue; + } + + if (strcmp(p, "..") == 0) { + /* Don't go up, if haven't gone down. */ + if (root == NULL) + goto noparent; + if (last->type != F_DIR || last->flags & F_DONE) { + if (last == root) + goto noparent; + last = last->parent; + } + last->flags |= F_DONE; + continue; + +noparent: mtree_err("no parent node"); + } + + plen = strlen(p) + 1; + if (plen > tnamelen) { + if ((ntname = realloc(tname, plen)) == NULL) + mtree_err("realloc: %s", strerror(errno)); + tname = ntname; + tnamelen = plen; + } + if (strunvis(tname, p) == -1) + mtree_err("strunvis failed on `%s'", p); + p = tname; + + pathparent = NULL; + if (strchr(p, '/') != NULL) { + cur = root; + for (; (e = strchr(p, '/')) != NULL; p = e+1) { + if (p == e) + continue; /* handle // */ + *e = '\0'; + if (strcmp(p, ".") != 0) { + while (cur && + strcmp(cur->name, p) != 0) { + cur = cur->next; + } + } + if (cur == NULL || cur->type != F_DIR) { + mtree_err("%s: %s", tname, + strerror(ENOENT)); + } + *e = '/'; + pathparent = cur; + cur = cur->child; + } + if (*p == '\0') + mtree_err("%s: empty leaf element", tname); + } + + if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) + mtree_err("%s", strerror(errno)); + *centry = ginfo; + centry->lineno = mtree_lineno; + strcpy(centry->name, p); +#define MAGIC "?*[" + if (strpbrk(p, MAGIC)) + centry->flags |= F_MAGIC; + set(next, centry); + + if (root == NULL) { + /* + * empty tree + */ + if (strcmp(centry->name, ".") != 0 || + centry->type != F_DIR) + mtree_err( + "root node must be the directory `.'"); + last = root = centry; + root->parent = root; + } else if (pathparent != NULL) { + /* + * full path entry + */ + centry->parent = pathparent; + cur = pathparent->child; + if (cur == NULL) { + pathparent->child = centry; + last = centry; + } else { + for (; cur != NULL; cur = cur->next) { + if (strcmp(cur->name, centry->name) + == 0) { + /* existing entry; replace */ + replacenode(cur, centry); + break; + } + if (cur->next == NULL) { + /* last entry; add new */ + cur->next = centry; + centry->prev = cur; + break; + } + } + last = cur; + while (last->next != NULL) + last = last->next; + } + } else if (strcmp(centry->name, ".") == 0) { + /* + * duplicate "." entry; always replace + */ + replacenode(root, centry); + } else if (last->type == F_DIR && !(last->flags & F_DONE)) { + /* + * new relative child + * (no duplicate check) + */ + centry->parent = last; + last = last->child = centry; + } else { + /* + * relative entry, up one directory + * (no duplicate check) + */ + centry->parent = last->parent; + centry->prev = last; + last = last->next = centry; + } + } + return (root); +} + +void +free_nodes(NODE *root) +{ + NODE *cur, *next; + + if (root == NULL) + return; + + next = NULL; + for (cur = root; cur != NULL; cur = next) { + next = cur->next; + free_nodes(cur->child); + REPLACEPTR(cur->slink, NULL); + REPLACEPTR(cur->md5digest, NULL); + REPLACEPTR(cur->rmd160digest, NULL); + REPLACEPTR(cur->sha1digest, NULL); + REPLACEPTR(cur->sha256digest, NULL); + REPLACEPTR(cur->sha384digest, NULL); + REPLACEPTR(cur->sha512digest, NULL); + REPLACEPTR(cur->tags, NULL); + REPLACEPTR(cur, NULL); + } +} + +/* + * dump_nodes -- + * dump the NODEs from `cur', based in the directory `dir'. + * if pathlast is none zero, print the path last, otherwise print + * it first. + */ +void +dump_nodes(const char *dir, NODE *root, int pathlast) +{ + NODE *cur; + char path[MAXPATHLEN]; + const char *name; + + for (cur = root; cur != NULL; cur = cur->next) { + if (cur->type != F_DIR && !matchtags(cur)) + continue; + + if (snprintf(path, sizeof(path), "%s%s%s", + dir, *dir ? "/" : "", cur->name) + >= sizeof(path)) + mtree_err("Pathname too long."); + + if (!pathlast) + printf("%s ", vispath(path)); + +#define MATCHFLAG(f) ((keys & (f)) && (cur->flags & (f))) + if (MATCHFLAG(F_TYPE)) + printf("type=%s ", nodetype(cur->type)); + if (MATCHFLAG(F_UID | F_UNAME)) { + if (keys & F_UNAME && + (name = user_from_uid(cur->st_uid, 1)) != NULL) + printf("uname=%s ", name); + else + printf("uid=%u ", cur->st_uid); + } + if (MATCHFLAG(F_GID | F_GNAME)) { + if (keys & F_GNAME && + (name = group_from_gid(cur->st_gid, 1)) != NULL) + printf("gname=%s ", name); + else + printf("gid=%u ", cur->st_gid); + } + if (MATCHFLAG(F_MODE)) + printf("mode=%#o ", cur->st_mode); + if (MATCHFLAG(F_DEV) && + (cur->type == F_BLOCK || cur->type == F_CHAR)) + printf("device=%#x ", cur->st_rdev); + if (MATCHFLAG(F_NLINK)) + printf("nlink=%d ", cur->st_nlink); + if (MATCHFLAG(F_SLINK)) + printf("link=%s ", vispath(cur->slink)); + if (MATCHFLAG(F_SIZE)) + printf("size=%lld ", (long long)cur->st_size); + if (MATCHFLAG(F_TIME)) + printf("time=%ld.%ld ", (long)cur->st_mtimespec.tv_sec, + cur->st_mtimespec.tv_nsec); + if (MATCHFLAG(F_CKSUM)) + printf("cksum=%lu ", cur->cksum); + if (MATCHFLAG(F_MD5)) + printf("md5=%s ", cur->md5digest); + if (MATCHFLAG(F_RMD160)) + printf("rmd160=%s ", cur->rmd160digest); + if (MATCHFLAG(F_SHA1)) + printf("sha1=%s ", cur->sha1digest); + if (MATCHFLAG(F_SHA256)) + printf("sha256=%s ", cur->sha256digest); + if (MATCHFLAG(F_SHA384)) + printf("sha384=%s ", cur->sha384digest); + if (MATCHFLAG(F_SHA512)) + printf("sha512=%s ", cur->sha512digest); + if (MATCHFLAG(F_FLAGS)) + printf("flags=%s ", + flags_to_string(cur->st_flags, "none")); + if (MATCHFLAG(F_IGN)) + printf("ignore "); + if (MATCHFLAG(F_OPT)) + printf("optional "); + if (MATCHFLAG(F_TAGS)) + printf("tags=%s ", cur->tags); + puts(pathlast ? vispath(path) : ""); + + if (cur->child) + dump_nodes(path, cur->child, pathlast); + } +} + +/* + * vispath -- + * strsvis(3) encodes path, which must not be longer than MAXPATHLEN + * characters long, and returns a pointer to a static buffer containing + * the result. + */ +char * +vispath(const char *path) +{ + const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' }; + static char pathbuf[4*MAXPATHLEN + 1]; + + strsvis(pathbuf, path, VIS_CSTYLE, extra); + return(pathbuf); +} + + +static dev_t +parsedev(char *arg) +{ +#define MAX_PACK_ARGS 3 + u_long numbers[MAX_PACK_ARGS]; + char *p, *ep, *dev; + int argc; + pack_t *pack; + dev_t result; + const char *error = NULL; + + if ((dev = strchr(arg, ',')) != NULL) { + *dev++='\0'; + if ((pack = pack_find(arg)) == NULL) + mtree_err("unknown format `%s'", arg); + argc = 0; + while ((p = strsep(&dev, ",")) != NULL) { + if (*p == '\0') + mtree_err("missing number"); + numbers[argc++] = strtoul(p, &ep, 0); + if (*ep != '\0') + mtree_err("invalid number `%s'", + p); + if (argc > MAX_PACK_ARGS) + mtree_err("too many arguments"); + } + if (argc < 2) + mtree_err("not enough arguments"); + result = (*pack)(argc, numbers, &error); + if (error != NULL) + mtree_err(error); + } else { + result = (dev_t)strtoul(arg, &ep, 0); + if (*ep != '\0') + mtree_err("invalid device `%s'", arg); + } + return (result); +} + +static void +replacenode(NODE *cur, NODE *new) +{ + +#define REPLACE(x) cur->x = new->x +#define REPLACESTR(x) REPLACEPTR(cur->x,new->x) + + if (cur->type != new->type) { + if (mtree_Mflag) { + /* + * merge entries with different types; we + * don't want children retained in this case. + */ + REPLACE(type); + free_nodes(cur->child); + cur->child = NULL; + } else { + mtree_err( + "existing entry for `%s', type `%s'" + " does not match type `%s'", + cur->name, nodetype(cur->type), + nodetype(new->type)); + } + } + + REPLACE(st_size); + REPLACE(st_mtimespec); + REPLACESTR(slink); + if (cur->slink != NULL) { + if ((cur->slink = strdup(new->slink)) == NULL) + mtree_err("memory allocation error"); + if (strunvis(cur->slink, new->slink) == -1) + mtree_err("strunvis failed on `%s'", new->slink); + free(new->slink); + } + REPLACE(st_uid); + REPLACE(st_gid); + REPLACE(st_mode); + REPLACE(st_rdev); + REPLACE(st_flags); + REPLACE(st_nlink); + REPLACE(cksum); + REPLACESTR(md5digest); + REPLACESTR(rmd160digest); + REPLACESTR(sha1digest); + REPLACESTR(sha256digest); + REPLACESTR(sha384digest); + REPLACESTR(sha512digest); + REPLACESTR(tags); + REPLACE(lineno); + REPLACE(flags); + free(new); +} + +static void +set(char *t, NODE *ip) +{ + int type, value, len; + gid_t gid; + uid_t uid; + char *kw, *val, *md, *ep; + void *m; + + while ((kw = strsep(&t, "= \t")) != NULL) { + if (*kw == '\0') + continue; + if (strcmp(kw, "all") == 0) + mtree_err("invalid keyword `all'"); + ip->flags |= type = parsekey(kw, &value); + if (!value) + /* Just set flag bit (F_IGN and F_OPT) */ + continue; + while ((val = strsep(&t, " \t")) != NULL && *val == '\0') + continue; + if (val == NULL) + mtree_err("missing value"); + switch (type) { + case F_CKSUM: + ip->cksum = strtoul(val, &ep, 10); + if (*ep) + mtree_err("invalid checksum `%s'", val); + break; + case F_DEV: + ip->st_rdev = parsedev(val); + break; + case F_FLAGS: + if (strcmp("none", val) == 0) + ip->st_flags = 0; + else if (string_to_flags(&val, &ip->st_flags, NULL) + != 0) + mtree_err("invalid flag `%s'", val); + break; + case F_GID: + ip->st_gid = (gid_t)strtoul(val, &ep, 10); + if (*ep) + mtree_err("invalid gid `%s'", val); + break; + case F_GNAME: + if (mtree_Wflag) /* don't parse if whacking */ + break; + if (gid_from_group(val, &gid) == -1) + mtree_err("unknown group `%s'", val); + ip->st_gid = gid; + break; + case F_MD5: + if (val[0]=='0' && val[1]=='x') + md=&val[2]; + else + md=val; + if ((ip->md5digest = strdup(md)) == NULL) + mtree_err("memory allocation error"); + break; + case F_MODE: + if ((m = setmode(val)) == NULL) + mtree_err("cannot set file mode `%s' (%s)", + val, strerror(errno)); + ip->st_mode = getmode(m, 0); + free(m); + break; + case F_NLINK: + ip->st_nlink = (nlink_t)strtoul(val, &ep, 10); + if (*ep) + mtree_err("invalid link count `%s'", val); + break; + case F_RMD160: + if (val[0]=='0' && val[1]=='x') + md=&val[2]; + else + md=val; + if ((ip->rmd160digest = strdup(md)) == NULL) + mtree_err("memory allocation error"); + break; + case F_SHA1: + if (val[0]=='0' && val[1]=='x') + md=&val[2]; + else + md=val; + if ((ip->sha1digest = strdup(md)) == NULL) + mtree_err("memory allocation error"); + break; + case F_SIZE: + ip->st_size = (off_t)strtoll(val, &ep, 10); + if (*ep) + mtree_err("invalid size `%s'", val); + break; + case F_SLINK: + if ((ip->slink = strdup(val)) == NULL) + mtree_err("memory allocation error"); + if (strunvis(ip->slink, val) == -1) + mtree_err("strunvis failed on `%s'", val); + break; + case F_TAGS: + len = strlen(val) + 3; /* "," + str + ",\0" */ + if ((ip->tags = malloc(len)) == NULL) + mtree_err("memory allocation error"); + snprintf(ip->tags, len, ",%s,", val); + break; + case F_TIME: + ip->st_mtimespec.tv_sec = + (time_t)strtoul(val, &ep, 10); + if (*ep != '.') + mtree_err("invalid time `%s'", val); + val = ep + 1; + ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10); + if (*ep) + mtree_err("invalid time `%s'", val); + break; + case F_TYPE: + ip->type = parsetype(val); + break; + case F_UID: + ip->st_uid = (uid_t)strtoul(val, &ep, 10); + if (*ep) + mtree_err("invalid uid `%s'", val); + break; + case F_UNAME: + if (mtree_Wflag) /* don't parse if whacking */ + break; + if (uid_from_user(val, &uid) == -1) + mtree_err("unknown user `%s'", val); + ip->st_uid = uid; + break; + case F_SHA256: + if (val[0]=='0' && val[1]=='x') + md=&val[2]; + else + md=val; + if ((ip->sha256digest = strdup(md)) == NULL) + mtree_err("memory allocation error"); + break; + case F_SHA384: + if (val[0]=='0' && val[1]=='x') + md=&val[2]; + else + md=val; + if ((ip->sha384digest = strdup(md)) == NULL) + mtree_err("memory allocation error"); + break; + case F_SHA512: + if (val[0]=='0' && val[1]=='x') + md=&val[2]; + else + md=val; + if ((ip->sha512digest = strdup(md)) == NULL) + mtree_err("memory allocation error"); + break; + default: + mtree_err( + "set(): unsupported key type 0x%x (INTERNAL ERROR)", + type); + /* NOTREACHED */ + } + } +} + +static void +unset(char *t, NODE *ip) +{ + char *p; + + while ((p = strsep(&t, " \t")) != NULL) { + if (*p == '\0') + continue; + ip->flags &= ~parsekey(p, NULL); + } +} diff --git a/vendor/bdj-sdk/host/src/makefs_termux/stat_flags.h b/vendor/bdj-sdk/host/src/makefs_termux/stat_flags.h new file mode 100644 index 0000000..bf8b30f --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/stat_flags.h @@ -0,0 +1,35 @@ +/* $NetBSD: stat_flags.h,v 1.1 2003/09/05 18:39:00 jlam Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)extern.h 8.1 (Berkeley) 5/31/93 + */ + +char *flags_to_string(u_long, const char *); +int string_to_flags(char **, u_long *, u_long *); diff --git a/vendor/bdj-sdk/host/src/makefs_termux/strstuff.c b/vendor/bdj-sdk/host/src/makefs_termux/strstuff.c new file mode 100644 index 0000000..888326c --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/strstuff.c @@ -0,0 +1,222 @@ +/* $NetBSD: strsuftoll.c,v 1.6 2004/03/05 05:58:29 lukem Exp $ */ +/*- + * Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego and Lance + * Visser of Convex Computer Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 +//__FBSDID("$FreeBSD: head/lib/libnetbsd/strsuftoll.c 244557 2012-12-21 20:37:38Z brooks $"); + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _LIBC +# ifdef __weak_alias +__weak_alias(strsuftoll, _strsuftoll) +__weak_alias(strsuftollx, _strsuftollx) +# endif +#endif /* LIBC */ + +/* + * Convert an expression of the following forms to a (u)int64_t. + * 1) A positive decimal number. + * 2) A positive decimal number followed by a b (mult by 512). + * 3) A positive decimal number followed by a k (mult by 1024). + * 4) A positive decimal number followed by a m (mult by 1048576). + * 5) A positive decimal number followed by a g (mult by 1073741824). + * 6) A positive decimal number followed by a t (mult by 1099511627776). + * 7) A positive decimal number followed by a w (mult by sizeof int) + * 8) Two or more positive decimal numbers (with/without k,b or w). + * separated by x (also * for backwards compatibility), specifying + * the product of the indicated values. + * Returns the result upon successful conversion, or exits with an + * appropriate error. + * + */ + +/* + * As strsuftoll(), but returns the error message into the provided buffer + * rather than exiting with it. + */ +/* LONGLONG */ +long long +strsuftollx(const char *desc, const char *val, + long long min, long long max, char *ebuf, size_t ebuflen) +{ + long long num, t; + char *expr; + + errno = 0; + ebuf[0] = '\0'; + + while (isspace((unsigned char)*val)) /* Skip leading space */ + val++; + + num = strtoll(val, &expr, 10); + if (errno == ERANGE) + goto erange; /* Overflow */ + + if (expr == val) /* No digits */ + goto badnum; + + switch (*expr) { + case 'b': + t = num; + num *= 512; /* 1 block */ + if (t > num) + goto erange; + ++expr; + break; + case 'k': + t = num; + num *= 1024; /* 1 kilobyte */ + if (t > num) + goto erange; + ++expr; + break; + case 'm': + t = num; + num *= 1048576; /* 1 megabyte */ + if (t > num) + goto erange; + ++expr; + break; + case 'g': + t = num; + num *= 1073741824; /* 1 gigabyte */ + if (t > num) + goto erange; + ++expr; + break; + case 't': + t = num; + num *= 1099511627776LL; /* 1 terabyte */ + if (t > num) + goto erange; + ++expr; + break; + case 'w': + t = num; + num *= sizeof(int); /* 1 word */ + if (t > num) + goto erange; + ++expr; + break; + } + + switch (*expr) { + case '\0': + break; + case '*': /* Backward compatible */ + case 'x': + t = num; + num *= strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen); + if (*ebuf != '\0') + return (0); + if (t > num) { + erange: + snprintf(ebuf, ebuflen, + "%s: %s", desc, strerror(ERANGE)); + return (0); + } + break; + default: + badnum: snprintf(ebuf, ebuflen, + "%s `%s': illegal number", desc, val); + return (0); + } + if (num < min) { + /* LONGLONG */ + snprintf(ebuf, ebuflen, "%s %lld is less than %lld.", + desc, (long long)num, (long long)min); + return (0); + } + if (num > max) { + /* LONGLONG */ + snprintf(ebuf, ebuflen, + "%s %lld is greater than %lld.", + desc, (long long)num, (long long)max); + return (0); + } + *ebuf = '\0'; + return (num); +} + +/* LONGLONG */ +long long +strsuftoll(const char *desc, const char *val, + long long min, long long max) +{ + long long result; + char errbuf[100]; + + result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf)); + if (*errbuf != '\0') + errx(1, "%s", errbuf); + return (result); +} diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf.c b/vendor/bdj-sdk/host/src/makefs_termux/udf.c new file mode 100644 index 0000000..6436a38 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf.c @@ -0,0 +1,1267 @@ +/* $NetBSD: udf.c,v 1.25 2022/04/09 10:05:35 riastradh Exp $ */ + +/* + * Copyright (c) 2006, 2008, 2013, 2021, 2022 Reinoud Zandijk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR ``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 AUTHOR 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. + * + */ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +//__RCSID("$NetBSD: udf.c,v 1.25 2022/04/09 10:05:35 riastradh Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" + +#if !HAVE_NBTOOL_CONFIG_H +#define _EXPOSE_MMC +#include "cdio.h" +#else +#include "udf/cdio_mmc_structs.h" +#endif + +#if !HAVE_NBTOOL_CONFIG_H +#define HAVE_STRUCT_TM_TM_GMTOFF +#endif + +#include "makefs.h" +#include "udf_core.h" +#include "newfs_udf.h" + +/* identification */ +#define IMPL_NAME "*NetBSD makefs 10.0" +#define APP_VERSION_MAIN 0 +#define APP_VERSION_SUB 5 + +/* + * Note: due to the setup of the newfs code, the current state of the program + * and its options are held in a few global variables. The FS specific parts + * are in global `context' and 'layout' structures. + */ + +/* global variables describing disc and format requests */ +int req_enable, req_disable; + + +/* --------------------------------------------------------------------- */ + +static int +udf_readonly_format(void) +{ + /* + * we choose the emulated profile to determine this since the media + * might be different from the format we create. Say creating a CDROM + * on a CD-R media. + */ + switch (emul_mmc_profile) { + case 0x00: /* unknown, treat as CDROM */ + case 0x08: /* CDROM */ + case 0x10: /* DVDROM */ + case 0x40: /* BDROM */ + return true; + } + return false; +} + + +#define OPT_STR(letter, name, desc) \ + { letter, name, NULL, OPT_STRBUF, 0, 0, desc } + +#define OPT_NUM(letter, name, field, min, max, desc) \ + { letter, name, &context.field, \ + sizeof(context.field) == 8 ? OPT_INT64 : \ + (sizeof(context.field) == 4 ? OPT_INT32 : \ + (sizeof(context.field) == 2 ? OPT_INT16 : OPT_INT8)), \ + min, max, desc } + +#define OPT_BOOL(letter, name, field, desc) \ + OPT_NUM(letter, name, field, 0, 1, desc) + +void +udf_prep_opts(fsinfo_t *fsopts) +{ + const option_t udf_options[] = { + OPT_STR('T', "disctype", "disc type (cdrom,dvdrom,bdrom," + "dvdram,bdre,disk,cdr,dvdr,bdr,cdrw,dvdrw)"), + OPT_STR('L', "loglabel", "\"logical volume name\""), + OPT_STR('P', "discid", "\"[volset name ':']" + "physical volume name\""), + OPT_NUM('t', "tz", gmtoff, -24, 24, "timezone"), + OPT_STR('v', "minver", "minimum UDF version in either " + "``0x201'' or ``2.01'' format"), + OPT_STR('V', "maxver", "maximum UDF version in either " + "``0x201'' or ``2.01'' format"), + OPT_NUM('p', "metaperc", meta_perc, 1, 99, + "minimum free metadata percentage"), + OPT_BOOL('c', "checksurface", check_surface, + "perform crude surface check on rewritable media"), + OPT_BOOL('F', "forceformat", create_new_session, + "force file system construction on non-empty recordable media"), + { .name = NULL } + }; + + /* initialise */ + req_enable = req_disable = 0; + fsopts->sectorsize = 512; /* minimum allowed sector size */ + + srandom((unsigned long) time(NULL)); + + udf_init_create_context(); + context.app_name = "*NetBSD UDF"; + context.app_version_main = APP_VERSION_MAIN; + context.app_version_sub = APP_VERSION_SUB; + context.impl_name = IMPL_NAME; + + /* minimum and maximum UDF versions we advise */ + context.min_udf = 0x102; + context.max_udf = 0x250; /* 0x260 is not ready */ + + /* defaults for disc/files */ + emul_mmc_profile = -1; /* invalid->no emulation */ + emul_packetsize = 1; /* reasonable default */ + emul_sectorsize = 512; /* minimum allowed sector size */ + emul_size = 0; /* empty */ + + /* use user's time zone as default */ +#if 0 +//#ifdef HAVE_STRUCT_TM_TM_GMTOFF + if (!stampst.st_ino) { + struct tm tm; + time_t now; + (void)time(&now); + (void)localtime_r(&now, &tm); + context.gmtoff = tm.tm_gmtoff; + } else +#endif + context.gmtoff = 0; + + /* return info */ + fsopts->fs_specific = NULL; + fsopts->fs_options = copy_opts(udf_options); +} + + +void +udf_cleanup_opts(fsinfo_t *fsopts) +{ + free(fsopts->fs_options); +} + + +/* ----- included from newfs_udf.c ------ */ + +#define CDRSIZE ((uint64_t) 700*1024*1024) /* small approx */ +#define CDRWSIZE ((uint64_t) 576*1024*1024) /* small approx */ +#define DVDRSIZE ((uint64_t) 4488*1024*1024) /* small approx */ +#define DVDRAMSIZE ((uint64_t) 4330*1024*1024) /* small approx with spare */ +#define DVDRWSIZE ((uint64_t) 4482*1024*1024) /* small approx */ +#define BDRSIZE ((uint64_t) 23866*1024*1024) /* small approx */ +#define BDRESIZE ((uint64_t) 23098*1024*1024) /* small approx */ +int +udf_parse_opts(const char *option, fsinfo_t *fsopts) +{ + option_t *udf_options = fsopts->fs_options; + uint64_t stdsize, maxsize; + uint32_t set_sectorsize; + char buffer[1024], *buf, *colon; + int i; + + assert(option != NULL); + + if (debug & DEBUG_FS_PARSE_OPTS) + printf("udf_parse_opts: got `%s'\n", option); + + i = set_option(udf_options, option, buffer, sizeof(buffer)); + if (i == -1) + return 0; + + if (udf_options[i].name == NULL) + abort(); + + set_sectorsize = 0; + stdsize = 0; + maxsize = 0; + + buf = buffer; + switch (udf_options[i].letter) { + case 'T': + if (strcmp(buf, "cdrom") == 0) { + emul_mmc_profile = 0x00; + maxsize = CDRSIZE; + } else if (strcmp(buf, "dvdrom") == 0) { + emul_mmc_profile = 0x10; + maxsize = DVDRSIZE; + } else if (strcmp(buf, "bdrom") == 0) { + emul_mmc_profile = 0x40; + maxsize = BDRSIZE; + } else if (strcmp(buf, "dvdram") == 0) { + emul_mmc_profile = 0x12; + stdsize = DVDRAMSIZE; + } else if (strcmp(buf, "bdre") == 0) { + emul_mmc_profile = 0x43; + stdsize = BDRESIZE; + } else if (strcmp(buf, "disk") == 0) { + emul_mmc_profile = 0x01; + } else if (strcmp(buf, "cdr") == 0) { + emul_mmc_profile = 0x09; + stdsize = CDRSIZE; + } else if (strcmp(buf, "dvdr") == 0) { + emul_mmc_profile = 0x1b; + stdsize = DVDRSIZE; + } else if (strcmp(buf, "bdr") == 0) { + emul_mmc_profile = 0x41; + stdsize = BDRSIZE; + } else if (strcmp(buf, "cdrw") == 0) { + emul_mmc_profile = 0x0a; + stdsize = CDRWSIZE; + } else if (strcmp(buf, "dvdrw") == 0) { + emul_mmc_profile = 0x1a; + stdsize = DVDRWSIZE; + } else { + errx(1, "unknown or unimplemented disc format"); + } + if (emul_mmc_profile != 0x01) + set_sectorsize = 2048; + break; + case 'L': + if (context.logvol_name) free(context.logvol_name); + context.logvol_name = strdup(buf); + break; + case 'P': + if ((colon = strstr(buf, ":"))) { + if (context.volset_name) + free(context.volset_name); + *colon = 0; + context.volset_name = strdup(buf); + buf = colon+1; + } + if (context.primary_name) + free(context.primary_name); + if ((strstr(buf, ":"))) + errx(1, "primary name can't have ':' in its name"); + context.primary_name = strdup(buf); + break; + case 'v': + context.min_udf = a_udf_version(buf, "min_udf"); + if (context.min_udf > 0x250) + errx(1, "maximum supported version is UDF 2.50"); + if (context.min_udf > context.max_udf) + context.max_udf = context.min_udf; + break; + case 'V': + context.max_udf = a_udf_version(buf, "min_udf"); + if (context.max_udf > 0x250) + errx(1, "maximum supported version is UDF 2.50"); + if (context.min_udf > context.max_udf) + context.min_udf = context.max_udf; + break; + } + if (set_sectorsize) + fsopts->sectorsize = set_sectorsize; + if (stdsize) { + if (fsopts->maxsize > 0) + stdsize = MIN(stdsize, (uint64_t) fsopts->maxsize); + if (fsopts->minsize > 0) + stdsize = MAX(stdsize, (uint64_t) fsopts->minsize); + fsopts->size = fsopts->minsize = fsopts->maxsize = stdsize; + } + if (maxsize) { + if (fsopts->maxsize > 0) + maxsize = MIN(maxsize, (uint64_t) fsopts->maxsize); + if (fsopts->minsize > 0) + maxsize = MAX(maxsize, (uint64_t) fsopts->minsize); + fsopts->maxsize = maxsize; + } + return 1; +} + +/* - + * -------------------------------------------------------------------- */ + +struct udf_stats { + uint32_t nfiles; + uint32_t ndirs; + uint32_t ndescr; + uint32_t nmetadatablocks; + uint32_t ndatablocks; +}; + + +/* node reference administration */ +static void +udf_inc_link(union dscrptr *dscr) +{ + struct file_entry *fe; + struct extfile_entry *efe; + + if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { + fe = &dscr->fe; + fe->link_cnt = udf_rw16(udf_rw16(fe->link_cnt) + 1); + } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { + efe = &dscr->efe; + efe->link_cnt = udf_rw16(udf_rw16(efe->link_cnt) + 1); + } else { + errx(1, "bad tag passed to udf_inc_link"); + } +} + + +static void +udf_set_link_cnt(union dscrptr *dscr, int num) +{ + struct file_entry *fe; + struct extfile_entry *efe; + + if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { + fe = &dscr->fe; + fe->link_cnt = udf_rw16(num); + } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { + efe = &dscr->efe; + efe->link_cnt = udf_rw16(num); + } else { + errx(1, "bad tag passed to udf_set_link_cnt"); + } +} + + +static uint32_t +udf_datablocks(off_t sz) +{ + /* predictor if it can be written inside the node */ + /* XXX the predictor assumes NO extended attributes in the node */ + if (sz < context.sector_size - UDF_EXTFENTRY_SIZE - 16) + return 0; + + return UDF_ROUNDUP(sz, context.sector_size) / context.sector_size; +} + + +static void +udf_prepare_fids(struct long_ad *dir_icb, struct long_ad *dirdata_icb, + uint8_t *dirdata, uint32_t dirdata_size) +{ + struct fileid_desc *fid; + struct long_ad *icb; + uint32_t fidsize, offset; + uint32_t location; + + if (udf_datablocks(dirdata_size) == 0) { + /* going internal */ + icb = dir_icb; + } else { + /* external blocks to write to */ + icb = dirdata_icb; + } + + for (offset = 0; offset < dirdata_size; offset += fidsize) { + /* for each FID: */ + fid = (struct fileid_desc *) (dirdata + offset); + assert(udf_rw16(fid->tag.id) == TAGID_FID); + + location = udf_rw32(icb->loc.lb_num); + location += offset / context.sector_size; + + fid->tag.tag_loc = udf_rw32(location); + udf_validate_tag_and_crc_sums((union dscrptr *) fid); + + fidsize = udf_fidsize(fid); + } +} + + +static int +udf_file_inject_blob(union dscrptr *dscr, uint8_t *blob, off_t size) +{ + struct icb_tag *icb; + struct file_entry *fe; + struct extfile_entry *efe; + uint64_t inf_len, obj_size; + uint32_t l_ea, l_ad; + uint16_t crclen; + uint8_t *data, *pos; + + fe = NULL; + efe = NULL; + if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { + fe = &dscr->fe; + data = fe->data; + l_ea = udf_rw32(fe->l_ea); + l_ad = udf_rw32(fe->l_ad); + icb = &fe->icbtag; + inf_len = udf_rw64(fe->inf_len); + obj_size = 0; + } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { + efe = &dscr->efe; + data = efe->data; + l_ea = udf_rw32(efe->l_ea); + l_ad = udf_rw32(efe->l_ad); + icb = &efe->icbtag; + inf_len = udf_rw64(efe->inf_len); + obj_size = udf_rw64(efe->obj_size); + } else { + errx(1, "bad tag passed to udf_file_inject_blob"); + } + crclen = udf_rw16(dscr->tag.desc_crc_len); + + /* check if we can go internal */ + if ((udf_rw16(icb->flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK) != + UDF_ICB_INTERN_ALLOC) + return 1; + + /* check if it will fit internally */ + if (udf_datablocks(size)) { + /* the predictor tells it won't fit internally */ + return 1; + } + + /* going internal */ + assert((udf_rw16(icb->flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK) == + UDF_ICB_INTERN_ALLOC); + assert(l_ad == 0); + + pos = data + l_ea + l_ad; + memcpy(pos, blob, size); + l_ad += size; + crclen += size; + + inf_len += size; + obj_size += size; + + if (fe) { + fe->l_ad = udf_rw32(l_ad); + fe->inf_len = udf_rw64(inf_len); + } else if (efe) { + efe->l_ad = udf_rw32(l_ad); + efe->inf_len = udf_rw64(inf_len); + efe->obj_size = udf_rw64(inf_len); + } + + /* make sure the header sums stays correct */ + dscr->tag.desc_crc_len = udf_rw16(crclen); + udf_validate_tag_and_crc_sums(dscr); + + return 0; +} + + +/* XXX no sparse file support */ +static void +udf_append_file_mapping(union dscrptr *dscr, struct long_ad *piece) +{ + struct icb_tag *icb; + struct file_entry *fe; + struct extfile_entry *efe; + struct long_ad *last_long, last_piece; + struct short_ad *last_short, new_short; + uint64_t inf_len, obj_size, logblks_rec; + uint32_t l_ea, l_ad, size; + uint32_t last_lb_num, piece_lb_num; + uint64_t last_len, piece_len, last_flags; + uint64_t rest_len, merge_len, last_end; + uint16_t last_part_num, piece_part_num; + uint16_t crclen, cur_alloc; + uint8_t *data, *pos; + const int short_len = sizeof(struct short_ad); + const int long_len = sizeof(struct long_ad); + const int sector_size = context.sector_size; + uint64_t max_len = UDF_ROUNDDOWN(UDF_EXT_MAXLEN, sector_size); + int use_shorts; + + fe = NULL; + efe = NULL; + if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { + fe = &dscr->fe; + data = fe->data; + l_ea = udf_rw32(fe->l_ea); + l_ad = udf_rw32(fe->l_ad); + icb = &fe->icbtag; + inf_len = udf_rw64(fe->inf_len); + logblks_rec = udf_rw64(fe->logblks_rec); + obj_size = 0; + } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { + efe = &dscr->efe; + data = efe->data; + l_ea = udf_rw32(efe->l_ea); + l_ad = udf_rw32(efe->l_ad); + icb = &efe->icbtag; + inf_len = udf_rw64(efe->inf_len); + obj_size = udf_rw64(efe->obj_size); + logblks_rec = udf_rw64(efe->logblks_rec); + } else { + errx(1, "bad tag passed to udf_file_append_blob"); + } + crclen = udf_rw16(dscr->tag.desc_crc_len); + + /* we use shorts if referring inside the metadata partition */ + use_shorts = (udf_rw16(piece->loc.part_num) == context.metadata_part); + + pos = data + l_ea; + cur_alloc = udf_rw16(icb->flags); + size = UDF_EXT_LEN(udf_rw32(piece->len)); + + /* extract last entry as a long_ad */ + memset(&last_piece, 0, sizeof(last_piece)); + last_len = 0; + last_lb_num = 0; + last_part_num = 0; + last_flags = 0; + last_short = NULL; + last_long = NULL; + if (l_ad != 0) { + if (use_shorts) { + assert(cur_alloc == UDF_ICB_SHORT_ALLOC); + pos += l_ad - short_len; + last_short = (struct short_ad *) pos; + last_lb_num = udf_rw32(last_short->lb_num); + last_part_num = udf_rw16(piece->loc.part_num); + last_len = UDF_EXT_LEN(udf_rw32(last_short->len)); + last_flags = UDF_EXT_FLAGS(udf_rw32(last_short->len)); + } else { + assert(cur_alloc == UDF_ICB_LONG_ALLOC); + pos += l_ad - long_len; + last_long = (struct long_ad *) pos; + last_lb_num = udf_rw32(last_long->loc.lb_num); + last_part_num = udf_rw16(last_long->loc.part_num); + last_len = UDF_EXT_LEN(udf_rw32(last_long->len)); + last_flags = UDF_EXT_FLAGS(udf_rw32(last_long->len)); + } + } + + piece_len = UDF_EXT_LEN(udf_rw32(piece->len)); + piece_lb_num = udf_rw32(piece->loc.lb_num); + piece_part_num = udf_rw16(piece->loc.part_num); + + /* try merging */ + rest_len = max_len - last_len; + + merge_len = MIN(piece_len, rest_len); + last_end = last_lb_num + (last_len / sector_size); + if ((piece_lb_num == last_end) && (last_part_num == piece_part_num)) { + /* we can merge */ + last_len += merge_len; + piece_len -= merge_len; + + /* write back merge result */ + if (use_shorts) { + last_short->len = udf_rw32(last_len | last_flags); + } else { + last_long->len = udf_rw32(last_len | last_flags); + } + piece_lb_num += merge_len / sector_size; + } + + if (piece_len) { + /* append new entry */ + pos = data + l_ea + l_ad; + if (use_shorts) { + icb->flags = udf_rw16(UDF_ICB_SHORT_ALLOC); + memset(&new_short, 0, short_len); + new_short.len = udf_rw32(piece_len); + new_short.lb_num = udf_rw32(piece_lb_num); + memcpy(pos, &new_short, short_len); + l_ad += short_len; + crclen += short_len; + } else { + icb->flags = udf_rw16(UDF_ICB_LONG_ALLOC); + piece->len = udf_rw32(piece_len); + piece->loc.lb_num = udf_rw32(piece_lb_num); + memcpy(pos, piece, long_len); + l_ad += long_len; + crclen += long_len; + } + } + piece->len = udf_rw32(0); + + inf_len += size; + obj_size += size; + logblks_rec += UDF_ROUNDUP(size, sector_size) / sector_size; + + dscr->tag.desc_crc_len = udf_rw16(crclen); + if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { + fe->l_ad = udf_rw32(l_ad); + fe->inf_len = udf_rw64(inf_len); + fe->logblks_rec = udf_rw64(logblks_rec); + } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { + efe->l_ad = udf_rw32(l_ad); + efe->inf_len = udf_rw64(inf_len); + efe->obj_size = udf_rw64(inf_len); + efe->logblks_rec = udf_rw64(logblks_rec); + } +} + + +static int +udf_append_file_contents(union dscrptr *dscr, struct long_ad *data_icb, + uint8_t *fdata, off_t flen) +{ + struct long_ad icb; + uint32_t location; + uint16_t vpart; + int sectors; + + if (udf_file_inject_blob(dscr, fdata, flen) == 0) + return 0; + + /* has to be appended in mappings */ + icb = *data_icb; + icb.len = udf_rw32(flen); + while (udf_rw32(icb.len) > 0) + udf_append_file_mapping(dscr, &icb); + udf_validate_tag_and_crc_sums(dscr); + + /* write out data piece */ + vpart = udf_rw16(data_icb->loc.part_num); + location = udf_rw32(data_icb->loc.lb_num); + sectors = udf_datablocks(flen); + + return udf_write_virt(fdata, location, vpart, sectors); +} + + +static int +udf_create_new_file(struct stat *st, union dscrptr **dscr, + int filetype, struct long_ad *icb) +{ + struct file_entry *fe; + struct extfile_entry *efe; + int error; + + fe = NULL; + efe = NULL; + if (context.dscrver == 2) { + error = udf_create_new_fe(&fe, filetype, st); + if (error) + errx(error, "can't create fe"); + *dscr = (union dscrptr *) fe; + icb->longad_uniqueid = udf_rw32(udf_rw64(fe->unique_id)); + } else { + error = udf_create_new_efe(&efe, filetype, st); + if (error) + errx(error, "can't create fe"); + *dscr = (union dscrptr *) efe; + icb->longad_uniqueid = udf_rw32(udf_rw64(efe->unique_id)); + } + + return 0; +} + + +static void +udf_estimate_walk(fsinfo_t *fsopts, + fsnode *root, char *dir, struct udf_stats *stats) +{ + struct fileid_desc *fid; + struct long_ad dummy_ref; + fsnode *cur; + fsinode *fnode; + size_t pathlen = strlen(dir); + char *mydir = dir + pathlen; + off_t sz; + uint32_t nblk, ddoff; + uint32_t softlink_len; + uint8_t *softlink_buf; + int nentries; + int error; + + stats->ndirs++; + + /* + * Count number of directory entries and count directory size; needed + * for the reservation of enough space for the directory. Pity we + * don't keep the FIDs we created. If it turns out to be a issue we + * can cache it later. + */ + fid = (struct fileid_desc *) malloc(context.sector_size); + assert(fid); + + ddoff = 40; /* '..' entry */ + for (cur = root, nentries = 0; cur != NULL; cur = cur->next) { + switch (cur->type & S_IFMT) { + default: + /* what kind of nodes? */ + break; + case S_IFCHR: + case S_IFBLK: + /* not supported yet */ + break; + case S_IFDIR: + if (strcmp(cur->name, ".") == 0) + continue; + /* FALLTHROUGH */ + case S_IFLNK: + case S_IFREG: + /* create dummy FID to see how long name will become */ + memset(&dummy_ref, 0, sizeof(dummy_ref)); + udf_create_fid(ddoff, fid, cur->name, 0, &dummy_ref); + nentries++; + ddoff += udf_fidsize(fid); + break; + } + } + sz = ddoff; + + root->inode->st.st_size = sz; /* max now */ + root->inode->flags |= FI_SIZED; + + nblk = udf_datablocks(sz); + stats->nmetadatablocks += nblk; + + /* for each entry in the directory, there needs to be a (E)FE */ + stats->nmetadatablocks += nentries + 1; + + /* recurse */ + for (cur = root; cur != NULL; cur = cur->next) { + switch (cur->type & S_IFMT) { + default: + /* what kind of nodes? */ + break; + case S_IFDIR: + if (strcmp(cur->name, ".") == 0) + continue; + /* empty dir? */ + if (!cur->child) + break; + mydir[0] = '/'; + strncpy(&mydir[1], cur->name, MAXPATHLEN - pathlen); + udf_estimate_walk(fsopts, cur->child, dir, stats); + mydir[0] = '\0'; + break; + case S_IFCHR: + case S_IFBLK: + /* not supported yet */ + // stats->nfiles++; + break; + case S_IFREG: + fnode = cur->inode; + /* don't double-count hard-links */ + if (!(fnode->flags & FI_SIZED)) { + sz = fnode->st.st_size; + nblk = udf_datablocks(sz); + stats->ndatablocks += nblk; + /* ... */ + fnode->flags |= FI_SIZED; + } + stats->nfiles++; + break; + case S_IFLNK: + /* softlink */ + fnode = cur->inode; + /* don't double-count hard-links */ + if (!(fnode->flags & FI_SIZED)) { + error = udf_encode_symlink(&softlink_buf, + &softlink_len, cur->symlink); + if (error) { + printf("SOFTLINK error %d\n", error); + break; + } + nblk = udf_datablocks(softlink_len); + stats->ndatablocks += nblk; + fnode->flags |= FI_SIZED; + + free(softlink_buf); + } + stats->nfiles++; + break; + } + } +} + + +#define UDF_MAX_CHUNK_SIZE (4*1024*1024) +static int +udf_copy_file(struct stat *st, char *path, fsnode *cur, struct fileid_desc *fid, + struct long_ad *icb) +{ + union dscrptr *dscr; + struct long_ad data_icb; + fsinode *fnode; + off_t sz, chunk, rd; + uint8_t *data; + bool intern; + int nblk; + int f; + int error; + + fnode = cur->inode; + + f = open(path, O_RDONLY); + if (f < 0) { + warn("Can't open file %s for reading", cur->name); + return errno; + } + + /* claim disc space for the (e)fe descriptor for this file */ + udf_metadata_alloc(1, icb); + udf_create_new_file(st, &dscr, UDF_ICB_FILETYPE_RANDOMACCESS, icb); + + sz = fnode->st.st_size; + + chunk = MIN(sz, UDF_MAX_CHUNK_SIZE); + data = malloc(MAX(UDF_ROUNDUP(chunk, context.sector_size), context.sector_size)); + assert(data); + + intern = (udf_datablocks(chunk) == 0); + error = 0; + while (chunk) { + rd = read(f, data, chunk); + if (rd != chunk) { + warn("Short read of file %s", cur->name); + error = errno; + break; + } + + nblk = UDF_ROUNDUP(chunk, context.sector_size) / context.sector_size; + if (chunk && !intern) + udf_data_alloc(nblk, &data_icb); + udf_append_file_contents(dscr, &data_icb, data, chunk); + + sz -= chunk; + chunk = MIN(sz, UDF_MAX_CHUNK_SIZE); + } + close(f); + free(data); + + /* write out dscr (e)fe */ + udf_set_link_cnt(dscr, fnode->nlink); + udf_write_dscr_virt(dscr, udf_rw32(icb->loc.lb_num), + udf_rw16(icb->loc.part_num), 1); + free(dscr); + + /* remember our location for hardlinks */ + cur->inode->fsuse = malloc(sizeof(struct long_ad)); + memcpy(cur->inode->fsuse, icb, sizeof(struct long_ad)); + + return error; +} + + +static int +udf_populate_walk(fsinfo_t *fsopts, fsnode *root, char *dir, + struct long_ad *parent_icb, struct long_ad *dir_icb) +{ + union dscrptr *dir_dscr, *dscr; + struct fileid_desc *fid; + struct long_ad icb, data_icb, dirdata_icb; + fsnode *cur; + fsinode *fnode; + size_t pathlen = strlen(dir); + size_t dirlen; + char *mydir = dir + pathlen; + uint32_t nblk, ddoff; + uint32_t softlink_len; + uint8_t *softlink_buf; + uint8_t *dirdata; + int error, ret, retval; + + /* claim disc space for the (e)fe descriptor for this dir */ + udf_metadata_alloc(1, dir_icb); + + /* create new e(fe) */ + udf_create_new_file(&root->inode->st, &dir_dscr, + UDF_ICB_FILETYPE_DIRECTORY, dir_icb); + + /* allocate memory for the directory contents */ + dirlen = root->inode->st.st_size; + nblk = UDF_ROUNDUP(dirlen, context.sector_size) / context.sector_size; + dirdata = malloc(nblk * context.sector_size); + assert(dirdata); + memset(dirdata, 0, nblk * context.sector_size); + + /* create and append '..' */ + fid = (struct fileid_desc *) dirdata; + ddoff = udf_create_parentfid(fid, parent_icb); + assert(ddoff == 40); + + /* for '..' */ + udf_inc_link(dir_dscr); + + /* recurse */ + retval = 0; + for (cur = root; cur != NULL; cur = cur->next) { + mydir[0] = '/'; + strncpy(&mydir[1], cur->name, MAXPATHLEN - pathlen); + + fid = (struct fileid_desc *) (dirdata + ddoff); + switch (cur->type & S_IFMT) { + default: + /* what kind of nodes? */ + retval = 2; + break; + case S_IFCHR: + case S_IFBLK: + /* not supported */ + retval = 2; + warnx("device node %s not supported", dir); + break; + case S_IFDIR: + /* not an empty dir? */ + if (strcmp(cur->name, ".") == 0) + break; + assert(cur->child); + if (cur->child) { + ret = udf_populate_walk(fsopts, cur->child, + dir, dir_icb, &icb); + if (ret) + retval = 2; + } + udf_create_fid(ddoff, fid, cur->name, + UDF_FILE_CHAR_DIR, &icb); + udf_inc_link(dir_dscr); + ddoff += udf_fidsize(fid); + break; + case S_IFREG: + fnode = cur->inode; + /* don't re-copy hard-links */ + if (!(fnode->flags & FI_WRITTEN)) { + printf("%s\n", dir); + error = udf_copy_file(&fnode->st, dir, cur, + fid, &icb); + if (!error) { + fnode->flags |= FI_WRITTEN; + udf_create_fid(ddoff, fid, cur->name, + 0, &icb); + ddoff += udf_fidsize(fid); + } else { + retval = 2; + } + } else { + /* hardlink! */ + printf("%s (hardlink)\n", dir); + udf_create_fid(ddoff, fid, cur->name, + 0, (struct long_ad *) (fnode->fsuse)); + ddoff += udf_fidsize(fid); + } + fnode->nlink--; + if (fnode->nlink == 0) + free(fnode->fsuse); + break; + case S_IFLNK: + /* softlink */ + fnode = cur->inode; + printf("%s -> %s\n", dir, cur->symlink); + error = udf_encode_symlink(&softlink_buf, + &softlink_len, cur->symlink); + if (error) { + printf("SOFTLINK error %d\n", error); + retval = 2; + break; + } + + udf_metadata_alloc(1, &icb); + udf_create_new_file(&fnode->st, &dscr, + UDF_ICB_FILETYPE_SYMLINK, &icb); + + nblk = udf_datablocks(softlink_len); + if (nblk > 0) + udf_data_alloc(nblk, &data_icb); + udf_append_file_contents(dscr, &data_icb, + softlink_buf, softlink_len); + + /* write out dscr (e)fe */ + udf_inc_link(dscr); + udf_write_dscr_virt(dscr, udf_rw32(icb.loc.lb_num), + udf_rw16(icb.loc.part_num), 1); + + free(dscr); + free(softlink_buf); + + udf_create_fid(ddoff, fid, cur->name, 0, &icb); + ddoff += udf_fidsize(fid); + break; + } + mydir[0] = '\0'; + } + assert(dirlen == ddoff); + + /* pre allocate space for the directory contents */ + memset(&dirdata_icb, 0, sizeof(dirdata_icb)); + nblk = udf_datablocks(dirlen); + + /* claim disc space for the dir contents if needed */ + if (nblk > 0) + udf_fids_alloc(nblk, &dirdata_icb); + + udf_prepare_fids(dir_icb, &dirdata_icb, dirdata, dirlen); + udf_append_file_contents(dir_dscr, &dirdata_icb, dirdata, dirlen); + + /* write out dir_dscr (e)fe */ + udf_write_dscr_virt(dir_dscr, udf_rw32(dir_icb->loc.lb_num), + udf_rw16(dir_icb->loc.part_num), 1); + + free(dirdata); + free(dir_dscr); + return retval; +} + + +static int +udf_populate(const char *dir, fsnode *root, fsinfo_t *fsopts, + struct udf_stats *stats) +{ + struct long_ad rooticb; + static char path[MAXPATHLEN+1]; + int error; + + strncpy(path, dir, sizeof(path)); + error = udf_populate_walk(fsopts, root, path, &rooticb, &rooticb); + + return error; +} + + +static void +udf_enumerate_and_estimate(const char *dir, fsnode *root, fsinfo_t *fsopts, + struct udf_stats *stats) +{ + char path[MAXPATHLEN + 1]; + off_t proposed_size; + uint32_t n, nblk, nmetablk, nbytes; + uint32_t spareable_blocks, spareable_blockingnr; + + strncpy(path, dir, sizeof(path)); + + /* calculate strict minimal size */ + udf_estimate_walk(fsopts, root, path, stats); +#if 0 + printf("ndirs %d\n", stats->ndirs); + printf("nfiles %d\n", stats->nfiles); + printf("ndata_blocks %d\n", stats->ndatablocks); + printf("nmetadata_blocks %d\n", stats->nmetadatablocks); + printf("\n"); +#endif + + /* adjust for options : free file nodes */ + if (fsopts->freefiles) { + /* be mercifull and reserve more for the FID */ + stats->nmetadatablocks += fsopts->freefiles * 1.5; + } else if ((n = fsopts->freefilepc)) { + stats->nmetadatablocks += (stats->nmetadatablocks*n) / (100-n); + } + + /* adjust for options : free data blocks */ + if (fsopts->freeblocks) { + stats->ndatablocks += fsopts->freeblocks; + } else if ((n = fsopts->freeblockpc)) { + stats->ndatablocks += (stats->ndatablocks * n) / (100-n); + } + + /* rough predictor of minimum disc size */ + nblk = stats->ndatablocks + stats->nmetadatablocks; + if (context.format_flags & FORMAT_META) { + float meta_p; + double factor; + + meta_p = (float) context.meta_perc/100.0; + factor = meta_p / (1.0 - meta_p); + + /* add space for metadata partition including some slack */ + nmetablk = factor * nblk + 32; + nblk = stats->ndatablocks + nmetablk; + + /* free space maps */ + nbytes = ceil((double) nblk * (1.0/8.0)); + nblk += 1 + (nbytes + context.sector_size-1)/context.sector_size; + if (!(context.format_flags & FORMAT_READONLY)) { + nbytes = ceil((double) nmetablk * (1.0/8.0)); + nblk += 1 + (nbytes + context.sector_size-1)/context.sector_size; + } + } else if (context.format_flags & FORMAT_SEQUENTIAL) { + /* nothing */ + } else { + if (!(context.format_flags & FORMAT_READONLY)) { + nbytes = ceil((double) nblk * (1.0/8.0)); + nblk += 1 + (nbytes + context.sector_size-1)/ + context.sector_size; + } + } + + /* + * Make extra room for spareable table if requested + */ + if (context.format_flags & FORMAT_SPAREABLE) { + spareable_blockingnr = udf_spareable_blockingnr(); + spareable_blocks = udf_spareable_blocks(); + + nblk += spareable_blocks * spareable_blockingnr; + nblk += spareable_blockingnr; /* slack */ + } + + nblk += 256; /* pre-volume space */ + nblk += 256; /* post-volume space */ + nblk += 1024; /* safeguard */ + + /* try to honour minimum size */ + n = fsopts->minsize / fsopts->sectorsize; + if (nblk < n) { + stats->ndatablocks += (n - nblk); + nblk += n - nblk; + } + proposed_size = (off_t) nblk * fsopts->sectorsize; + /* sanity size */ + if (proposed_size < 512*1024) + proposed_size = 512*1024; + + if (fsopts->size) { + if (fsopts->size < proposed_size) + errx(1, "makefs_udf: won't fit on disc!"); + } else { + fsopts->size = proposed_size; + } + + fsopts->inodes = stats->nfiles + stats->ndirs; +} + + +void +udf_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) +{ + struct udf_stats stats; + uint64_t truncate_len; + uint32_t last_sector, ext; + char scrap[255]; + int error; + + /* setup */ + emul_sectorsize = fsopts->sectorsize; + emul_size = 0; + context.sector_size = fsopts->sectorsize; + + /* names */ + error = udf_proces_names(); + if (error) + errx(1, "bad names given"); + + /* open disc device or emulated file */ + if (udf_opendisc(image, O_CREAT)) { + udf_closedisc(); + errx(1, "can't open %s", image); + } + fsopts->fd = dev_fd; + + /* determine format */ + if (udf_readonly_format()) + req_enable |= FORMAT_READONLY; + // printf("req_enable %d, req_disable %d\n", req_enable, req_disable); + error = udf_derive_format(req_enable, req_disable); + if (error) { + udf_closedisc(); + errx(1, "can't derive format from media/settings"); + } + + /* estimate the amount of space needed */ + memset(&stats, 0, sizeof(stats)); + udf_enumerate_and_estimate(dir, root, fsopts, &stats); + + printf("Calculated size of `%s' is " + "%"PRIu64" KiB, %"PRIu64" MiB, %"PRIu64" GiB with %ld inodes\n", + image, + (uint64_t) fsopts->size/1024, + (uint64_t) fsopts->size/1024/1024, + (uint64_t) fsopts->size/1024/1024/1024, + (long)fsopts->inodes); + emul_size = MAX(emul_size, fsopts->size); + if ((fsopts->maxsize > 0) && (emul_size > fsopts->maxsize)) + errx(1, "won't fit due to set maximum disk size"); + + /* prepare disc if necessary (recordables mainly) */ + error = udf_prepare_disc(); + if (error) { + udf_closedisc(); + errx(1, "preparing disc failed"); + } + + /* update mmc info but now with correct size */ + udf_update_discinfo(); + udf_dump_discinfo(&mmc_discinfo); + + printf("Building disc compatible with UDF version %x to %x\n\n", + context.min_udf, context.max_udf); +// (void)snprintb(scrap, sizeof(scrap), FORMAT_FLAGBITS, +// (uint64_t) context.format_flags); + printf("UDF properties %s\n", scrap); + printf("Volume set `%s'\n", context.volset_name); + printf("Primary volume `%s`\n", context.primary_name); + printf("Logical volume `%s`\n", context.logvol_name); + if (context.format_flags & FORMAT_META) + printf("Metadata percentage %d%% (%d%% used)\n", + context.meta_perc, + (int) ceilf(100.0*stats.nmetadatablocks/stats.ndatablocks)); + printf("\n"); + + /* prefix */ + udf_allow_writing(); + if (udf_do_newfs_prefix()) { + udf_closedisc(); + errx(1, "basic setup failed"); + } + + /* update context */ + context.unique_id = 0; + + /* add all directories */ + error = udf_populate(dir, root, fsopts, &stats); + + if (!error) { + /* update values for integrity sequence */ + context.num_files = stats.nfiles; + context.num_directories = stats.ndirs; + + udf_do_newfs_postfix(); + + if (S_ISREG(dev_fd_stat.st_mode) && + (context.format_flags & FORMAT_VAT)) { + udf_translate_vtop(context.alloc_pos[context.data_part], + context.data_part, + &last_sector, &ext); + truncate_len = (uint64_t) last_sector * context.sector_size; + + printf("\nTruncing the disc-image to allow for VAT\n"); + printf("Free space left on this volume approx. " + "%"PRIu64" KiB, %"PRIu64" MiB\n", + (fsopts->size - truncate_len)/1024, + (fsopts->size - truncate_len)/1024/1024); + ftruncate(dev_fd, truncate_len); + } + } + udf_closedisc(); + + if (error == 2) + errx(error, "not all files could be added"); + if (error == 1) + errx(error, "creation of %s failed", image); + return; +} diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf/Makefile b/vendor/bdj-sdk/host/src/makefs_termux/udf/Makefile new file mode 100644 index 0000000..0c50ef9 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf/Makefile @@ -0,0 +1,19 @@ +# $NetBSD: Makefile.inc,v 1.2 2013/08/05 18:45:00 reinoud Exp $ +# + +UDF= ${NETBSDSRCDIR}/sys/fs/udf +UDF_NEWFS= ${NETBSDSRCDIR}/sbin/newfs_udf +FSCK= ${NETBSDSRCDIR}/sbin/fsck # use progress meter. + +.PATH: ${.CURDIR}/udf ${UDF} ${UDF_NEWFS} ${FSCK} + +CPPFLAGS+= -I${UDF} -I${UDF_NEWFS} -I${FSCK} + +SRCS += udf_create.c udf_write.c udf_osta.c newfs_udf.c + +objs: + $(CC) -o udf_osta.o udf_osta.c + $(CC) -o udf_create.o udf_create.c + $(CC) -o udf_write.o udf_write.c + ar rs libudf.a *.o + diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf/Makefile.inc b/vendor/bdj-sdk/host/src/makefs_termux/udf/Makefile.inc new file mode 100644 index 0000000..706965d --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf/Makefile.inc @@ -0,0 +1,16 @@ +# $NetBSD: Makefile.inc,v 1.2 2013/08/05 18:45:00 reinoud Exp $ +# + +UDF= ${NETBSDSRCDIR}/sys/fs/udf +UDF_NEWFS= ${NETBSDSRCDIR}/sbin/newfs_udf +FSCK= ${NETBSDSRCDIR}/sbin/fsck # use progress meter. + +.PATH: ${.CURDIR}/udf ${UDF} ${UDF_NEWFS} ${FSCK} + +CPPFLAGS+= -I${UDF} -I${UDF_NEWFS} -I${FSCK} + +SRCS += udf_create.c udf_write.c udf_osta.c + +libs: + $(CC) $(SRCS) -o libudf.o + diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf/cdio.h b/vendor/bdj-sdk/host/src/makefs_termux/udf/cdio.h new file mode 100644 index 0000000..86e2375 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf/cdio.h @@ -0,0 +1,429 @@ +/* $NetBSD: cdio.h,v 1.34 2015/09/06 06:01:02 dholland Exp $ */ + +#ifndef _SYS_CDIO_H_ +#define _SYS_CDIO_H_ + +#include + +// #include + +/* Shared between kernel & process */ + +union msf_lba { + struct { + u_char unused; + u_char minute; + u_char second; + u_char frame; + } msf; + uint32_t lba; + u_char addr[4]; +}; + +struct cd_toc_entry { + u_char nothing1; +#if BYTE_ORDER == LITTLE_ENDIAN + uint32_t control:4; + uint32_t addr_type:4; +#endif +#if BYTE_ORDER == BIG_ENDIAN + uint32_t addr_type:4; + uint32_t control:4; +#endif + u_char track; + u_char nothing2; + union msf_lba addr; +}; + +struct cd_sub_channel_header { + u_char nothing1; + u_char audio_status; +#define CD_AS_AUDIO_INVALID 0x00 +#define CD_AS_PLAY_IN_PROGRESS 0x11 +#define CD_AS_PLAY_PAUSED 0x12 +#define CD_AS_PLAY_COMPLETED 0x13 +#define CD_AS_PLAY_ERROR 0x14 +#define CD_AS_NO_STATUS 0x15 + u_char data_len[2]; +}; + +struct cd_sub_channel_q_data { + u_char data_format; +#if BYTE_ORDER == LITTLE_ENDIAN + uint32_t control:4; + uint32_t addr_type:4; +#endif +#if BYTE_ORDER == BIG_ENDIAN + uint32_t addr_type:4; + uint32_t control:4; +#endif + u_char track_number; + u_char index_number; + u_char absaddr[4]; + u_char reladdr[4]; +#if BYTE_ORDER == LITTLE_ENDIAN + uint32_t :7; + uint32_t mc_valid:1; +#endif +#if BYTE_ORDER == BIG_ENDIAN + uint32_t mc_valid:1; + uint32_t :7; +#endif + u_char mc_number[15]; +#if BYTE_ORDER == LITTLE_ENDIAN + uint32_t :7; + uint32_t ti_valid:1; +#endif +#if BYTE_ORDER == BIG_ENDIAN + uint32_t ti_valid:1; + uint32_t :7; +#endif + u_char ti_number[15]; +}; + +struct cd_sub_channel_position_data { + u_char data_format; +#if BYTE_ORDER == LITTLE_ENDIAN + uint32_t control:4; + uint32_t addr_type:4; +#endif +#if BYTE_ORDER == BIG_ENDIAN + uint32_t addr_type:4; + uint32_t control:4; +#endif + u_char track_number; + u_char index_number; + union msf_lba absaddr; + union msf_lba reladdr; +}; + +struct cd_sub_channel_media_catalog { + u_char data_format; + u_char nothing1; + u_char nothing2; + u_char nothing3; +#if BYTE_ORDER == LITTLE_ENDIAN + uint32_t :7; + uint32_t mc_valid:1; +#endif +#if BYTE_ORDER == BIG_ENDIAN + uint32_t mc_valid:1; + uint32_t :7; +#endif + u_char mc_number[15]; +}; + +struct cd_sub_channel_track_info { + u_char data_format; + u_char nothing1; + u_char track_number; + u_char nothing2; +#if BYTE_ORDER == LITTLE_ENDIAN + uint32_t :7; + uint32_t ti_valid:1; +#endif +#if BYTE_ORDER == BIG_ENDIAN + uint32_t ti_valid:1; + uint32_t :7; +#endif + u_char ti_number[15]; +}; + +struct cd_sub_channel_info { + struct cd_sub_channel_header header; + union { + struct cd_sub_channel_q_data q_data; + struct cd_sub_channel_position_data position; + struct cd_sub_channel_media_catalog media_catalog; + struct cd_sub_channel_track_info track_info; + } what; +}; + +/* + * Ioctls for the CD drive + */ +struct ioc_play_track { + u_char start_track; + u_char start_index; + u_char end_track; + u_char end_index; +}; + +#define CDIOCPLAYTRACKS _IOW('c', 1, struct ioc_play_track) +struct ioc_play_blocks { + int blk; + int len; +}; +#define CDIOCPLAYBLOCKS _IOW('c', 2, struct ioc_play_blocks) + +struct ioc_read_subchannel { + u_char address_format; +#define CD_LBA_FORMAT 1 +#define CD_MSF_FORMAT 2 + u_char data_format; +#define CD_SUBQ_DATA 0 +#define CD_CURRENT_POSITION 1 +#define CD_MEDIA_CATALOG 2 +#define CD_TRACK_INFO 3 + u_char track; + int data_len; + struct cd_sub_channel_info *data; +}; +#define CDIOCREADSUBCHANNEL _IOWR('c', 3, struct ioc_read_subchannel ) + +#ifdef _KERNEL +/* As above, but with the buffer following the request for in-kernel users. */ +struct ioc_read_subchannel_buf { + struct ioc_read_subchannel req; + struct cd_sub_channel_info info; +}; +#define CDIOCREADSUBCHANNEL_BUF _IOWR('c', 3, struct ioc_read_subchannel_buf) +#endif + +struct ioc_toc_header { + u_short len; + u_char starting_track; + u_char ending_track; +}; + +#define CDIOREADTOCHEADER _IOR('c', 4, struct ioc_toc_header) + +struct ioc_read_toc_entry { + u_char address_format; + u_char starting_track; + u_short data_len; + struct cd_toc_entry *data; +}; +#define CDIOREADTOCENTRIES _IOWR('c', 5, struct ioc_read_toc_entry) +#define CDIOREADTOCENTRYS CDIOREADTOCENTRIES + +#ifdef _KERNEL +/* As above, but with the buffer following the request for in-kernel users. */ +struct ioc_read_toc_entry_buf { + struct ioc_read_toc_entry req; + struct cd_toc_entry entry[100]; /* NB: 8 bytes each */ +}; +#define CDIOREADTOCENTRIES_BUF _IOWR('c', 5, struct ioc_read_toc_entry_buf) +#endif + +/* read LBA start of a given session; 0=last, others not yet supported */ +#define CDIOREADMSADDR _IOWR('c', 6, int) + +struct ioc_patch { + u_char patch[4]; /* one for each channel */ +}; +#define CDIOCSETPATCH _IOW('c', 9, struct ioc_patch) + +struct ioc_vol { + u_char vol[4]; /* one for each channel */ +}; +#define CDIOCGETVOL _IOR('c', 10, struct ioc_vol) +#define CDIOCSETVOL _IOW('c', 11, struct ioc_vol) +#define CDIOCSETMONO _IO('c', 12) +#define CDIOCSETSTEREO _IO('c', 13) +#define CDIOCSETMUTE _IO('c', 14) +#define CDIOCSETLEFT _IO('c', 15) +#define CDIOCSETRIGHT _IO('c', 16) +#define CDIOCSETDEBUG _IO('c', 17) +#define CDIOCCLRDEBUG _IO('c', 18) +#define CDIOCPAUSE _IO('c', 19) +#define CDIOCRESUME _IO('c', 20) +#define CDIOCRESET _IO('c', 21) +#define CDIOCSTART _IO('c', 22) +#define CDIOCSTOP _IO('c', 23) +#define CDIOCEJECT _IO('c', 24) +#define CDIOCALLOW _IO('c', 25) +#define CDIOCPREVENT _IO('c', 26) +#define CDIOCCLOSE _IO('c', 27) + +struct ioc_play_msf { + u_char start_m; + u_char start_s; + u_char start_f; + u_char end_m; + u_char end_s; + u_char end_f; +}; +#define CDIOCPLAYMSF _IOW('c', 25, struct ioc_play_msf) + +struct ioc_load_unload { + u_char options; +#define CD_LU_ABORT 0x1 /* NOTE: These are the same as the ATAPI */ +#define CD_LU_UNLOAD 0x2 /* op values for the LOAD_UNLOAD command */ +#define CD_LU_LOAD 0x3 + u_char slot; +}; +#define CDIOCLOADUNLOAD _IOW('c', 26, struct ioc_load_unload) + + +#if defined(_KERNEL) || defined(_EXPOSE_MMC) +/* not exposed to userland yet until its completely mature */ +/* + * MMC device abstraction interface. + * + * It gathers information from GET_CONFIGURATION, READ_DISCINFO, + * READ_TRACKINFO, READ_TOC2, READ_CD_CAPACITY and GET_CONFIGURATION + * SCSI/ATAPI calls regardless if its a legacy CD-ROM/DVD-ROM device or a MMC + * standard recordable device. + */ +struct mmc_discinfo { + uint16_t mmc_profile; + uint16_t mmc_class; + + uint8_t disc_state; + uint8_t last_session_state; + uint8_t bg_format_state; + uint8_t link_block_penalty; /* in sectors */ + + uint64_t mmc_cur; /* current MMC_CAPs */ + uint64_t mmc_cap; /* possible MMC_CAPs */ + + uint32_t disc_flags; /* misc flags */ + + uint32_t disc_id; + uint64_t disc_barcode; + uint8_t application_code; /* 8 bit really */ + + uint8_t unused1[3]; /* padding */ + + uint32_t last_possible_lba; /* last leadout start adr. */ + uint32_t sector_size; + + uint16_t num_sessions; + uint16_t num_tracks; /* derived */ + + uint16_t first_track; + uint16_t first_track_last_session; + uint16_t last_track_last_session; + + uint16_t unused2; /* padding/misc info resv. */ + + uint16_t reserved1[4]; /* MMC-5 track resources */ + uint32_t reserved2[3]; /* MMC-5 POW resources */ + + uint32_t reserved3[8]; /* MMC-5+ */ +}; +#define MMCGETDISCINFO _IOR('c', 28, struct mmc_discinfo) + +#define MMC_CLASS_UNKN 0 +#define MMC_CLASS_DISC 1 +#define MMC_CLASS_CD 2 +#define MMC_CLASS_DVD 3 +#define MMC_CLASS_MO 4 +#define MMC_CLASS_BD 5 +#define MMC_CLASS_FILE 0xffff /* emulation mode */ + +#define MMC_DFLAGS_BARCODEVALID (1 << 0) /* barcode is present and valid */ +#define MMC_DFLAGS_DISCIDVALID (1 << 1) /* discid is present and valid */ +#define MMC_DFLAGS_APPCODEVALID (1 << 2) /* application code valid */ +#define MMC_DFLAGS_UNRESTRICTED (1 << 3) /* restricted, then set app. code */ + +#define MMC_DFLAGS_FLAGBITS \ + "\10\1BARCODEVALID\2DISCIDVALID\3APPCODEVALID\4UNRESTRICTED" + +#define MMC_CAP_SEQUENTIAL (1 << 0) /* sequential writable only */ +#define MMC_CAP_RECORDABLE (1 << 1) /* record-able; i.e. not static */ +#define MMC_CAP_ERASABLE (1 << 2) /* drive can erase sectors */ +#define MMC_CAP_BLANKABLE (1 << 3) /* media can be blanked */ +#define MMC_CAP_FORMATTABLE (1 << 4) /* media can be formatted */ +#define MMC_CAP_REWRITABLE (1 << 5) /* media can be rewritten */ +#define MMC_CAP_MRW (1 << 6) /* Mount Rainier formatted */ +#define MMC_CAP_PACKET (1 << 7) /* using packet recording */ +#define MMC_CAP_STRICTOVERWRITE (1 << 8) /* only writes a packet at a time */ +#define MMC_CAP_PSEUDOOVERWRITE (1 << 9) /* overwrite through replacement */ +#define MMC_CAP_ZEROLINKBLK (1 << 10) /* zero link block length capable */ +#define MMC_CAP_HW_DEFECTFREE (1 << 11) /* hardware defect management */ + +#define MMC_CAP_FLAGBITS \ + "\10\1SEQUENTIAL\2RECORDABLE\3ERASABLE\4BLANKABLE\5FORMATTABLE" \ + "\6REWRITABLE\7MRW\10PACKET\11STRICTOVERWRITE\12PSEUDOOVERWRITE" \ + "\13ZEROLINKBLK\14HW_DEFECTFREE" + +#define MMC_STATE_EMPTY 0 +#define MMC_STATE_INCOMPLETE 1 +#define MMC_STATE_FULL 2 +#define MMC_STATE_CLOSED 3 + +#define MMC_BGFSTATE_UNFORM 0 +#define MMC_BGFSTATE_STOPPED 1 +#define MMC_BGFSTATE_RUNNING 2 +#define MMC_BGFSTATE_COMPLETED 3 + + +struct mmc_trackinfo { + uint16_t tracknr; /* IN/OUT */ + uint16_t sessionnr; + + uint8_t track_mode; + uint8_t data_mode; + + uint16_t flags; + + uint32_t track_start; + uint32_t next_writable; + uint32_t free_blocks; + uint32_t packet_size; + uint32_t track_size; + uint32_t last_recorded; +}; +#define MMCGETTRACKINFO _IOWR('c', 29, struct mmc_trackinfo) + +#define MMC_TRACKINFO_COPY (1 << 0) +#define MMC_TRACKINFO_DAMAGED (1 << 1) +#define MMC_TRACKINFO_FIXED_PACKET (1 << 2) +#define MMC_TRACKINFO_INCREMENTAL (1 << 3) +#define MMC_TRACKINFO_BLANK (1 << 4) +#define MMC_TRACKINFO_RESERVED (1 << 5) +#define MMC_TRACKINFO_NWA_VALID (1 << 6) +#define MMC_TRACKINFO_LRA_VALID (1 << 7) +#define MMC_TRACKINFO_DATA (1 << 8) +#define MMC_TRACKINFO_AUDIO (1 << 9) +#define MMC_TRACKINFO_AUDIO_4CHAN (1 << 10) +#define MMC_TRACKINFO_PRE_EMPH (1 << 11) + +#define MMC_TRACKINFO_FLAGBITS \ + "\10\1COPY\2DAMAGED\3FIXEDPACKET\4INCREMENTAL\5BLANK" \ + "\6RESERVED\7NWA_VALID\10LRA_VALID\11DATA\12AUDIO" \ + "\13AUDIO_4CHAN\14PRE_EMPH" + +struct mmc_op { + uint16_t operation; /* IN */ + uint16_t mmc_profile; /* IN */ + + /* parameters to operation */ + uint16_t tracknr; /* IN */ + uint16_t sessionnr; /* IN */ + uint32_t extent; /* IN */ + + uint32_t reserved[4]; +}; +#define MMCOP _IOWR('c', 30, struct mmc_op) + +#define MMC_OP_SYNCHRONISECACHE 1 +#define MMC_OP_CLOSETRACK 2 +#define MMC_OP_CLOSESESSION 3 +#define MMC_OP_FINALISEDISC 4 +#define MMC_OP_RESERVETRACK 5 +#define MMC_OP_RESERVETRACK_NWA 6 +#define MMC_OP_UNRESERVETRACK 7 +#define MMC_OP_REPAIRTRACK 8 +#define MMC_OP_UNCLOSELASTSESSION 9 +#define MMC_OP_MAX 9 + +struct mmc_writeparams { + uint16_t tracknr; /* IN */ + uint16_t mmc_class; /* IN */ + uint32_t mmc_cur; /* IN */ + uint32_t blockingnr; /* IN */ + + /* when tracknr == 0 */ + uint8_t track_mode; /* IN; normally 5 */ + uint8_t data_mode; /* IN; normally 2 */ +}; +#define MMC_TRACKMODE_DEFAULT 5 /* data, incremental recording */ +#define MMC_DATAMODE_DEFAULT 2 /* CDROM XA disc */ +#define MMCSETUPWRITEPARAMS _IOW('c', 31, struct mmc_writeparams) + +#endif /* _KERNEL || _EXPOSE_MMC */ + +#endif /* !_SYS_CDIO_H_ */ diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf/cdio_mmc_structs.h b/vendor/bdj-sdk/host/src/makefs_termux/udf/cdio_mmc_structs.h new file mode 100644 index 0000000..8e5992d --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf/cdio_mmc_structs.h @@ -0,0 +1,163 @@ +/* $NetBSD: cdio_mmc_structs.h,v 1.1 2013/08/05 18:44:16 reinoud Exp $ */ + +/* + * Copyright (c) 2006, 2008, 2013 Reinoud Zandijk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR ``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 AUTHOR 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. + * + */ + +#ifndef _CDIO_MMC_EMU_H_ +#define _CDIO_MMC_EMU_H_ + +#include + +/* + * MMC device abstraction interface. + * + * It gathers information from GET_CONFIGURATION, READ_DISCINFO, + * READ_TRACKINFO, READ_TOC2, READ_CD_CAPACITY and GET_CONFIGURATION + * SCSI/ATAPI calls regardless if its a legacy CD-ROM/DVD-ROM device or a MMC + * standard recordable device. + */ +struct mmc_discinfo { + uint16_t mmc_profile; + uint16_t mmc_class; + + uint8_t disc_state; + uint8_t last_session_state; + uint8_t bg_format_state; + uint8_t link_block_penalty; /* in sectors */ + + uint64_t mmc_cur; /* current MMC_CAPs */ + uint64_t mmc_cap; /* possible MMC_CAPs */ + + uint32_t disc_flags; /* misc flags */ + + uint32_t disc_id; + uint64_t disc_barcode; + uint8_t application_code; /* 8 bit really */ + + uint8_t unused1[3]; /* padding */ + + uint32_t last_possible_lba; /* last leadout start adr. */ + uint32_t sector_size; + + uint16_t num_sessions; + uint16_t num_tracks; /* derived */ + + uint16_t first_track; + uint16_t first_track_last_session; + uint16_t last_track_last_session; + + uint16_t unused2; /* padding/misc info resv. */ + + uint16_t reserved1[4]; /* MMC-5 track resources */ + uint32_t reserved2[3]; /* MMC-5 POW resources */ + + uint32_t reserved3[8]; /* MMC-5+ */ +}; +#define MMCGETDISCINFO _IOR('c', 28, struct mmc_discinfo) + +#define MMC_CLASS_UNKN 0 +#define MMC_CLASS_DISC 1 +#define MMC_CLASS_CD 2 +#define MMC_CLASS_DVD 3 +#define MMC_CLASS_MO 4 +#define MMC_CLASS_BD 5 +#define MMC_CLASS_FILE 0xffff /* emulation mode */ + +#define MMC_DFLAGS_BARCODEVALID (1 << 0) /* barcode is present and valid */ +#define MMC_DFLAGS_DISCIDVALID (1 << 1) /* discid is present and valid */ +#define MMC_DFLAGS_APPCODEVALID (1 << 2) /* application code valid */ +#define MMC_DFLAGS_UNRESTRICTED (1 << 3) /* restricted, then set app. code */ + +#define MMC_DFLAGS_FLAGBITS \ + "\10\1BARCODEVALID\2DISCIDVALID\3APPCODEVALID\4UNRESTRICTED" + +#define MMC_CAP_SEQUENTIAL (1 << 0) /* sequential writable only */ +#define MMC_CAP_RECORDABLE (1 << 1) /* record-able; i.e. not static */ +#define MMC_CAP_ERASABLE (1 << 2) /* drive can erase sectors */ +#define MMC_CAP_BLANKABLE (1 << 3) /* media can be blanked */ +#define MMC_CAP_FORMATTABLE (1 << 4) /* media can be formatted */ +#define MMC_CAP_REWRITABLE (1 << 5) /* media can be rewritten */ +#define MMC_CAP_MRW (1 << 6) /* Mount Rainier formatted */ +#define MMC_CAP_PACKET (1 << 7) /* using packet recording */ +#define MMC_CAP_STRICTOVERWRITE (1 << 8) /* only writes a packet at a time */ +#define MMC_CAP_PSEUDOOVERWRITE (1 << 9) /* overwrite through replacement */ +#define MMC_CAP_ZEROLINKBLK (1 << 10) /* zero link block length capable */ +#define MMC_CAP_HW_DEFECTFREE (1 << 11) /* hardware defect management */ + +#define MMC_CAP_FLAGBITS \ + "\10\1SEQUENTIAL\2RECORDABLE\3ERASABLE\4BLANKABLE\5FORMATTABLE" \ + "\6REWRITABLE\7MRW\10PACKET\11STRICTOVERWRITE\12PSEUDOOVERWRITE" \ + "\13ZEROLINKBLK\14HW_DEFECTFREE" + +#define MMC_STATE_EMPTY 0 +#define MMC_STATE_INCOMPLETE 1 +#define MMC_STATE_FULL 2 +#define MMC_STATE_CLOSED 3 + +#define MMC_BGFSTATE_UNFORM 0 +#define MMC_BGFSTATE_STOPPED 1 +#define MMC_BGFSTATE_RUNNING 2 +#define MMC_BGFSTATE_COMPLETED 3 + + +struct mmc_trackinfo { + uint16_t tracknr; /* IN/OUT */ + uint16_t sessionnr; + + uint8_t track_mode; + uint8_t data_mode; + + uint16_t flags; + + uint32_t track_start; + uint32_t next_writable; + uint32_t free_blocks; + uint32_t packet_size; + uint32_t track_size; + uint32_t last_recorded; +}; +#define MMCGETTRACKINFO _IOWR('c', 29, struct mmc_trackinfo) + +#define MMC_TRACKINFO_COPY (1 << 0) +#define MMC_TRACKINFO_DAMAGED (1 << 1) +#define MMC_TRACKINFO_FIXED_PACKET (1 << 2) +#define MMC_TRACKINFO_INCREMENTAL (1 << 3) +#define MMC_TRACKINFO_BLANK (1 << 4) +#define MMC_TRACKINFO_RESERVED (1 << 5) +#define MMC_TRACKINFO_NWA_VALID (1 << 6) +#define MMC_TRACKINFO_LRA_VALID (1 << 7) +#define MMC_TRACKINFO_DATA (1 << 8) +#define MMC_TRACKINFO_AUDIO (1 << 9) +#define MMC_TRACKINFO_AUDIO_4CHAN (1 << 10) +#define MMC_TRACKINFO_PRE_EMPH (1 << 11) + +#define MMC_TRACKINFO_FLAGBITS \ + "\10\1COPY\2DAMAGED\3FIXEDPACKET\4INCREMENTAL\5BLANK" \ + "\6RESERVED\7NWA_VALID\10LRA_VALID\11DATA\12AUDIO" \ + "\13AUDIO_4CHAN\14PRE_EMPH" + +#endif /* _CDIO_MMC_EMU_H_ */ + diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf/ecma167-udf.h b/vendor/bdj-sdk/host/src/makefs_termux/udf/ecma167-udf.h new file mode 100644 index 0000000..17dc7de --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf/ecma167-udf.h @@ -0,0 +1,840 @@ +/* $NetBSD: ecma167-udf.h,v 1.17 2022/03/18 16:06:18 reinoud Exp $ */ + +/*- + * Copyright (c) 2003, 2004, 2005, 2006, 2008, 2009, 2017, 2018 + * Reinoud Zandijk + * Copyright (c) 2001, 2002 Scott Long + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR 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 AUTHOR 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. + * + * + * Extended and adapted for UDFv2.50+ bij Reinoud Zandijk based on the + * original by Scott Long. + * + * 20030508 Made some small typo and explanatory comments + * 20030510 Added UDF 2.01 structures + * 20030519 Added/correct comments on multi-partitioned logical volume space + * 20050616 Added pseudo overwrite + * 20050624 Added the missing extended attribute types and `magic values'. + * 20051106 Reworked some implementation use parts + * + */ + + +#ifndef _FS_UDF_ECMA167_UDF_H_ +#define _FS_UDF_ECMA167_UDF_H_ + + +/* + * in case of an older gcc versions, define the __packed as explicit + * attribute + */ + +/* + * You may specify the `aligned' and `transparent_union' attributes either in + * a `typedef' declaration or just past the closing curly brace of a complete + * enum, struct or union type _definition_ and the `packed' attribute only + * past the closing brace of a definition. You may also specify attributes + * between the enum, struct or union tag and the name of the type rather than + * after the closing brace. +*/ + +#ifndef __packed +#define __packed __attribute__((packed)) +#endif + + +/* ecma167-udf.h */ + +/* Volume recognition sequence ECMA 167 rev. 3 16.1 */ +struct vrs_desc { + uint8_t struct_type; + uint8_t identifier[5]; + uint8_t version; + uint8_t data[2041]; +} __packed; + + +#define VRS_NSR02 "NSR02" +#define VRS_NSR03 "NSR03" +#define VRS_BEA01 "BEA01" +#define VRS_TEA01 "TEA01" +#define VRS_CD001 "CD001" +#define VRS_CDW02 "CDW02" + + +/* Structure/definitions/constants a la ECMA 167 rev. 3 */ + + +#define MAX_TAGID_VOLUMES 9 +/* Tag identifiers */ +enum { + TAGID_SPARING_TABLE = 0, + TAGID_PRI_VOL = 1, + TAGID_ANCHOR = 2, + TAGID_VOL = 3, + TAGID_IMP_VOL = 4, + TAGID_PARTITION = 5, + TAGID_LOGVOL = 6, + TAGID_UNALLOC_SPACE = 7, + TAGID_TERM = 8, + TAGID_LOGVOL_INTEGRITY= 9, + TAGID_FSD = 256, + TAGID_FID = 257, + TAGID_ALLOCEXTENT = 258, + TAGID_INDIRECTENTRY = 259, + TAGID_ICB_TERM = 260, + TAGID_FENTRY = 261, + TAGID_EXTATTR_HDR = 262, + TAGID_UNALL_SP_ENTRY = 263, + TAGID_SPACE_BITMAP = 264, + TAGID_PART_INTEGRITY = 265, + TAGID_EXTFENTRY = 266, + TAGID_MAX = 266 +}; + + +enum { + UDF_DOMAIN_FLAG_HARD_WRITE_PROTECT = 1, + UDF_DOMAIN_FLAG_SOFT_WRITE_PROTECT = 2 +}; + + +enum { + UDF_ACCESSTYPE_NOT_SPECIFIED = 0, /* unknown */ + UDF_ACCESSTYPE_PSEUDO_OVERWITE = 0, /* pseudo overwritable, e.g. BD-R's LOW */ + UDF_ACCESSTYPE_READ_ONLY = 1, /* really only readable */ + UDF_ACCESSTYPE_WRITE_ONCE = 2, /* write once and you're done */ + UDF_ACCESSTYPE_REWRITEABLE = 3, /* may need extra work to rewrite */ + UDF_ACCESSTYPE_OVERWRITABLE = 4 /* no limits on rewriting; e.g. harddisc*/ +}; + + +/* Descriptor tag [3/7.2] */ +struct desc_tag { + uint16_t id; + uint16_t descriptor_ver; + uint8_t cksum; + uint8_t reserved; + uint16_t serial_num; + uint16_t desc_crc; + uint16_t desc_crc_len; + uint32_t tag_loc; +} __packed; +#define UDF_DESC_TAG_LENGTH 16 + + +/* Recorded Address [4/7.1] */ +struct lb_addr { /* within partition space */ + uint32_t lb_num; + uint16_t part_num; +} __packed; + + +/* Extent Descriptor [3/7.1] */ +struct extent_ad { + uint32_t len; + uint32_t loc; +} __packed; + + +/* Short Allocation Descriptor [4/14.14.1] */ +struct short_ad { + uint32_t len; + uint32_t lb_num; +} __packed; + + +/* Long Allocation Descriptor [4/14.14.2] */ +struct UDF_ADImp_use { + uint16_t flags; + uint32_t unique_id; +} __packed; +#define UDF_ADIMP_FLAGS_EXTENT_ERASED 1 + + +struct long_ad { + uint32_t len; + struct lb_addr loc; /* within a logical volume mapped partition space !! */ + union { + uint8_t bytes[6]; + struct UDF_ADImp_use im_used; + } impl; +} __packed; +#define longad_uniqueid impl.im_used.unique_id + + +/* Extended Allocation Descriptor [4/14.14.3] ; identifies an extent of allocation descriptors ; also in UDF ? */ +struct ext_ad { + uint32_t ex_len; + uint32_t rec_len; + uint32_t inf_len; + struct lb_addr ex_loc; + uint8_t reserved[2]; +} __packed; + + +/* ICB : Information Control Block; positioning */ +union icb { + struct short_ad s_ad; + struct long_ad l_ad; + struct ext_ad e_ad; +}; + + +/* short/long/ext extent have flags encoded in length */ +#define UDF_EXT_ALLOCATED (0U<<30) +#define UDF_EXT_FREED (1U<<30) +#define UDF_EXT_ALLOCATED_BUT_NOT_USED (1U<<30) +#define UDF_EXT_FREE (2U<<30) +#define UDF_EXT_REDIRECT (3U<<30) +#define UDF_EXT_FLAGS(len) ((len) & (3U<<30)) +#define UDF_EXT_LEN(len) ((len) & ((1U<<30)-1)) +#define UDF_EXT_MAXLEN ((1U<<30)-1) + + +/* Character set spec [1/7.2.1] */ +struct charspec { + uint8_t type; + uint8_t inf[63]; +} __packed; + + +struct pathcomp { + uint8_t type; + uint8_t l_ci; + uint16_t comp_filever; + uint8_t ident[256]; +} __packed; +#define UDF_PATH_COMP_SIZE 4 +#define UDF_PATH_COMP_RESERVED 0 +#define UDF_PATH_COMP_ROOT 1 +#define UDF_PATH_COMP_MOUNTROOT 2 +#define UDF_PATH_COMP_PARENTDIR 3 +#define UDF_PATH_COMP_CURDIR 4 +#define UDF_PATH_COMP_NAME 5 + + +/* Timestamp [1/7.3] */ +struct timestamp { + uint16_t type_tz; + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t centisec; + uint8_t hund_usec; + uint8_t usec; +} __packed; +#define UDF_TIMESTAMP_SIZE 12 + + +/* Entity Identifier [1/7.4] */ +#define UDF_REGID_ID_SIZE 23 +struct regid { + uint8_t flags; + uint8_t id[UDF_REGID_ID_SIZE]; + uint8_t id_suffix[8]; +} __packed; + + +/* ICB Tag [4/14.6] */ +struct icb_tag { + uint32_t prev_num_dirs; + uint16_t strat_type; + union { + uint8_t strat_param[2]; + uint16_t strat_param16; + }; + uint16_t max_num_entries; + uint8_t reserved; + uint8_t file_type; + struct lb_addr parent_icb; + uint16_t flags; +} __packed; +#define UDF_ICB_TAG_FLAGS_ALLOC_MASK 0x03 +#define UDF_ICB_SHORT_ALLOC 0x00 +#define UDF_ICB_LONG_ALLOC 0x01 +#define UDF_ICB_EXT_ALLOC 0x02 +#define UDF_ICB_INTERN_ALLOC 0x03 + +#define UDF_ICB_TAG_FLAGS_DIRORDERED (1<< 3) +#define UDF_ICB_TAG_FLAGS_NONRELOC (1<< 4) +#define UDF_ICB_TAG_FLAGS_CONTIGUES (1<< 9) +#define UDF_ICB_TAG_FLAGS_MULTIPLEVERS (1<<12) + +#define UDF_ICB_TAG_FLAGS_SETUID (1<< 6) +#define UDF_ICB_TAG_FLAGS_SETGID (1<< 7) +#define UDF_ICB_TAG_FLAGS_STICKY (1<< 8) + +#define UDF_ICB_FILETYPE_UNKNOWN 0 +#define UDF_ICB_FILETYPE_UNALLOCSPACE 1 +#define UDF_ICB_FILETYPE_PARTINTEGRITY 2 +#define UDF_ICB_FILETYPE_INDIRECTENTRY 3 +#define UDF_ICB_FILETYPE_DIRECTORY 4 +#define UDF_ICB_FILETYPE_RANDOMACCESS 5 +#define UDF_ICB_FILETYPE_BLOCKDEVICE 6 +#define UDF_ICB_FILETYPE_CHARDEVICE 7 +#define UDF_ICB_FILETYPE_EXTATTRREC 8 +#define UDF_ICB_FILETYPE_FIFO 9 +#define UDF_ICB_FILETYPE_SOCKET 10 +#define UDF_ICB_FILETYPE_TERM 11 +#define UDF_ICB_FILETYPE_SYMLINK 12 +#define UDF_ICB_FILETYPE_STREAMDIR 13 +#define UDF_ICB_FILETYPE_VAT 248 +#define UDF_ICB_FILETYPE_REALTIME 249 +#define UDF_ICB_FILETYPE_META_MAIN 250 +#define UDF_ICB_FILETYPE_META_MIRROR 251 +#define UDF_ICB_FILETYPE_META_BITMAP 252 + + +/* Anchor Volume Descriptor Pointer [3/10.2] */ +struct anchor_vdp { + struct desc_tag tag; + struct extent_ad main_vds_ex; /* to main volume descriptor set ; 16 sectors min */ + struct extent_ad reserve_vds_ex; /* copy of main volume descriptor set ; 16 sectors min */ +} __packed; + + +/* Volume Descriptor Pointer [3/10.3] */ +struct vol_desc_ptr { + struct desc_tag tag; /* use for extending the volume descriptor space */ + uint32_t vds_number; + struct extent_ad next_vds_ex; /* points to the next block for volume descriptor space */ +} __packed; + + +/* Primary Volume Descriptor [3/10.1] */ +struct pri_vol_desc { + struct desc_tag tag; + uint32_t seq_num; /* MAX prevail */ + uint32_t pvd_num; /* assigned by author; 0 is special as in it may only occur once */ + char vol_id[32]; /* KEY ; main identifier of this disc */ + uint16_t vds_num; /* volume descriptor number; i.e. what volume number is it */ + uint16_t max_vol_seq; /* maximum volume descriptor number known */ + uint16_t ichg_lvl; + uint16_t max_ichg_lvl; + uint32_t charset_list; + uint32_t max_charset_list; + char volset_id[128]; /* KEY ; if part of a multi-disc set or a band of volumes */ + struct charspec desc_charset; /* KEY according to ECMA 167 */ + struct charspec explanatory_charset; + struct extent_ad vol_abstract; + struct extent_ad vol_copyright; + struct regid app_id; + struct timestamp time; + struct regid imp_id; + uint8_t imp_use[64]; + uint32_t prev_vds_loc; /* location of predecessor _lov ? */ + uint16_t flags; /* bit 0 : if set indicates volume set name is meaningful */ + uint8_t reserved[22]; +} __packed; + + +/* UDF specific implementation use part of the implementation use volume descriptor */ +struct udf_lv_info { + struct charspec lvi_charset; + char logvol_id[128]; + + char lvinfo1[36]; + char lvinfo2[36]; + char lvinfo3[36]; + + struct regid impl_id; + uint8_t impl_use[128]; +} __packed; + + +/* Implementation use Volume Descriptor */ +struct impvol_desc { + struct desc_tag tag; + uint32_t seq_num; + struct regid impl_id; + union { + struct udf_lv_info lv_info; + char impl_use[460]; + } _impl_use; +} __packed; + + +/* Logical Volume Descriptor [3/10.6] */ +struct logvol_desc { + struct desc_tag tag; + uint32_t seq_num; /* MAX prevail */ + struct charspec desc_charset; /* KEY */ + char logvol_id[128]; /* KEY */ + uint32_t lb_size; + struct regid domain_id; + union { + struct long_ad fsd_loc; /* to fileset descriptor SEQUENCE */ + uint8_t logvol_content_use[16]; + } _lvd_use; + uint32_t mt_l; /* Partition map length */ + uint32_t n_pm; /* Number of partition maps */ + struct regid imp_id; + uint8_t imp_use[128]; + struct extent_ad integrity_seq_loc; + uint8_t maps[1]; +} __packed; +#define lv_fsd_loc _lvd_use.fsd_loc + +#define UDF_INTEGRITY_OPEN 0 +#define UDF_INTEGRITY_CLOSED 1 + + +#define UDF_PMAP_SIZE 64 + +/* Type 1 Partition Map [3/10.7.2] */ +struct part_map_1 { + uint8_t type; + uint8_t len; + uint16_t vol_seq_num; + uint16_t part_num; +} __packed; + + +/* Type 2 Partition Map [3/10.7.3] */ +struct part_map_2 { + uint8_t type; + uint8_t len; + uint8_t reserved[2]; + struct regid part_id; + uint16_t vol_seq_num; + uint16_t part_num; + uint8_t reserved2[24]; +} __packed; + + +/* Virtual Partition Map [UDF 2.01/2.2.8] */ +struct part_map_virt { + uint8_t type; + uint8_t len; + uint8_t reserved[2]; + struct regid id; + uint16_t vol_seq_num; + uint16_t part_num; + uint8_t reserved1[24]; +} __packed; + + +/* Sparable Partition Map [UDF 2.01/2.2.9] */ +struct part_map_spare { + uint8_t type; + uint8_t len; + uint8_t reserved[2]; + struct regid id; + uint16_t vol_seq_num; + uint16_t part_num; + uint16_t packet_len; + uint8_t n_st; /* Number of redundant sparing tables range 1-4 */ + uint8_t reserved1; + uint32_t st_size; /* size of EACH sparing table */ + uint32_t st_loc[1]; /* locations of sparing tables */ +} __packed; + + +/* Metadata Partition Map [UDF 2.50/2.2.10] */ +struct part_map_meta { + uint8_t type; + uint8_t len; + uint8_t reserved[2]; + struct regid id; + uint16_t vol_seq_num; + uint16_t part_num; + uint32_t meta_file_lbn; /* logical block number for file entry within part_num */ + uint32_t meta_mirror_file_lbn; + uint32_t meta_bitmap_file_lbn; + uint32_t alloc_unit_size; /* allocation unit size in blocks */ + uint16_t alignment_unit_size; /* alignment necessary in blocks */ + uint8_t flags; + uint8_t reserved1[5]; +} __packed; +#define METADATA_DUPLICATED 1 + + +union udf_pmap { + uint8_t data[UDF_PMAP_SIZE]; + struct part_map_1 pm1; + struct part_map_2 pm2; + struct part_map_virt pmv; + struct part_map_spare pms; + struct part_map_meta pmm; +}; + + +/* Sparing Map Entry [UDF 2.01/2.2.11] */ +struct spare_map_entry { + uint32_t org; /* partition relative address */ + uint32_t map; /* absolute disc address (!) can be in partition, but doesn't have to be */ +} __packed; + + +/* Sparing Table [UDF 2.01/2.2.11] */ +struct udf_sparing_table { + struct desc_tag tag; + struct regid id; + uint16_t rt_l; /* Relocation Table len */ + uint8_t reserved[2]; + uint32_t seq_num; + struct spare_map_entry entries[1]; +} __packed; + + +#define UDF_NO_PREV_VAT 0xffffffff +/* UDF 1.50 VAT suffix [UDF 2.2.10 (UDF 1.50 spec)] */ +struct udf_oldvat_tail { + struct regid id; /* "*UDF Virtual Alloc Tbl" */ + uint32_t prev_vat; +} __packed; + + +/* VAT table [UDF 2.0.1/2.2.10] */ +struct udf_vat { + uint16_t header_len; + uint16_t impl_use_len; + char logvol_id[128]; /* newer version of the LVD one */ + uint32_t prev_vat; + uint32_t num_files; + uint32_t num_directories; + uint16_t min_udf_readver; + uint16_t min_udf_writever; + uint16_t max_udf_writever; + uint16_t reserved; + uint8_t data[1]; /* impl.use followed by VAT entries (uint32_t) */ +} __packed; + + +/* Space bitmap descriptor as found in the partition header descriptor */ +struct space_bitmap_desc { + struct desc_tag tag; /* TagId 264 */ + uint32_t num_bits; /* number of bits */ + uint32_t num_bytes; /* bytes that contain it */ + uint8_t data[1]; +} __packed; + + +/* Unalloc space entry as found in the partition header descriptor */ +struct space_entry_desc { + struct desc_tag tag; /* TagId 263 */ + struct icb_tag icbtag; /* type 1 */ + uint32_t l_ad; /* in bytes */ + uint8_t entry[1]; +} __packed; + + +/* Partition header descriptor; in the contents_use of part_desc */ +struct part_hdr_desc { + struct short_ad unalloc_space_table; + struct short_ad unalloc_space_bitmap; + struct short_ad part_integrity_table; /* has to be ZERO for UDF */ + struct short_ad freed_space_table; + struct short_ad freed_space_bitmap; + uint8_t reserved[88]; +} __packed; + + +/* Partition Descriptor [3/10.5] */ +struct part_desc { + struct desc_tag tag; + uint32_t seq_num; /* MAX prevailing */ + uint16_t flags; /* bit 0 : if set the space is allocated */ + uint16_t part_num; /* KEY */ + struct regid contents; + union { + struct part_hdr_desc part_hdr; + uint8_t contents_use[128]; + } _impl_use; + uint32_t access_type; /* R/W, WORM etc. */ + uint32_t start_loc; /* start of partition with given length */ + uint32_t part_len; + struct regid imp_id; + uint8_t imp_use[128]; + uint8_t reserved[156]; +} __packed; +#define pd_part_hdr _impl_use.part_hdr +#define UDF_PART_FLAG_ALLOCATED 1 + + +/* Unallocated Space Descriptor (UDF 2.01/2.2.5) */ +struct unalloc_sp_desc { + struct desc_tag tag; + uint32_t seq_num; /* MAX prevailing */ + uint32_t alloc_desc_num; + struct extent_ad alloc_desc[1]; +} __packed; + + +/* Logical Volume Integrity Descriptor [3/30.10] */ +struct logvolhdr { + uint64_t next_unique_id; + /* rest reserved */ +} __packed; + + +struct udf_logvol_info { + struct regid impl_id; + uint32_t num_files; + uint32_t num_directories; + uint16_t min_udf_readver; + uint16_t min_udf_writever; + uint16_t max_udf_writever; +} __packed; + + +struct logvol_int_desc { + struct desc_tag tag; + struct timestamp time; + uint32_t integrity_type; + struct extent_ad next_extent; + union { + struct logvolhdr logvolhdr; + int8_t reserved[32]; + } _impl_use; + uint32_t num_part; + uint32_t l_iu; + uint32_t tables[1]; /* Freespace table, Sizetable, Implementation use */ +} __packed; +#define lvint_next_unique_id _impl_use.logvolhdr.next_unique_id + + +/* File Set Descriptor [4/14.1] */ +struct fileset_desc { + struct desc_tag tag; + struct timestamp time; + uint16_t ichg_lvl; + uint16_t max_ichg_lvl; + uint32_t charset_list; + uint32_t max_charset_list; + uint32_t fileset_num; /* key! */ + uint32_t fileset_desc_num; + struct charspec logvol_id_charset; + char logvol_id[128]; /* for recovery */ + struct charspec fileset_charset; + char fileset_id[32]; /* Mountpoint !! */ + char copyright_file_id[32]; + char abstract_file_id[32]; + struct long_ad rootdir_icb; /* to rootdir; icb->virtual ? */ + struct regid domain_id; + struct long_ad next_ex; /* to the next fileset_desc extent */ + struct long_ad streamdir_icb; /* streamdir; needed? */ + uint8_t reserved[32]; +} __packed; + + +/* File Identifier Descriptor [4/14.4] */ +struct fileid_desc { + struct desc_tag tag; + uint16_t file_version_num; + uint8_t file_char; + uint8_t l_fi; /* Length of file identifier area */ + struct long_ad icb; + uint16_t l_iu; /* Length of implementation use area */ + uint8_t data[1]; +} __packed; +#define UDF_FID_SIZE 38 +#define UDF_FILE_CHAR_VIS (1 << 0) /* Invisible */ +#define UDF_FILE_CHAR_DIR (1 << 1) /* Directory */ +#define UDF_FILE_CHAR_DEL (1 << 2) /* Deleted */ +#define UDF_FILE_CHAR_PAR (1 << 3) /* Parent Directory */ +#define UDF_FILE_CHAR_META (1 << 4) /* Stream metadata */ + + +/* Extended attributes [4/14.10.1] */ +struct extattrhdr_desc { + struct desc_tag tag; + uint32_t impl_attr_loc; /* offsets within this descriptor */ + uint32_t appl_attr_loc; /* ditto */ +} __packed; +#define UDF_IMPL_ATTR_LOC_NOT_PRESENT 0xffffffff +#define UDF_APPL_ATTR_LOC_NOT_PRESENT 0xffffffff + + +/* Extended attribute entry [4/48.10.2] */ +struct extattr_entry { + uint32_t type; + uint8_t subtype; + uint8_t reserved[3]; + uint32_t a_l; +} __packed; + + +/* Extended attribute entry; type 2048 [4/48.10.8] */ +struct impl_extattr_entry { + struct extattr_entry hdr; + uint32_t iu_l; + struct regid imp_id; + union { + uint8_t data[1]; + uint16_t data16; + }; +} __packed; + + +/* Extended attribute entry; type 65 536 [4/48.10.9] */ +struct appl_extattr_entry { + struct extattr_entry hdr; + uint32_t au_l; + struct regid appl_id; + uint8_t data[1]; +} __packed; + + +/* File Times attribute entry; type 5 or type 6 [4/48.10.5], [4/48.10.6] */ +struct filetimes_extattr_entry { + struct extattr_entry hdr; + uint32_t d_l; /* length of times[] data following */ + uint32_t existence; /* bitmask */ + struct timestamp times[1]; /* in order of ascending bits */ +} __packed; +#define UDF_FILETIMES_ATTR_NO 5 +#define UDF_FILETIMES_FILE_CREATION 1 +#define UDF_FILETIMES_FILE_DELETION 4 +#define UDF_FILETIMES_FILE_EFFECTIVE 8 +#define UDF_FILETIMES_FILE_BACKUPED 16 +#define UDF_FILETIMES_ATTR_SIZE(no) (20 + (no)*sizeof(struct timestamp)) + + +/* Device Specification Extended Attribute [4/4.10.7] */ +struct device_extattr_entry { + struct extattr_entry hdr; + uint32_t iu_l; /* length of implementation use */ + uint32_t major; + uint32_t minor; + uint8_t data[1]; /* UDF: if nonzero length, contain developer ID regid */ +} __packed; +#define UDF_DEVICESPEC_ATTR_NO 12 + + +/* VAT LV extension Extended Attribute [UDF 3.3.4.5.1.3] 1.50 errata */ +struct vatlvext_extattr_entry { + uint64_t unique_id_chk; /* needs to be copy of ICB's */ + uint32_t num_files; + uint32_t num_directories; + char logvol_id[128]; /* replaces logvol name */ +} __packed; + + +/* File Entry [4/14.9] */ +struct file_entry { + struct desc_tag tag; + struct icb_tag icbtag; + uint32_t uid; + uint32_t gid; + uint32_t perm; + uint16_t link_cnt; + uint8_t rec_format; + uint8_t rec_disp_attr; + uint32_t rec_len; + uint64_t inf_len; + uint64_t logblks_rec; + struct timestamp atime; + struct timestamp mtime; + struct timestamp attrtime; + uint32_t ckpoint; + struct long_ad ex_attr_icb; + struct regid imp_id; + uint64_t unique_id; + uint32_t l_ea; /* Length of extended attribute area */ + uint32_t l_ad; /* Length of allocation descriptors */ + uint8_t data[1]; +} __packed; +#define UDF_FENTRY_SIZE 176 +#define UDF_FENTRY_PERM_USER_MASK 0x07 +#define UDF_FENTRY_PERM_GRP_MASK 0xE0 +#define UDF_FENTRY_PERM_OWNER_MASK 0x1C00 + + +/* Extended File Entry [4/48.17] */ +struct extfile_entry { + struct desc_tag tag; + struct icb_tag icbtag; + uint32_t uid; + uint32_t gid; + uint32_t perm; + uint16_t link_cnt; + uint8_t rec_format; + uint8_t rec_disp_attr; + uint32_t rec_len; + uint64_t inf_len; + uint64_t obj_size; + uint64_t logblks_rec; + struct timestamp atime; + struct timestamp mtime; + struct timestamp ctime; + struct timestamp attrtime; + uint32_t ckpoint; + uint32_t reserved1; + struct long_ad ex_attr_icb; + struct long_ad streamdir_icb; + struct regid imp_id; + uint64_t unique_id; + uint32_t l_ea; /* Length of extended attribute area */ + uint32_t l_ad; /* Length of allocation descriptors */ + uint8_t data[1]; +} __packed; +#define UDF_EXTFENTRY_SIZE 216 + + +/* Indirect entry [ecma 48.7] */ +struct indirect_entry { + struct desc_tag tag; + struct icb_tag icbtag; + struct long_ad indirect_icb; +} __packed; + + +/* Allocation extent descriptor [ecma 48.5] */ +struct alloc_ext_entry { + struct desc_tag tag; + uint32_t prev_entry; + uint32_t l_ad; + uint8_t data[1]; +} __packed; + + +union dscrptr { + struct desc_tag tag; + struct anchor_vdp avdp; + struct vol_desc_ptr vdp; + struct pri_vol_desc pvd; + struct logvol_desc lvd; + struct unalloc_sp_desc usd; + struct logvol_int_desc lvid; + struct impvol_desc ivd; + struct part_desc pd; + struct fileset_desc fsd; + struct fileid_desc fid; + struct file_entry fe; + struct extfile_entry efe; + struct extattrhdr_desc eahd; + struct indirect_entry inde; + struct alloc_ext_entry aee; + struct udf_sparing_table spt; + struct space_bitmap_desc sbd; + struct space_entry_desc sed; +}; + + +#endif /* !_FS_UDF_ECMA167_UDF_H_ */ diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf/newfs_udf.h b/vendor/bdj-sdk/host/src/makefs_termux/udf/newfs_udf.h new file mode 100644 index 0000000..67daea7 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf/newfs_udf.h @@ -0,0 +1,35 @@ +/* $NetBSD: newfs_udf.h,v 1.9 2022/04/09 09:58:11 riastradh Exp $ */ + +/* + * Copyright (c) 2006, 2008, 2013 Reinoud Zandijk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR ``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 AUTHOR 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. + * + */ + +#ifndef _FS_UDF_NEWFS_UDF_H_ +#define _FS_UDF_NEWFS_UDF_H_ + +/* general settings */ +#define UDF_512_TRACK 0 /* NOT recommended */ + +#endif /* _FS_UDF_NEWFS_UDF_H_ */ diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf/udf_bswap.h b/vendor/bdj-sdk/host/src/makefs_termux/udf/udf_bswap.h new file mode 100644 index 0000000..b202428 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf/udf_bswap.h @@ -0,0 +1,76 @@ +/* $NetBSD: udf_bswap.h,v 1.8 2009/10/22 21:50:01 bouyer Exp $ */ + +/* + * Copyright (c) 1998 Manuel Bouyer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR ``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 AUTHOR 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. + * + * adapted for UDF by Reinoud Zandijk + * + */ + +#ifndef _FS_UDF_UDF_BSWAP_H_ +#define _FS_UDF_UDF_BSWAP_H_ + +#include +// #include +// #include + +/* rest only relevant for big endian machines */ +#if (BYTE_ORDER == BIG_ENDIAN) + +/* inlines for access to swapped data */ +static __inline uint16_t udf_rw16(uint16_t); +static __inline uint32_t udf_rw32(uint32_t); +static __inline uint64_t udf_rw64(uint64_t); + + +static __inline uint16_t +udf_rw16(uint16_t a) +{ + return bswap16(a); +} + + +static __inline uint32_t +udf_rw32(uint32_t a) +{ + return bswap32(a); +} + + +static __inline uint64_t +udf_rw64(uint64_t a) +{ + return bswap64(a); +} + +#else + +#define udf_rw16(a) ((uint16_t)(a)) +#define udf_rw32(a) ((uint32_t)(a)) +#define udf_rw64(a) ((uint64_t)(a)) + +#endif + + +#endif /* !_FS_UDF_UDF_BSWAP_H_ */ + diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf/udf_mount.h b/vendor/bdj-sdk/host/src/makefs_termux/udf/udf_mount.h new file mode 100644 index 0000000..897b9f9 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf/udf_mount.h @@ -0,0 +1,63 @@ +/* $NetBSD: udf_mount.h,v 1.4 2019/10/16 21:52:22 maya Exp $ */ + +/* + * Copyright (c) 2006 Reinoud Zandijk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR ``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 AUTHOR 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. + * + */ + + +#ifndef _FS_UDF_UDF_MOUNT_H_ +#define _FS_UDF_UDF_MOUNT_H_ + +/* + * Arguments to mount UDF filingsystem. + */ + +#define UDFMNT_VERSION 1 +struct udf_args { + uint32_t version; /* version of this structure */ + char *fspec; /* mount specifier */ + int32_t sessionnr; /* session specifier, rel of abs */ + uint32_t udfmflags; /* mount options */ + int32_t gmtoff; /* offset from UTC in seconds */ + + uid_t anon_uid; /* mapping of anonymous files uid */ + gid_t anon_gid; /* mapping of anonymous files gid */ + uid_t nobody_uid; /* nobody:nobody will map to -1:-1 */ + gid_t nobody_gid; /* nobody:nobody will map to -1:-1 */ + + uint32_t sector_size; /* for mounting dumps/files */ + + /* extendable */ + uint8_t reserved[32]; +}; + + +/* udf mount options */ + +#define UDFMNT_CLOSESESSION 0x00000001 /* close session on dismount */ +#define UDFMNT_BITS "\20\1CLOSESESSION" + +#endif /* !_FS_UDF_UDF_MOUNT_H_ */ + diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf/udf_osta.h b/vendor/bdj-sdk/host/src/makefs_termux/udf/udf_osta.h new file mode 100644 index 0000000..4d166b7 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf/udf_osta.h @@ -0,0 +1,44 @@ +/* $NetBSD: udf_osta.h,v 1.4 2008/05/14 16:49:48 reinoud Exp $ */ + +/* + * Prototypes for the OSTA functions + */ + + +#ifndef _FS_UDF_OSTA_H_ +#define _FS_UDF_OSTA_H_ + +#include + +#ifndef _KERNEL +#include +#endif + +#ifndef UNIX +#define UNIX +#endif + +#ifndef MAXLEN +#define MAXLEN 255 +#endif + + +/*********************************************************************** + * The following two typedef's are to remove compiler dependancies. + * byte needs to be unsigned 8-bit, and unicode_t needs to be + * unsigned 16-bit. + */ +typedef uint16_t unicode_t; +typedef uint8_t byte; + + +int udf_UncompressUnicode(int, byte *, unicode_t *); +int udf_CompressUnicode(int, int, unicode_t *, byte *); +unsigned short udf_cksum(unsigned char *, int); +unsigned short udf_unicode_cksum(unsigned short *, int); +uint16_t udf_ea_cksum(uint8_t *data); +int UDFTransName(unicode_t *, unicode_t *, int); +int UnicodeLength(unicode_t *string); + + +#endif /* _FS_UDF_OSTA_H_ */ diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf/unicode.h b/vendor/bdj-sdk/host/src/makefs_termux/udf/unicode.h new file mode 100644 index 0000000..9ffde9b --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf/unicode.h @@ -0,0 +1,161 @@ +/* $NetBSD: unicode.h,v 1.1 2013/08/05 14:11:30 reinoud Exp $ */ + +/*- + * Copyright (c) 2001, 2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Paul Borman at Krystal Technologies. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +/* + * Routines for handling Unicode encoded in UTF-8 form, code derived from + * src/lib/libc/locale/utf2.c. + */ +static u_int16_t wget_utf8(const char **, size_t *); +static int wput_utf8(char *, size_t, u_int16_t); + +/* + * Read one UTF8-encoded character off the string, shift the string pointer + * and return the character. + */ +static u_int16_t +wget_utf8(const char **str, size_t *sz) +{ + unsigned int c; + u_int16_t rune = 0; + const char *s = *str; + static const int _utf_count[16] = { + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 2, 2, 3, 0, + }; + + /* must be called with at least one byte remaining */ + assert(*sz > 0); + + c = _utf_count[(s[0] & 0xf0) >> 4]; + if (c == 0 || c > *sz) { + decoding_error: + /* + * The first character is in range 128-255 and doesn't + * mark valid a valid UTF-8 sequence. There is not much + * we can do with this, so handle by returning + * the first character as if it would be a correctly + * encoded ISO-8859-1 character. + */ + c = 1; + } + + switch (c) { + case 1: + rune = s[0] & 0xff; + break; + case 2: + if ((s[1] & 0xc0) != 0x80) + goto decoding_error; + rune = ((s[0] & 0x1F) << 6) | (s[1] & 0x3F); + break; + case 3: + if ((s[1] & 0xC0) != 0x80 || (s[2] & 0xC0) != 0x80) + goto decoding_error; + rune = ((s[0] & 0x0F) << 12) | ((s[1] & 0x3F) << 6) + | (s[2] & 0x3F); + break; + } + + *str += c; + *sz -= c; + return rune; +} + +/* + * Encode wide character and write it to the string. 'n' specifies + * how much buffer space remains in 's'. Returns number of bytes written + * to the target string 's'. + */ +static int +wput_utf8(char *s, size_t n, u_int16_t wc) +{ + if (wc & 0xf800) { + if (n < 3) { + /* bound check failure */ + return 0; + } + + s[0] = 0xE0 | (wc >> 12); + s[1] = 0x80 | ((wc >> 6) & 0x3F); + s[2] = 0x80 | ((wc) & 0x3F); + return 3; + } else if (wc & 0x0780) { + if (n < 2) { + /* bound check failure */ + return 0; + } + + s[0] = 0xC0 | (wc >> 6); + s[1] = 0x80 | ((wc) & 0x3F); + return 2; + } else { + if (n < 1) { + /* bound check failure */ + return 0; + } + + s[0] = wc; + return 1; + } +} diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf_core.c b/vendor/bdj-sdk/host/src/makefs_termux/udf_core.c new file mode 100644 index 0000000..86dc117 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf_core.c @@ -0,0 +1,5114 @@ +/* $NetBSD: udf_core.c,v 1.9 2022/04/26 15:11:42 reinoud Exp $ */ +/* + * Copyright (c) 2006, 2008, 2021, 2022 Reinoud Zandijk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR ``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 AUTHOR 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. + * + */ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +//__RCSID("$NetBSD: udf_core.c,v 1.9 2022/04/26 15:11:42 reinoud Exp $"); + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" +#include +#include +#include +#include +#include "newfs_udf.h" +#include "unicode.h" +#include "udf_core.h" + + + +/* disk partition support */ +#if !HAVE_NBTOOL_CONFIG_H +//#include "../fsck/partutil.h" +//#include "../fsck/partutil.c" +#endif + + +/* queue for temporary storage of sectors to be written out */ +struct wrpacket { + uint64_t start_sectornr; + uint8_t *packet_data; + uint64_t present; + TAILQ_ENTRY(wrpacket) next; +}; + + +/* global variables describing disc and format requests */ +struct udf_create_context context; +struct udf_disclayout layout; + + +int dev_fd_rdonly; /* device: open readonly! */ +int dev_fd; /* device: file descriptor */ +struct stat dev_fd_stat; /* device: last stat info */ +char *dev_name; /* device: name */ +int emul_mmc_profile; /* for files */ +int emul_packetsize; /* for discs and files */ +int emul_sectorsize; /* for files */ +off_t emul_size; /* for files */ + +struct mmc_discinfo mmc_discinfo; /* device: disc info */ +union dscrptr *terminator_dscr; /* generic terminator descriptor*/ + + +/* write queue and track blocking skew */ +TAILQ_HEAD(wrpacket_list, wrpacket) write_queue; +int write_queuelen; +int write_queue_suspend; +uint32_t wrtrack_skew; /* offset for writing sector0 */ + +static void udf_init_writequeue(int write_strategy); +static int udf_writeout_writequeue(bool complete); + +/* + * NOTE that there is some overlap between this code and the udf kernel fs. + * This is intentionally though it might better be factored out one day. + */ + +void +udf_init_create_context(void) +{ + /* clear */ + memset(&context, 0, sizeof(struct udf_create_context)); + + /* fill with defaults currently known */ + context.dscrver = 3; + context.min_udf = 0x0102; + context.max_udf = 0x0250; + context.serialnum = 1; /* default */ + + context.gmtoff = 0; + context.meta_perc = UDF_META_PERC; + context.check_surface = 0; + context.create_new_session = 0; + + context.sector_size = 512; /* minimum for UDF */ + context.media_accesstype = UDF_ACCESSTYPE_NOT_SPECIFIED; + context.format_flags = FORMAT_INVALID; + context.write_strategy = UDF_WRITE_PACKET; + + context.logvol_name = NULL; + context.primary_name = NULL; + context.volset_name = NULL; + context.fileset_name = NULL; + + /* most basic identification */ + context.app_name = "*NetBSD"; + context.app_version_main = 0; + context.app_version_sub = 0; + context.impl_name = "*NetBSD"; + + context.vds_seq = 0; /* first one starts with zero */ + + /* Minimum value of 16 : UDF 3.2.1.1, 3.3.3.4. */ + context.unique_id = 0x10; + + context.num_files = 0; + context.num_directories = 0; + + context.data_part = 0; + context.metadata_part = 0; +} + + +/* version can be specified as 0xabc or a.bc */ +static int +parse_udfversion(const char *pos, uint32_t *version) { + int hex = 0; + char c1, c2, c3, c4; + + *version = 0; + if (*pos == '0') { + pos++; + /* expect hex format */ + hex = 1; + if (*pos++ != 'x') + return 1; + } + + c1 = *pos++; + if (c1 < '0' || c1 > '9') + return 1; + c1 -= '0'; + + c2 = *pos++; + if (!hex) { + if (c2 != '.') + return 1; + c2 = *pos++; + } + if (c2 < '0' || c2 > '9') + return 1; + c2 -= '0'; + + c3 = *pos++; + if (c3 < '0' || c3 > '9') + return 1; + c3 -= '0'; + + c4 = *pos++; + if (c4 != 0) + return 1; + + *version = c1 * 0x100 + c2 * 0x10 + c3; + return 0; +} + + +/* + * Parse a given string for an udf version. + * May exit. + */ +int +a_udf_version(const char *s, const char *id_type) +{ + uint32_t version; + + if (parse_udfversion(s, &version)) + errx(1, "unknown %s version %s; specify as hex or float", id_type, s); + switch (version) { + case 0x102: + case 0x150: + case 0x200: + case 0x201: + case 0x250: + break; + case 0x260: + /* we don't support this one */ + errx(1, "UDF version 0x260 is not supported"); + break; + default: + errx(1, "unknown %s version %s, choose from " + "0x102, 0x150, 0x200, 0x201, 0x250", + id_type, s); + } + return version; +} + + +static uint32_t +udf_space_bitmap_len(uint32_t part_size) +{ + return sizeof(struct space_bitmap_desc)-1 + + part_size/8; +} + + +uint32_t +udf_bytes_to_sectors(uint64_t bytes) +{ + uint32_t sector_size = context.sector_size; + return (bytes + sector_size -1) / sector_size; +} + + +void +udf_dump_layout(void) { +#ifdef DEBUG + int format_flags = context.format_flags; + int sector_size = context.sector_size; + + printf("Summary so far\n"); + printf("\tiso9660_vrs\t\t%d\n", layout.iso9660_vrs); + printf("\tanchor0\t\t\t%d\n", layout.anchors[0]); + printf("\tanchor1\t\t\t%d\n", layout.anchors[1]); + printf("\tanchor2\t\t\t%d\n", layout.anchors[2]); + printf("\tvds1_size\t\t%d\n", layout.vds1_size); + printf("\tvds2_size\t\t%d\n", layout.vds2_size); + printf("\tvds1\t\t\t%d\n", layout.vds1); + printf("\tvds2\t\t\t%d\n", layout.vds2); + printf("\tlvis_size\t\t%d\n", layout.lvis_size); + printf("\tlvis\t\t\t%d\n", layout.lvis); + if (format_flags & FORMAT_SPAREABLE) { + printf("\tspareable size\t\t%d\n", layout.spareable_area_size); + printf("\tspareable\t\t%d\n", layout.spareable_area); + } + printf("\tpartition start lba\t%d\n", layout.part_start_lba); + printf("\tpartition size\t\t%ld KiB, %ld MiB\n", + ((uint64_t) layout.part_size_lba * sector_size) / 1024, + ((uint64_t) layout.part_size_lba * sector_size) / (1024*1024)); + if ((format_flags & FORMAT_SEQUENTIAL) == 0) { + printf("\tpart bitmap start\t%d\n", layout.unalloc_space); + printf("\t\tfor %d lba\n", layout.alloc_bitmap_dscr_size); + } + if (format_flags & FORMAT_META) { + printf("\tmeta blockingnr\t\t%d\n", layout.meta_blockingnr); + printf("\tmeta alignment\t\t%d\n", layout.meta_alignment); + printf("\tmeta size\t\t%ld KiB, %ld MiB\n", + ((uint64_t) layout.meta_part_size_lba * sector_size) / 1024, + ((uint64_t) layout.meta_part_size_lba * sector_size) / (1024*1024)); + printf("\tmeta file\t\t%d\n", layout.meta_file); + printf("\tmeta mirror\t\t%d\n", layout.meta_mirror); + printf("\tmeta bitmap\t\t%d\n", layout.meta_bitmap); + printf("\tmeta bitmap start\t%d\n", layout.meta_bitmap_space); + printf("\t\tfor %d lba\n", layout.meta_bitmap_dscr_size); + printf("\tmeta space start\t%d\n", layout.meta_part_start_lba); + printf("\t\tfor %d lba\n", layout.meta_part_size_lba); + } + printf("\n"); +#endif +} + + +int +udf_calculate_disc_layout(int min_udf, + uint32_t first_lba, uint32_t last_lba, + uint32_t sector_size, uint32_t blockingnr) +{ + uint64_t kbsize, bytes; + uint32_t spareable_blockingnr; + uint32_t align_blockingnr; + uint32_t pos, mpos; + int format_flags = context.format_flags; + + /* clear */ + memset(&layout, 0, sizeof(layout)); + + /* fill with parameters */ + layout.wrtrack_skew = wrtrack_skew; + layout.first_lba = first_lba; + layout.last_lba = last_lba; + layout.blockingnr = blockingnr; + layout.spareable_blocks = udf_spareable_blocks(); + + /* start disc layouting */ + + /* + * location of iso9660 vrs is defined as first sector AFTER 32kb, + * minimum `sector size' 2048 + */ + layout.iso9660_vrs = ((32*1024 + sector_size - 1) / sector_size) + + first_lba; + + /* anchor starts at specified offset in sectors */ + layout.anchors[0] = first_lba + 256; + if (format_flags & FORMAT_TRACK512) + layout.anchors[0] = first_lba + 512; + layout.anchors[1] = last_lba - 256; + layout.anchors[2] = last_lba; + + /* update workable space */ + first_lba = layout.anchors[0] + blockingnr; + last_lba = layout.anchors[1] - 1; + + /* XXX rest of anchor packet can be added to unallocated space descr */ + + /* reserve space for VRS and VRS copy and associated tables */ + layout.vds1_size = MAX(16, blockingnr); /* UDF 2.2.3.1+2 */ + layout.vds1 = first_lba; + first_lba += layout.vds1_size; /* next packet */ + + layout.vds2_size = layout.vds1_size; + if (format_flags & FORMAT_SEQUENTIAL) { + /* for sequential, append them ASAP */ + layout.vds2 = first_lba; + first_lba += layout.vds2_size; + } else { + layout.vds2 = layout.anchors[1] +1 - layout.vds2_size; + last_lba = layout.vds2 - 1; + } + + /* + * Reserve space for logvol integrity sequence, at least 8192 bytes + * for overwritable and rewritable media UDF 2.2.4.6, ECMA 3/10.6.12. + */ + layout.lvis_size = MAX(8192.0/sector_size, 2 * blockingnr); + if (layout.lvis_size * sector_size < 8192) + layout.lvis_size++; + if (format_flags & FORMAT_VAT) + layout.lvis_size = 2; + if (format_flags & FORMAT_WORM) + layout.lvis_size = 64 * blockingnr; + + /* TODO skip bad blocks in LVID sequence */ + layout.lvis = first_lba; + first_lba += layout.lvis_size; + + /* initial guess of UDF partition size */ + layout.part_start_lba = first_lba; + layout.part_size_lba = last_lba - layout.part_start_lba; + + /* all non sequential media needs an unallocated space bitmap */ + layout.alloc_bitmap_dscr_size = 0; + if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) { + bytes = udf_space_bitmap_len(layout.part_size_lba); + layout.alloc_bitmap_dscr_size = udf_bytes_to_sectors(bytes); + + /* XXX freed space map when applicable */ + } + + spareable_blockingnr = udf_spareable_blockingnr(); + align_blockingnr = blockingnr; + + if (format_flags & (FORMAT_SPAREABLE | FORMAT_META)) + align_blockingnr = spareable_blockingnr; + + layout.align_blockingnr = align_blockingnr; + layout.spareable_blockingnr = spareable_blockingnr; + + /* + * Align partition LBA space to blocking granularity. Not strictly + * necessary for non spareables but safer for the VRS data since it is + * updated sporadically + */ + +#ifdef DEBUG + printf("Lost %lu slack sectors at start\n", UDF_ROUNDUP( + first_lba, align_blockingnr) - + first_lba); + printf("Lost %lu slack sectors at end\n", + last_lba - UDF_ROUNDDOWN( + last_lba, align_blockingnr)); +#endif + + first_lba = UDF_ROUNDUP(first_lba, align_blockingnr); + last_lba = UDF_ROUNDDOWN(last_lba, align_blockingnr); + + if ((format_flags & FORMAT_SPAREABLE) == 0) + layout.spareable_blocks = 0; + + if (format_flags & FORMAT_SPAREABLE) { + layout.spareable_area_size = + layout.spareable_blocks * spareable_blockingnr; + + /* a sparing table descriptor is a whole blockingnr sectors */ + layout.sparing_table_dscr_lbas = spareable_blockingnr; + + /* place the descriptors at the start and end of the area */ + layout.spt_1 = first_lba; + first_lba += layout.sparing_table_dscr_lbas; + + layout.spt_2 = last_lba - layout.sparing_table_dscr_lbas; + last_lba -= layout.sparing_table_dscr_lbas; + + /* allocate spareable section */ + layout.spareable_area = first_lba; + first_lba += layout.spareable_area_size; + } + + /* update guess of UDF partition size */ + layout.part_start_lba = first_lba; + layout.part_size_lba = last_lba - layout.part_start_lba; + + /* determine partition selection for data and metadata */ + context.data_part = 0; + context.metadata_part = context.data_part; + if ((format_flags & FORMAT_VAT) || (format_flags & FORMAT_META)) + context.metadata_part = context.data_part + 1; + context.fids_part = context.metadata_part; + if (format_flags & FORMAT_VAT) + context.fids_part = context.data_part; + + /* + * Pick fixed logical space sector numbers for main FSD, rootdir and + * unallocated space. The reason for this pre-allocation is that they + * are referenced in the volume descriptor sequence and hence can't be + * allocated later. + */ + pos = 0; + layout.unalloc_space = pos; + pos += layout.alloc_bitmap_dscr_size; + + /* claim metadata descriptors and partition space [UDF 2.2.10] */ + if (format_flags & FORMAT_META) { + /* note: all in backing partition space */ + layout.meta_file = pos++; + layout.meta_bitmap = 0xffffffff; + if (!(context.format_flags & FORMAT_READONLY)) + layout.meta_bitmap = pos++; + layout.meta_mirror = layout.part_size_lba-1; + layout.meta_alignment = MAX(blockingnr, spareable_blockingnr); + layout.meta_blockingnr = MAX(layout.meta_alignment, 32); + + /* calculate our partition length and store in sectors */ + layout.meta_part_size_lba = layout.part_size_lba * + ((float) context.meta_perc / 100.0); + layout.meta_part_size_lba = MAX(layout.meta_part_size_lba, 32); + layout.meta_part_size_lba = + UDF_ROUNDDOWN(layout.meta_part_size_lba, layout.meta_blockingnr); + + if (!(context.format_flags & FORMAT_READONLY)) { + /* metadata partition free space bitmap */ + bytes = udf_space_bitmap_len(layout.meta_part_size_lba); + layout.meta_bitmap_dscr_size = udf_bytes_to_sectors(bytes); + + layout.meta_bitmap_space = pos; + pos += layout.meta_bitmap_dscr_size; + } + + layout.meta_part_start_lba = UDF_ROUNDUP(pos, layout.meta_alignment); + pos = layout.meta_part_start_lba + layout.meta_part_size_lba; + } + + if (context.metadata_part == context.data_part) { + mpos = pos; + layout.fsd = mpos; mpos += 1; + layout.rootdir = mpos; + pos = mpos; + } else { + mpos = 0; + layout.fsd = mpos; mpos += 1; + layout.rootdir = mpos; + } + + /* pos and mpos now refer to the rootdir block */ + context.alloc_pos[context.data_part] = pos; + context.alloc_pos[context.metadata_part] = mpos; + + udf_dump_layout(); + + kbsize = (uint64_t) last_lba * sector_size; + printf("Total space on this medium approx. " + "%llu KiB, %llu MiB\n", + kbsize/1024, kbsize/(1024*1024)); + kbsize = (uint64_t)(layout.part_size_lba - layout.alloc_bitmap_dscr_size + - layout.meta_bitmap_dscr_size) * sector_size; + printf("Recordable free space on this volume approx. " + "%llu KiB, %llu MiB\n\n", + kbsize/1024, kbsize/(1024*1024)); + + return 0; +} + + +/* + * Check if the blob starts with a good UDF tag. Tags are protected by a + * checksum over the header, except one byte at position 4 that is the + * checksum itself. + */ +int +udf_check_tag(void *blob) +{ + struct desc_tag *tag = blob; + uint8_t *pos, sum, cnt; + + /* check TAG header checksum */ + pos = (uint8_t *) tag; + sum = 0; + + for(cnt = 0; cnt < 16; cnt++) { + if (cnt != 4) + sum += *pos; + pos++; + } + if (sum != tag->cksum) { + /* bad tag header checksum; this is not a valid tag */ + return EINVAL; + } + + return 0; +} + + +/* + * check tag payload will check descriptor CRC as specified. + * If the descriptor is too long, it will return EIO otherwise EINVAL. + */ +int +udf_check_tag_payload(void *blob, uint32_t max_length) +{ + struct desc_tag *tag = blob; + uint16_t crc, crc_len; + + crc_len = udf_rw16(tag->desc_crc_len); + + /* check payload CRC if applicable */ + if (crc_len == 0) + return 0; + + if (crc_len > max_length) + return EIO; + + crc = udf_cksum(((uint8_t *) tag) + UDF_DESC_TAG_LENGTH, crc_len); + if (crc != udf_rw16(tag->desc_crc)) { + /* bad payload CRC; this is a broken tag */ + return EINVAL; + } + + return 0; +} + + +int +udf_check_tag_and_location(void *blob, uint32_t location) +{ + struct desc_tag *tag = blob; + + if (udf_check_tag(blob)) + return 1; + if (udf_rw32(tag->tag_loc) != location) + return 1; + return 0; +} + + +int +udf_validate_tag_sum(union dscrptr *dscr) +{ + struct desc_tag *tag = &dscr->tag; + uint8_t *pos, sum, cnt; + + /* calculate TAG header checksum */ + pos = (uint8_t *) tag; + sum = 0; + + for (cnt = 0; cnt < 16; cnt++) { + if (cnt != 4) sum += *pos; + pos++; + }; + tag->cksum = sum; /* 8 bit */ + + return 0; +} + + +/* assumes sector number of descriptor to be already present */ +int +udf_validate_tag_and_crc_sums(union dscrptr *dscr) +{ + struct desc_tag *tag = &dscr->tag; + uint16_t crc; + + /* check payload CRC if applicable */ + if (udf_rw16(tag->desc_crc_len) > 0) { + crc = udf_cksum(((uint8_t *) tag) + UDF_DESC_TAG_LENGTH, + udf_rw16(tag->desc_crc_len)); + tag->desc_crc = udf_rw16(crc); + }; + + /* calculate TAG header checksum */ + return udf_validate_tag_sum(dscr); +} + + +void +udf_inittag(struct desc_tag *tag, int tagid, uint32_t loc) +{ + tag->id = udf_rw16(tagid); + tag->descriptor_ver = udf_rw16(context.dscrver); + tag->cksum = 0; + tag->reserved = 0; + tag->serial_num = udf_rw16(context.serialnum); + tag->tag_loc = udf_rw32(loc); +} + + +int +udf_create_anchor(int num) +{ + struct anchor_vdp *avdp; + uint32_t vds1_extent_len = layout.vds1_size * context.sector_size; + uint32_t vds2_extent_len = layout.vds2_size * context.sector_size; + + avdp = context.anchors[num]; + if (!avdp) + if ((avdp = calloc(1, context.sector_size)) == NULL) + return ENOMEM; + + udf_inittag(&avdp->tag, TAGID_ANCHOR, layout.anchors[num]); + + avdp->main_vds_ex.loc = udf_rw32(layout.vds1); + avdp->main_vds_ex.len = udf_rw32(vds1_extent_len); + + avdp->reserve_vds_ex.loc = udf_rw32(layout.vds2); + avdp->reserve_vds_ex.len = udf_rw32(vds2_extent_len); + + /* CRC length for an anchor is 512 - tag length; defined in Ecma 167 */ + avdp->tag.desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH); + + context.anchors[num] = avdp; + return 0; +} + + +void +udf_create_terminator(union dscrptr *dscr, uint32_t loc) +{ + memset(dscr, 0, context.sector_size); + udf_inittag(&dscr->tag, TAGID_TERM, loc); + + /* CRC length for an anchor is 512 - tag length; defined in Ecma 167 */ + dscr->tag.desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH); +} + + +void +udf_osta_charset(struct charspec *charspec) +{ + memset(charspec, 0, sizeof(*charspec)); + charspec->type = 0; + strcpy((char *) charspec->inf, "OSTA Compressed Unicode"); +} + + +/* ---- shared from kernel's udf_subr.c, slightly modified ---- */ +void +udf_to_unix_name(char *result, int result_len, char *id, int len, + struct charspec *chsp) +{ + uint16_t *raw_name, *unix_name; + uint16_t *inchp, ch; + char *outchp; + const char *osta_id = "OSTA Compressed Unicode"; + int ucode_chars, nice_uchars, is_osta_typ0, nout; + + raw_name = malloc(2048 * sizeof(uint16_t)); + assert(raw_name); + + unix_name = raw_name + 1024; /* split space in half */ + assert(sizeof(char) == sizeof(uint8_t)); + outchp = result; + + is_osta_typ0 = (chsp->type == 0); + is_osta_typ0 &= (strcmp((char *) chsp->inf, osta_id) == 0); + if (is_osta_typ0) { + /* TODO clean up */ + *raw_name = *unix_name = 0; + ucode_chars = udf_UncompressUnicode(len, (uint8_t *) id, raw_name); + ucode_chars = MIN(ucode_chars, UnicodeLength((unicode_t *) raw_name)); + nice_uchars = UDFTransName(unix_name, raw_name, ucode_chars); + /* output UTF8 */ + for (inchp = unix_name; nice_uchars>0; inchp++, nice_uchars--) { + ch = *inchp; + nout = wput_utf8(outchp, result_len, ch); + outchp += nout; result_len -= nout; + if (!ch) break; + } + *outchp++ = 0; + } else { + /* assume 8bit char length byte latin-1 */ + assert(*id == 8); + assert(strlen((char *) (id+1)) <= NAME_MAX); + memcpy((char *) result, (char *) (id+1), strlen((char *) (id+1))); + } + free(raw_name); +} + + +void +unix_to_udf_name(char *result, uint8_t *result_len, char const *name, int name_len, + struct charspec *chsp) +{ + uint16_t *raw_name; + uint16_t *outchp; + const char *inchp; + const char *osta_id = "OSTA Compressed Unicode"; + int udf_chars, is_osta_typ0, bits; + size_t cnt; + + /* allocate temporary unicode-16 buffer */ + raw_name = malloc(1024); + assert(raw_name); + + /* convert utf8 to unicode-16 */ + *raw_name = 0; + inchp = name; + outchp = raw_name; + bits = 8; + for (cnt = name_len, udf_chars = 0; cnt;) { + *outchp = wget_utf8(&inchp, &cnt); + if (*outchp > 0xff) + bits=16; + outchp++; + udf_chars++; + } + /* null terminate just in case */ + *outchp++ = 0; + + is_osta_typ0 = (chsp->type == 0); + is_osta_typ0 &= (strcmp((char *) chsp->inf, osta_id) == 0); + if (is_osta_typ0) { + udf_chars = udf_CompressUnicode(udf_chars, bits, + (unicode_t *) raw_name, + (byte *) result); + } else { + printf("unix to udf name: no CHSP0 ?\n"); + /* XXX assume 8bit char length byte latin-1 */ + *result++ = 8; udf_chars = 1; + strncpy(result, name + 1, name_len); + udf_chars += name_len; + } + *result_len = udf_chars; + free(raw_name); +} + + +/* first call udf_set_regid and then the suffix */ +void +udf_set_regid(struct regid *regid, char const *name) +{ + memset(regid, 0, sizeof(*regid)); + regid->flags = 0; /* not dirty and not protected */ + strcpy((char *) regid->id, name); +} + + +void +udf_add_domain_regid(struct regid *regid) +{ + uint16_t *ver; + + ver = (uint16_t *) regid->id_suffix; + *ver = udf_rw16(context.min_udf); +} + + +void +udf_add_udf_regid(struct regid *regid) +{ + uint16_t *ver; + + ver = (uint16_t *) regid->id_suffix; + *ver = udf_rw16(context.min_udf); + + regid->id_suffix[2] = 4; /* unix */ + regid->id_suffix[3] = 8; /* NetBSD */ +} + + +void +udf_add_impl_regid(struct regid *regid) +{ + regid->id_suffix[0] = 4; /* unix */ + regid->id_suffix[1] = 8; /* NetBSD */ +} + + +void +udf_add_app_regid(struct regid *regid) +{ + regid->id_suffix[0] = context.app_version_main; + regid->id_suffix[1] = context.app_version_sub; +} + + +/* + * Timestamp to timespec conversion code is taken with small modifications + * from FreeBSD /sys/fs/udf by Scott Long + */ + +static int mon_lens[2][12] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} +}; + + +static int +udf_isaleapyear(int year) +{ + int i; + + i = (year % 4) ? 0 : 1; + i &= (year % 100) ? 1 : 0; + i |= (year % 400) ? 0 : 1; + + return i; +} + + +void +udf_timestamp_to_timespec(struct timestamp *timestamp, struct timespec *timespec) +{ + uint32_t usecs, secs, nsecs; + uint16_t tz; + int i, lpyear, daysinyear, year; + + timespec->tv_sec = secs = 0; + timespec->tv_nsec = nsecs = 0; + + /* + * DirectCD seems to like using bogus year values. + * Distrust time->month especially, since it will be used for an array + * index. + */ + year = udf_rw16(timestamp->year); + if ((year < 1970) || (timestamp->month > 12)) { + return; + } + + /* Calculate the time and day */ + usecs = timestamp->usec + 100*timestamp->hund_usec + 10000*timestamp->centisec; + nsecs = usecs * 1000; + secs = timestamp->second; + secs += timestamp->minute * 60; + secs += timestamp->hour * 3600; + secs += (timestamp->day-1) * 3600 * 24; /* day : 1-31 */ + + /* Calclulate the month */ + lpyear = udf_isaleapyear(year); + for (i = 1; i < timestamp->month; i++) + secs += mon_lens[lpyear][i-1] * 3600 * 24; /* month: 1-12 */ + + for (i = 1970; i < year; i++) { + daysinyear = udf_isaleapyear(i) + 365 ; + secs += daysinyear * 3600 * 24; + } + + /* + * Calculate the time zone. The timezone is 12 bit signed 2's + * compliment, so we gotta do some extra magic to handle it right. + */ + tz = udf_rw16(timestamp->type_tz); + tz &= 0x0fff; /* only lower 12 bits are significant */ + if (tz & 0x0800) /* sign extention */ + tz |= 0xf000; + + /* TODO check timezone conversion */ +#if 1 + /* check if we are specified a timezone to convert */ + if (udf_rw16(timestamp->type_tz) & 0x1000) + if ((int16_t) tz != -2047) + secs -= (int16_t) tz * 60; +#endif + timespec->tv_sec = secs; + timespec->tv_nsec = nsecs; +} + + +/* + * Fill in timestamp structure based on clock_gettime(). Time is reported back + * as a time_t accompanied with a nano second field. + * + * The husec, usec and csec could be relaxed in type. + */ +void +udf_timespec_to_timestamp(struct timespec *timespec, struct timestamp *timestamp) +{ + struct tm tm; + uint64_t husec, usec, csec; + + memset(timestamp, 0, sizeof(*timestamp)); + gmtime_r(×pec->tv_sec, &tm); + + /* + * Time type and time zone : see ECMA 1/7.3, UDF 2., 2.1.4.1, 3.1.1. + * + * Lower 12 bits are two complement signed timezone offset if bit 12 + * (method 1) is clear. Otherwise if bit 12 is set, specify timezone + * offset to -2047 i.e. unsigned `zero' + */ + + /* set method 1 for CUT/GMT */ + timestamp->type_tz = udf_rw16((1<<12) + 0); + timestamp->year = udf_rw16(tm.tm_year + 1900); + timestamp->month = tm.tm_mon + 1; /* `tm' uses 0..11 for months */ + timestamp->day = tm.tm_mday; + timestamp->hour = tm.tm_hour; + timestamp->minute = tm.tm_min; + timestamp->second = tm.tm_sec; + + usec = (timespec->tv_nsec + 500) / 1000; /* round */ + husec = usec / 100; + usec -= husec * 100; /* only 0-99 in usec */ + csec = husec / 100; /* only 0-99 in csec */ + husec -= csec * 100; /* only 0-99 in husec */ + + /* in rare cases there is overflow in csec */ + csec = MIN(99, csec); + husec = MIN(99, husec); + usec = MIN(99, usec); + + timestamp->centisec = csec; + timestamp->hund_usec = husec; + timestamp->usec = usec; +} + + +static void +udf_set_timestamp(struct timestamp *timestamp, time_t value) +{ + struct timespec t; + + memset(&t, 0, sizeof(struct timespec)); + t.tv_sec = value; + t.tv_nsec = 0; + udf_timespec_to_timestamp(&t, timestamp); +} + + +static uint32_t +unix_mode_to_udf_perm(mode_t mode) +{ + uint32_t perm; + + perm = ((mode & S_IRWXO) ); + perm |= ((mode & S_IRWXG) << 2); + perm |= ((mode & S_IRWXU) << 4); + perm |= ((mode & S_IWOTH) << 3); + perm |= ((mode & S_IWGRP) << 5); + perm |= ((mode & S_IWUSR) << 7); + + return perm; +} + +/* end of copied code */ + + +void +udf_encode_osta_id(char *osta_id, uint16_t len, char *text) +{ + struct charspec osta_charspec; + uint8_t result_len; + + memset(osta_id, 0, len); + if (!text || (strlen(text) == 0)) return; + + udf_osta_charset(&osta_charspec); + unix_to_udf_name(osta_id, &result_len, text, strlen(text), + &osta_charspec); + + /* Ecma 167/7.2.13 states that length is recorded in the last byte */ + osta_id[len-1] = strlen(text)+1; +} + + +void +udf_set_timestamp_now(struct timestamp *timestamp) +{ + struct timespec now; + +#ifdef CLOCK_REALTIME + (void)clock_gettime(CLOCK_REALTIME, &now); +#else + struct timeval time_of_day; + + (void)gettimeofday(&time_of_day, NULL); + now.tv_sec = time_of_day.tv_sec; + now.tv_nsec = time_of_day.tv_usec * 1000; +#endif + udf_timespec_to_timestamp(&now, timestamp); +} + + +int +udf_create_primaryd(void) +{ + struct pri_vol_desc *pri; + uint16_t crclen; + + pri = calloc(1, context.sector_size); + if (pri == NULL) + return ENOMEM; + + memset(pri, 0, context.sector_size); + udf_inittag(&pri->tag, TAGID_PRI_VOL, /* loc */ 0); + pri->seq_num = udf_rw32(context.vds_seq); context.vds_seq++; + + pri->pvd_num = udf_rw32(0); /* default serial */ + udf_encode_osta_id(pri->vol_id, 32, context.primary_name); + + /* set defaults for single disc volumes as UDF prescribes */ + pri->vds_num = udf_rw16(1); + pri->max_vol_seq = udf_rw16(1); + pri->ichg_lvl = udf_rw16(2); + pri->max_ichg_lvl = udf_rw16(3); + pri->flags = udf_rw16(0); + + pri->charset_list = udf_rw32(1); /* only CS0 */ + pri->max_charset_list = udf_rw32(1); /* only CS0 */ + + udf_encode_osta_id(pri->volset_id, 128, context.volset_name); + udf_osta_charset(&pri->desc_charset); + udf_osta_charset(&pri->explanatory_charset); + + udf_set_regid(&pri->app_id, context.app_name); + udf_add_app_regid(&pri->app_id); + + udf_set_regid(&pri->imp_id, context.impl_name); + udf_add_impl_regid(&pri->imp_id); + + udf_set_timestamp_now(&pri->time); + + crclen = sizeof(struct pri_vol_desc) - UDF_DESC_TAG_LENGTH; + pri->tag.desc_crc_len = udf_rw16(crclen); + + context.primary_vol = pri; + + return 0; +} + + +/* + * BUGALERT: some rogue implementations use random physical partition + * numbers to break other implementations so lookup the number. + */ + +uint16_t +udf_find_raw_phys(uint16_t raw_phys_part) +{ + struct part_desc *part; + uint16_t phys_part; + + for (phys_part = 0; phys_part < UDF_PARTITIONS; phys_part++) { + part = context.partitions[phys_part]; + if (part == NULL) + break; + if (udf_rw16(part->part_num) == raw_phys_part) + break; + } + return phys_part; +} + + +/* XXX no support for unallocated or freed space tables yet (!) */ +int +udf_create_partitiond(int part_num) +{ + struct part_desc *pd; + struct part_hdr_desc *phd; + uint32_t sector_size, bitmap_bytes; + uint16_t crclen; + int part_accesstype = context.media_accesstype; + + sector_size = context.sector_size; + bitmap_bytes = layout.alloc_bitmap_dscr_size * sector_size; + + if (context.partitions[part_num]) + errx(1, "internal error, partition %d already defined in %s", + part_num, __func__); + + pd = calloc(1, context.sector_size); + if (pd == NULL) + return ENOMEM; + phd = &pd->_impl_use.part_hdr; + + udf_inittag(&pd->tag, TAGID_PARTITION, /* loc */ 0); + pd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++; + + pd->flags = udf_rw16(1); /* allocated */ + pd->part_num = udf_rw16(part_num); /* only one physical partition */ + + if (context.dscrver == 2) { + udf_set_regid(&pd->contents, "+NSR02"); + } else { + udf_set_regid(&pd->contents, "+NSR03"); + } + udf_add_app_regid(&pd->contents); + + phd->unalloc_space_bitmap.len = udf_rw32(bitmap_bytes); + phd->unalloc_space_bitmap.lb_num = udf_rw32(layout.unalloc_space); + + if (layout.freed_space) { + phd->freed_space_bitmap.len = udf_rw32(bitmap_bytes); + phd->freed_space_bitmap.lb_num = udf_rw32(layout.freed_space); + } + + pd->access_type = udf_rw32(part_accesstype); + pd->start_loc = udf_rw32(layout.part_start_lba); + pd->part_len = udf_rw32(layout.part_size_lba); + + udf_set_regid(&pd->imp_id, context.impl_name); + udf_add_impl_regid(&pd->imp_id); + + crclen = sizeof(struct part_desc) - UDF_DESC_TAG_LENGTH; + pd->tag.desc_crc_len = udf_rw16(crclen); + + context.partitions[part_num] = pd; + + return 0; +} + + +int +udf_create_unalloc_spaced(void) +{ + struct unalloc_sp_desc *usd; + uint16_t crclen; + + usd = calloc(1, context.sector_size); + if (usd == NULL) + return ENOMEM; + + udf_inittag(&usd->tag, TAGID_UNALLOC_SPACE, /* loc */ 0); + usd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++; + + /* no default entries */ + usd->alloc_desc_num = udf_rw32(0); /* no entries */ + + crclen = sizeof(struct unalloc_sp_desc) - sizeof(struct extent_ad); + crclen -= UDF_DESC_TAG_LENGTH; + usd->tag.desc_crc_len = udf_rw16(crclen); + + context.unallocated = usd; + + return 0; +} + + +static int +udf_create_base_logical_dscr(void) +{ + struct logvol_desc *lvd; + uint32_t sector_size; + uint16_t crclen; + + sector_size = context.sector_size; + + lvd = calloc(1, sector_size); + if (lvd == NULL) + return ENOMEM; + + udf_inittag(&lvd->tag, TAGID_LOGVOL, /* loc */ 0); + lvd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++; + + udf_osta_charset(&lvd->desc_charset); + udf_encode_osta_id(lvd->logvol_id, 128, context.logvol_name); + lvd->lb_size = udf_rw32(sector_size); + + udf_set_regid(&lvd->domain_id, "*OSTA UDF Compliant"); + udf_add_domain_regid(&lvd->domain_id); + + /* no partition mappings/entries yet */ + lvd->mt_l = udf_rw32(0); + lvd->n_pm = udf_rw32(0); + + udf_set_regid(&lvd->imp_id, context.impl_name); + udf_add_impl_regid(&lvd->imp_id); + + lvd->integrity_seq_loc.loc = udf_rw32(layout.lvis); + lvd->integrity_seq_loc.len = udf_rw32(layout.lvis_size * sector_size); + + /* just one fsd for now */ + lvd->lv_fsd_loc.len = udf_rw32(sector_size); + lvd->lv_fsd_loc.loc.part_num = udf_rw16(context.metadata_part); + lvd->lv_fsd_loc.loc.lb_num = udf_rw32(layout.fsd); + + crclen = sizeof(struct logvol_desc) - 1 - UDF_DESC_TAG_LENGTH; + lvd->tag.desc_crc_len = udf_rw16(crclen); + + context.logical_vol = lvd; + context.vtop_tp[UDF_VTOP_RAWPART] = UDF_VTOP_TYPE_RAW; + + return 0; +} + + +static void +udf_add_logvol_part_physical(uint16_t phys_part) +{ + struct logvol_desc *logvol = context.logical_vol; + union udf_pmap *pmap; + uint8_t *pmap_pos; + uint16_t crclen; + uint32_t pmap1_size, log_part; + + log_part = udf_rw32(logvol->n_pm); + pmap_pos = logvol->maps + udf_rw32(logvol->mt_l); + pmap1_size = sizeof(struct part_map_1); + + pmap = (union udf_pmap *) pmap_pos; + pmap->pm1.type = 1; + pmap->pm1.len = sizeof(struct part_map_1); + pmap->pm1.vol_seq_num = udf_rw16(1); /* no multi-volume */ + pmap->pm1.part_num = udf_rw16(phys_part); + + context.vtop [log_part] = phys_part; + context.vtop_tp [log_part] = UDF_VTOP_TYPE_PHYS; + context.part_size[log_part] = layout.part_size_lba; + context.part_free[log_part] = layout.part_size_lba; + + /* increment number of partitions and length */ + logvol->n_pm = udf_rw32(log_part + 1); + logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmap1_size); + + crclen = udf_rw16(logvol->tag.desc_crc_len) + pmap1_size; + logvol->tag.desc_crc_len = udf_rw16(crclen); +} + + +static void +udf_add_logvol_part_virtual(uint16_t phys_part) +{ + union udf_pmap *pmap; + struct logvol_desc *logvol = context.logical_vol; + uint8_t *pmap_pos; + uint16_t crclen; + uint32_t pmapv_size, log_part; + + log_part = udf_rw32(logvol->n_pm); + pmap_pos = logvol->maps + udf_rw32(logvol->mt_l); + pmapv_size = sizeof(struct part_map_2); + + pmap = (union udf_pmap *) pmap_pos; + pmap->pmv.type = 2; + pmap->pmv.len = pmapv_size; + + udf_set_regid(&pmap->pmv.id, "*UDF Virtual Partition"); + udf_add_udf_regid(&pmap->pmv.id); + + pmap->pmv.vol_seq_num = udf_rw16(1); /* no multi-volume */ + pmap->pmv.part_num = udf_rw16(phys_part); + + context.vtop [log_part] = phys_part; + context.vtop_tp [log_part] = UDF_VTOP_TYPE_VIRT; + context.part_size[log_part] = 0xffffffff; + context.part_free[log_part] = 0xffffffff; + + /* increment number of partitions and length */ + logvol->n_pm = udf_rw32(log_part + 1); + logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmapv_size); + + crclen = udf_rw16(logvol->tag.desc_crc_len) + pmapv_size; + logvol->tag.desc_crc_len = udf_rw16(crclen); +} + + +/* sparing table size is in bytes */ +static void +udf_add_logvol_part_spareable(uint16_t phys_part) +{ + union udf_pmap *pmap; + struct logvol_desc *logvol = context.logical_vol; + uint32_t *st_pos, spareable_bytes, pmaps_size; + uint8_t *pmap_pos, num; + uint16_t crclen; + uint32_t log_part; + + log_part = udf_rw32(logvol->n_pm); + pmap_pos = logvol->maps + udf_rw32(logvol->mt_l); + pmaps_size = sizeof(struct part_map_2); + spareable_bytes = layout.spareable_area_size * context.sector_size; + + pmap = (union udf_pmap *) pmap_pos; + pmap->pms.type = 2; + pmap->pms.len = pmaps_size; + + udf_set_regid(&pmap->pmv.id, "*UDF Sparable Partition"); + udf_add_udf_regid(&pmap->pmv.id); + + pmap->pms.vol_seq_num = udf_rw16(1); /* no multi-volume */ + pmap->pms.part_num = udf_rw16(phys_part); + + pmap->pms.packet_len = udf_rw16(layout.spareable_blockingnr); + pmap->pms.st_size = udf_rw32(spareable_bytes); + + /* enter spare tables */ + st_pos = &pmap->pms.st_loc[0]; + *st_pos++ = udf_rw32(layout.spt_1); + *st_pos++ = udf_rw32(layout.spt_2); + + num = 2; + if (layout.spt_2 == 0) num--; + if (layout.spt_1 == 0) num--; + pmap->pms.n_st = num; /* 8 bit */ + + context.vtop [log_part] = phys_part; + context.vtop_tp [log_part] = UDF_VTOP_TYPE_SPAREABLE; + context.part_size[log_part] = layout.part_size_lba; + context.part_free[log_part] = layout.part_size_lba; + + /* increment number of partitions and length */ + logvol->n_pm = udf_rw32(log_part + 1); + logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmaps_size); + + crclen = udf_rw16(logvol->tag.desc_crc_len) + pmaps_size; + logvol->tag.desc_crc_len = udf_rw16(crclen); +} + + +int +udf_create_sparing_tabled(void) +{ + struct udf_sparing_table *spt; + struct spare_map_entry *sme; + uint32_t loc, cnt; + uint32_t crclen; /* XXX: should be 16; need to detect overflow */ + + spt = calloc(context.sector_size, layout.sparing_table_dscr_lbas); + if (spt == NULL) + return ENOMEM; + + /* a sparing table descriptor is a whole spareable_blockingnr sectors */ + udf_inittag(&spt->tag, TAGID_SPARING_TABLE, /* loc */ 0); + + udf_set_regid(&spt->id, "*UDF Sparing Table"); + udf_add_udf_regid(&spt->id); + + spt->rt_l = udf_rw16(layout.spareable_blocks); + spt->seq_num = udf_rw32(0); /* first generation */ + + for (cnt = 0; cnt < layout.spareable_blocks; cnt++) { + sme = &spt->entries[cnt]; + loc = layout.spareable_area + cnt * layout.spareable_blockingnr; + sme->org = udf_rw32(0xffffffff); /* open for reloc */ + sme->map = udf_rw32(loc); + } + + /* calculate crc len for actual size */ + crclen = sizeof(struct udf_sparing_table) - UDF_DESC_TAG_LENGTH; + crclen += (layout.spareable_blocks-1) * sizeof(struct spare_map_entry); + + assert(crclen <= UINT16_MAX); + spt->tag.desc_crc_len = udf_rw16((uint16_t)crclen); + + context.sparing_table = spt; + + return 0; +} + + +static void +udf_add_logvol_part_meta(uint16_t phys_part) +{ + union udf_pmap *pmap; + struct logvol_desc *logvol = context.logical_vol; + uint8_t *pmap_pos; + uint32_t pmapv_size, log_part; + uint16_t crclen; + + log_part = udf_rw32(logvol->n_pm); + pmap_pos = logvol->maps + udf_rw32(logvol->mt_l); + pmapv_size = sizeof(struct part_map_2); + + pmap = (union udf_pmap *) pmap_pos; + pmap->pmm.type = 2; + pmap->pmm.len = pmapv_size; + + udf_set_regid(&pmap->pmm.id, "*UDF Metadata Partition"); + udf_add_udf_regid(&pmap->pmm.id); + + pmap->pmm.vol_seq_num = udf_rw16(1); /* no multi-volume */ + pmap->pmm.part_num = udf_rw16(phys_part); + + /* fill in meta data file(s) and alloc/alignment unit sizes */ + pmap->pmm.meta_file_lbn = udf_rw32(layout.meta_file); + pmap->pmm.meta_mirror_file_lbn = udf_rw32(layout.meta_mirror); + pmap->pmm.meta_bitmap_file_lbn = udf_rw32(layout.meta_bitmap); + pmap->pmm.alloc_unit_size = udf_rw32(layout.meta_blockingnr); + pmap->pmm.alignment_unit_size = udf_rw16(layout.meta_alignment); + pmap->pmm.flags = 0; /* METADATA_DUPLICATED */ + + context.vtop [log_part] = phys_part; + context.vtop_tp [log_part] = UDF_VTOP_TYPE_META; + context.part_size[log_part] = layout.meta_part_size_lba; + context.part_free[log_part] = layout.meta_part_size_lba; + + /* increment number of partitions and length */ + logvol->n_pm = udf_rw32(log_part + 1); + logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + pmapv_size); + + crclen = udf_rw16(logvol->tag.desc_crc_len) + pmapv_size; + logvol->tag.desc_crc_len = udf_rw16(crclen); +} + + +int +udf_create_logical_dscr(void) +{ + int error; + + if ((error = udf_create_base_logical_dscr())) + return error; + + /* we pass data_part for there might be a read-only part one day */ + if (context.format_flags & FORMAT_SPAREABLE) { + /* spareable partition mapping has no physical mapping */ + udf_add_logvol_part_spareable(context.data_part); + } else { + udf_add_logvol_part_physical(context.data_part); + } + + if (context.format_flags & FORMAT_VAT) { + /* add VAT virtual mapping; reflects on datapart */ + udf_add_logvol_part_virtual(context.data_part); + } + if (context.format_flags & FORMAT_META) { + /* add META data mapping; reflects on datapart */ + udf_add_logvol_part_meta(context.data_part); + } + + return 0; +} + + +int +udf_create_impvold(char *field1, char *field2, char *field3) +{ + struct impvol_desc *ivd; + struct udf_lv_info *lvi; + uint16_t crclen; + + ivd = calloc(1, context.sector_size); + if (ivd == NULL) + return ENOMEM; + lvi = &ivd->_impl_use.lv_info; + + udf_inittag(&ivd->tag, TAGID_IMP_VOL, /* loc */ 0); + ivd->seq_num = udf_rw32(context.vds_seq); context.vds_seq++; + + udf_set_regid(&ivd->impl_id, "*UDF LV Info"); + udf_add_udf_regid(&ivd->impl_id); + + /* fill in UDF specific part */ + udf_osta_charset(&lvi->lvi_charset); + udf_encode_osta_id(lvi->logvol_id, 128, context.logvol_name); + + udf_encode_osta_id(lvi->lvinfo1, 36, field1); + udf_encode_osta_id(lvi->lvinfo2, 36, field2); + udf_encode_osta_id(lvi->lvinfo3, 36, field3); + + udf_set_regid(&lvi->impl_id, context.impl_name); + udf_add_impl_regid(&lvi->impl_id); + + crclen = sizeof(struct impvol_desc) - UDF_DESC_TAG_LENGTH; + ivd->tag.desc_crc_len = udf_rw16(crclen); + + context.implementation = ivd; + + return 0; +} + + +/* XXX might need to be sanitised a bit */ +void +udf_update_lvintd(int type) +{ + struct logvol_int_desc *lvid; + struct udf_logvol_info *lvinfo; + struct logvol_desc *logvol; + uint32_t *pos; + uint32_t cnt, num_partmappings; + uint32_t crclen; /* XXX: should be 16; need to detect overflow */ + + lvid = context.logvol_integrity; + logvol = context.logical_vol; + assert(lvid); + assert(logvol); + + lvid->integrity_type = udf_rw32(type); + udf_set_timestamp_now(&lvid->time); + + /* initialise lvinfo just in case its not set yet */ + num_partmappings = udf_rw32(logvol->n_pm); + assert(num_partmappings > 0); + + lvinfo = (struct udf_logvol_info *) + (lvid->tables + num_partmappings * 2); + context.logvol_info = lvinfo; + + udf_set_regid(&lvinfo->impl_id, context.impl_name); + udf_add_impl_regid(&lvinfo->impl_id); + + if (type == UDF_INTEGRITY_CLOSED) { + lvinfo->num_files = udf_rw32(context.num_files); + lvinfo->num_directories = udf_rw32(context.num_directories); + + lvid->lvint_next_unique_id = udf_rw64(context.unique_id); + } + + /* sane enough? */ + if (udf_rw16(lvinfo->min_udf_readver) < context.min_udf) + lvinfo->min_udf_readver = udf_rw16(context.min_udf); + if (udf_rw16(lvinfo->min_udf_writever) < context.min_udf) + lvinfo->min_udf_writever = udf_rw16(context.min_udf); + if (udf_rw16(lvinfo->max_udf_writever) < context.max_udf) + lvinfo->max_udf_writever = udf_rw16(context.max_udf); + + lvid->num_part = udf_rw32(num_partmappings); + + pos = &lvid->tables[0]; + for (cnt = 0; cnt < num_partmappings; cnt++) { + *pos++ = udf_rw32(context.part_free[cnt]); + } + for (cnt = 0; cnt < num_partmappings; cnt++) { + *pos++ = udf_rw32(context.part_size[cnt]); + } + + crclen = sizeof(struct logvol_int_desc) -4 -UDF_DESC_TAG_LENGTH + + udf_rw32(lvid->l_iu); + crclen += num_partmappings * 2 * 4; + + assert(crclen <= UINT16_MAX); + if (lvid->tag.desc_crc_len == 0) + lvid->tag.desc_crc_len = udf_rw16(crclen); + + context.logvol_info = lvinfo; +} + + +int +udf_create_lvintd(int type) +{ + struct logvol_int_desc *lvid; + int l_iu; + + lvid = calloc(1, context.sector_size); + if (lvid == NULL) + return ENOMEM; + + udf_inittag(&lvid->tag, TAGID_LOGVOL_INTEGRITY, /* loc */ 0); + context.logvol_integrity = lvid; + + /* only set for standard UDF info, no extra impl. use needed */ + l_iu = sizeof(struct udf_logvol_info); + lvid->l_iu = udf_rw32(l_iu); + + udf_update_lvintd(type); + + return 0; +} + + +int +udf_create_fsd(void) +{ + struct fileset_desc *fsd; + uint16_t crclen; + + fsd = calloc(1, context.sector_size); + if (fsd == NULL) + return ENOMEM; + + udf_inittag(&fsd->tag, TAGID_FSD, /* loc */ 0); + + udf_set_timestamp_now(&fsd->time); + fsd->ichg_lvl = udf_rw16(3); /* UDF 2.3.2.1 */ + fsd->max_ichg_lvl = udf_rw16(3); /* UDF 2.3.2.2 */ + + fsd->charset_list = udf_rw32(1); /* only CS0 */ + fsd->max_charset_list = udf_rw32(1); /* only CS0 */ + + fsd->fileset_num = udf_rw32(0); /* only one fsd */ + fsd->fileset_desc_num = udf_rw32(0); /* original */ + + udf_osta_charset(&fsd->logvol_id_charset); + udf_encode_osta_id(fsd->logvol_id, 128, context.logvol_name); + + udf_osta_charset(&fsd->fileset_charset); + udf_encode_osta_id(fsd->fileset_id, 32, context.fileset_name); + + /* copyright file and abstract file names obmitted */ + + fsd->rootdir_icb.len = udf_rw32(context.sector_size); + fsd->rootdir_icb.loc.lb_num = udf_rw32(layout.rootdir); + fsd->rootdir_icb.loc.part_num = udf_rw16(context.metadata_part); + + udf_set_regid(&fsd->domain_id, "*OSTA UDF Compliant"); + udf_add_domain_regid(&fsd->domain_id); + + /* next_ex stays zero */ + /* no system streamdirs yet */ + + crclen = sizeof(struct fileset_desc) - UDF_DESC_TAG_LENGTH; + fsd->tag.desc_crc_len = udf_rw16(crclen); + + context.fileset_desc = fsd; + + return 0; +} + + +int +udf_create_space_bitmap(uint32_t dscr_size, uint32_t part_size_lba, + struct space_bitmap_desc **sbdp) +{ + struct space_bitmap_desc *sbd; + uint32_t cnt; + uint16_t crclen; + + *sbdp = NULL; + sbd = calloc(context.sector_size, dscr_size); + if (sbd == NULL) + return ENOMEM; + + udf_inittag(&sbd->tag, TAGID_SPACE_BITMAP, /* loc */ 0); + + sbd->num_bits = udf_rw32(part_size_lba); + sbd->num_bytes = udf_rw32((part_size_lba + 7)/8); + + /* fill space with 0xff to indicate free */ + for (cnt = 0; cnt < udf_rw32(sbd->num_bytes); cnt++) + sbd->data[cnt] = 0xff; + + /* set crc to only cover the header (UDF 2.3.1.2, 2.3.8.1) */ + crclen = sizeof(struct space_bitmap_desc) -1 - UDF_DESC_TAG_LENGTH; + sbd->tag.desc_crc_len = udf_rw16(crclen); + + *sbdp = sbd; + return 0; +} + +/* --------------------------------------------------------------------- */ + +int +udf_register_bad_block(uint32_t location) +{ + struct udf_sparing_table *spt; + struct spare_map_entry *sme, *free_sme; + uint32_t cnt; + + spt = context.sparing_table; + if (spt == NULL) + errx(1, "internal error, adding bad block to " + "non spareable in %s", __func__); + + /* find us a free spare map entry */ + free_sme = NULL; + for (cnt = 0; cnt < layout.spareable_blocks; cnt++) { + sme = &spt->entries[cnt]; + /* if we are allready in it, bail out */ + if (udf_rw32(sme->org) == location) + return 0; + if (udf_rw32(sme->org) == 0xffffffff) { + free_sme = sme; + break; + } + } + if (free_sme == NULL) { + warnx("disc relocation blocks full; disc too damaged"); + return EINVAL; + } + free_sme->org = udf_rw32(location); + + return 0; +} + + +void +udf_mark_allocated(uint32_t start_lb, int partnr, uint32_t blocks) +{ + union dscrptr *dscr; + uint8_t *bpos; + uint32_t cnt, bit; + + /* account for space used on underlying partition */ +#ifdef DEBUG + printf("mark allocated : partnr %d, start_lb %d for %d blocks\n", + partnr, start_lb, blocks); +#endif + + switch (context.vtop_tp[partnr]) { + case UDF_VTOP_TYPE_VIRT: + /* nothing */ + break; + case UDF_VTOP_TYPE_PHYS: + case UDF_VTOP_TYPE_SPAREABLE: + case UDF_VTOP_TYPE_META: + if (context.part_unalloc_bits[context.vtop[partnr]] == NULL) { + context.part_free[partnr] = 0; + break; + } +#ifdef DEBUG + printf("marking %d+%d as used\n", start_lb, blocks); +#endif + dscr = (union dscrptr *) (context.part_unalloc_bits[partnr]); + for (cnt = start_lb; cnt < start_lb + blocks; cnt++) { + bpos = &dscr->sbd.data[cnt / 8]; + bit = cnt % 8; + /* only account for bits marked free */ + if ((*bpos & (1 << bit))) + context.part_free[partnr] -= 1; + *bpos &= ~(1<< bit); + } + break; + default: + errx(1, "internal error: bad mapping type %d in %s", + context.vtop_tp[partnr], __func__); + } +} + + +void +udf_advance_uniqueid(void) +{ + /* Minimum value of 16 : UDF 3.2.1.1, 3.3.3.4. */ + context.unique_id++; + if (context.unique_id < 0x10) + context.unique_id = 0x10; +} + +/* --------------------------------------------------------------------- */ + +/* XXX implement the using of the results */ +int +udf_surface_check(void) +{ + uint32_t loc, block_bytes; + uint32_t sector_size, blockingnr, bpos; + uint8_t *buffer; + int error, num_errors; + + if (mmc_discinfo.mmc_class == MMC_CLASS_DISC) + return 0; + + sector_size = context.sector_size; + blockingnr = layout.blockingnr; + + block_bytes = layout.blockingnr * sector_size; + if ((buffer = malloc(block_bytes)) == NULL) + return ENOMEM; + + /* set all one to not kill Flash memory? */ + for (bpos = 0; bpos < block_bytes; bpos++) + buffer[bpos] = 0x00; + + printf("\nChecking disc surface : phase 1 - writing\n"); + num_errors = 0; + loc = layout.first_lba; + while (loc <= layout.last_lba) { + /* write blockingnr sectors */ + error = pwrite(dev_fd, buffer, block_bytes, + (uint64_t) loc*sector_size); + printf(" %08d + %d (%02d %%)\r", loc, blockingnr, + (int)((100.0 * loc)/layout.last_lba)); + fflush(stdout); + if (error == -1) { + /* block is bad */ + printf("BAD block at %08d + %d \n", + loc, layout.blockingnr); + if ((error = udf_register_bad_block(loc))) { + free(buffer); + return error; + } + num_errors ++; + } + loc += layout.blockingnr; + } + + printf("\nChecking disc surface : phase 2 - reading\n"); + num_errors = 0; + loc = layout.first_lba; + while (loc <= layout.last_lba) { + /* read blockingnr sectors */ + error = pread(dev_fd, buffer, block_bytes, loc*sector_size); + printf(" %08d + %d (%02d %%)\r", loc, blockingnr, + (int)((100.0 * loc)/layout.last_lba)); + fflush(stdout); + if (error == -1) { + /* block is bad */ + printf("BAD block at %08d + %d \n", + loc, layout.blockingnr); + if ((error = udf_register_bad_block(loc))) { + free(buffer); + return error; + } + num_errors ++; + } + loc += layout.blockingnr; + } + printf("Scan complete : %d bad blocks found\n", num_errors); + free(buffer); + + return 0; +} + +/* --------------------------------------------------------------------- */ + +#define UDF_SYMLINKBUFLEN (64*1024) /* picked */ +int +udf_encode_symlink(uint8_t **pathbufp, uint32_t *pathlenp, char *target) +{ + struct charspec osta_charspec; + struct pathcomp pathcomp; + char *pathbuf, *pathpos, *compnamepos; +// char *mntonname; +// int mntonnamelen; + int pathlen, len, compnamelen; + int error; + + /* process `target' to an UDF structure */ + pathbuf = malloc(UDF_SYMLINKBUFLEN); + assert(pathbuf); + + *pathbufp = NULL; + *pathlenp = 0; + + pathpos = pathbuf; + pathlen = 0; + udf_osta_charset(&osta_charspec); + + if (*target == '/') { + /* symlink starts from the root */ + len = UDF_PATH_COMP_SIZE; + memset(&pathcomp, 0, len); + pathcomp.type = UDF_PATH_COMP_ROOT; + +#if 0 + /* XXX how to check for in makefs? */ + /* check if its mount-point relative! */ + mntonname = udf_node->ump->vfs_mountp->mnt_stat.f_mntonname; + mntonnamelen = strlen(mntonname); + if (strlen(target) >= mntonnamelen) { + if (strncmp(target, mntonname, mntonnamelen) == 0) { + pathcomp.type = UDF_PATH_COMP_MOUNTROOT; + target += mntonnamelen; + } + } else { + target++; + } +#else + target++; +#endif + + memcpy(pathpos, &pathcomp, len); + pathpos += len; + pathlen += len; + } + + error = 0; + while (*target) { + /* ignore multiple '/' */ + while (*target == '/') { + target++; + } + if (!*target) + break; + + /* extract component name */ + compnamelen = 0; + compnamepos = target; + while ((*target) && (*target != '/')) { + target++; + compnamelen++; + } + + /* just trunc if too long ?? (security issue) */ + if (compnamelen >= 127) { + error = ENAMETOOLONG; + break; + } + + /* convert unix name to UDF name */ + len = sizeof(struct pathcomp); + memset(&pathcomp, 0, len); + pathcomp.type = UDF_PATH_COMP_NAME; + len = UDF_PATH_COMP_SIZE; + + if ((compnamelen == 2) && (strncmp(compnamepos, "..", 2) == 0)) + pathcomp.type = UDF_PATH_COMP_PARENTDIR; + if ((compnamelen == 1) && (*compnamepos == '.')) + pathcomp.type = UDF_PATH_COMP_CURDIR; + + if (pathcomp.type == UDF_PATH_COMP_NAME) { + unix_to_udf_name( + (char *) &pathcomp.ident, &pathcomp.l_ci, + compnamepos, compnamelen, + &osta_charspec); + len = UDF_PATH_COMP_SIZE + pathcomp.l_ci; + } + + if (pathlen + len >= UDF_SYMLINKBUFLEN) { + error = ENAMETOOLONG; + break; + } + + memcpy(pathpos, &pathcomp, len); + pathpos += len; + pathlen += len; + } + + if (error) { + /* aparently too big */ + free(pathbuf); + return error; + } + + /* return status of symlink contents writeout */ + *pathbufp = (uint8_t *) pathbuf; + *pathlenp = pathlen; + + return 0; + +} +#undef UDF_SYMLINKBUFLEN + + +/* + * XXX note the different semantics from udfclient: for FIDs it still rounds + * up to sectors. Use udf_fidsize() for a correct length. + */ +uint32_t +udf_tagsize(union dscrptr *dscr, uint32_t lb_size) +{ + uint32_t size, tag_id, num_lb, elmsz; + + tag_id = udf_rw16(dscr->tag.id); + + switch (tag_id) { + case TAGID_LOGVOL : + size = sizeof(struct logvol_desc) - 1; + size += udf_rw32(dscr->lvd.mt_l); + break; + case TAGID_UNALLOC_SPACE : + elmsz = sizeof(struct extent_ad); + size = sizeof(struct unalloc_sp_desc) - elmsz; + size += udf_rw32(dscr->usd.alloc_desc_num) * elmsz; + break; + case TAGID_FID : + size = UDF_FID_SIZE + dscr->fid.l_fi + udf_rw16(dscr->fid.l_iu); + size = (size + 3) & ~3; + break; + case TAGID_LOGVOL_INTEGRITY : + size = sizeof(struct logvol_int_desc) - sizeof(uint32_t); + size += udf_rw32(dscr->lvid.l_iu); + size += (2 * udf_rw32(dscr->lvid.num_part) * sizeof(uint32_t)); + break; + case TAGID_SPACE_BITMAP : + size = sizeof(struct space_bitmap_desc) - 1; + size += udf_rw32(dscr->sbd.num_bytes); + break; + case TAGID_SPARING_TABLE : + elmsz = sizeof(struct spare_map_entry); + size = sizeof(struct udf_sparing_table) - elmsz; + size += udf_rw16(dscr->spt.rt_l) * elmsz; + break; + case TAGID_FENTRY : + size = sizeof(struct file_entry); + size += udf_rw32(dscr->fe.l_ea) + udf_rw32(dscr->fe.l_ad)-1; + break; + case TAGID_EXTFENTRY : + size = sizeof(struct extfile_entry); + size += udf_rw32(dscr->efe.l_ea) + udf_rw32(dscr->efe.l_ad)-1; + break; + case TAGID_FSD : + size = sizeof(struct fileset_desc); + break; + default : + size = sizeof(union dscrptr); + break; + } + + if ((size == 0) || (lb_size == 0)) + return 0; + + if (lb_size == 1) + return size; + + /* round up in sectors */ + num_lb = (size + lb_size -1) / lb_size; + return num_lb * lb_size; +} + + +int +udf_fidsize(struct fileid_desc *fid) +{ + uint32_t size; + + if (udf_rw16(fid->tag.id) != TAGID_FID) + errx(1, "internal error, bad tag in %s", __func__); + + size = UDF_FID_SIZE + fid->l_fi + udf_rw16(fid->l_iu); + size = (size + 3) & ~3; + + return size; +} + + +int +udf_create_parentfid(struct fileid_desc *fid, struct long_ad *parent) +{ + /* the size of an empty FID is 38 but needs to be a multiple of 4 */ + int fidsize = 40; + + udf_inittag(&fid->tag, TAGID_FID, udf_rw32(parent->loc.lb_num)); + fid->file_version_num = udf_rw16(1); /* UDF 2.3.4.1 */ + fid->file_char = UDF_FILE_CHAR_DIR | UDF_FILE_CHAR_PAR; + fid->icb = *parent; + fid->icb.longad_uniqueid = parent->longad_uniqueid; + fid->tag.desc_crc_len = udf_rw16(fidsize - UDF_DESC_TAG_LENGTH); + + /* we have to do the fid here explicitly for simplicity */ + udf_validate_tag_and_crc_sums((union dscrptr *) fid); + + return fidsize; +} + + +void +udf_create_fid(uint32_t diroff, struct fileid_desc *fid, char *name, + int file_char, struct long_ad *ref) +{ + struct charspec osta_charspec; + uint32_t endfid; + uint32_t fidsize, lb_rest; + + memset(fid, 0, sizeof(*fid)); + udf_inittag(&fid->tag, TAGID_FID, udf_rw32(ref->loc.lb_num)); + fid->file_version_num = udf_rw16(1); /* UDF 2.3.4.1 */ + fid->file_char = file_char; + fid->l_iu = udf_rw16(0); + fid->icb = *ref; + fid->icb.longad_uniqueid = ref->longad_uniqueid; + + udf_osta_charset(&osta_charspec); + unix_to_udf_name((char *) fid->data, &fid->l_fi, name, strlen(name), + &osta_charspec); + + /* + * OK, tricky part: we need to pad so the next descriptor header won't + * cross the sector boundary + */ + endfid = diroff + udf_fidsize(fid); + lb_rest = context.sector_size - (endfid % context.sector_size); + if (lb_rest < sizeof(struct desc_tag)) { + /* add at least 32 */ + fid->l_iu = udf_rw16(32); + udf_set_regid((struct regid *) fid->data, context.impl_name); + udf_add_impl_regid((struct regid *) fid->data); + + unix_to_udf_name((char *) fid->data + udf_rw16(fid->l_iu), + &fid->l_fi, name, strlen(name), &osta_charspec); + } + + fidsize = udf_fidsize(fid); + fid->tag.desc_crc_len = udf_rw16(fidsize - UDF_DESC_TAG_LENGTH); + + /* make sure the header sums stays correct */ + udf_validate_tag_and_crc_sums((union dscrptr *)fid); +} + + +static void +udf_append_parentfid(union dscrptr *dscr, struct long_ad *parent_icb) +{ + struct file_entry *fe; + struct extfile_entry *efe; + struct fileid_desc *fid; + uint32_t l_ea; + uint32_t fidsize, crclen; + uint8_t *bpos, *data; + + fe = NULL; + efe = NULL; + if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { + fe = &dscr->fe; + data = fe->data; + l_ea = udf_rw32(fe->l_ea); + } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { + efe = &dscr->efe; + data = efe->data; + l_ea = udf_rw32(efe->l_ea); + } else { + errx(1, "internal error, bad tag in %s", __func__); + } + + /* create '..' */ + bpos = data + l_ea; + fid = (struct fileid_desc *) bpos; + fidsize = udf_create_parentfid(fid, parent_icb); + + /* record fidlength information */ + if (fe) { + fe->inf_len = udf_rw64(fidsize); + fe->l_ad = udf_rw32(fidsize); + fe->logblks_rec = udf_rw64(0); /* intern */ + crclen = sizeof(struct file_entry); + } else { + efe->inf_len = udf_rw64(fidsize); + efe->obj_size = udf_rw64(fidsize); + efe->l_ad = udf_rw32(fidsize); + efe->logblks_rec = udf_rw64(0); /* intern */ + crclen = sizeof(struct extfile_entry); + } + crclen -= 1 + UDF_DESC_TAG_LENGTH; + crclen += l_ea + fidsize; + dscr->tag.desc_crc_len = udf_rw16(crclen); + + /* make sure the header sums stays correct */ + udf_validate_tag_and_crc_sums(dscr); +} + +/* --------------------------------------------------------------------- */ + +/* + * Extended attribute support. UDF knows of 3 places for extended attributes: + * + * (a) inside the file's (e)fe in the length of the extended attribute area + * before the allocation descriptors/filedata + * + * (b) in a file referenced by (e)fe->ext_attr_icb and + * + * (c) in the e(fe)'s associated stream directory that can hold various + * sub-files. In the stream directory a few fixed named subfiles are reserved + * for NT/Unix ACL's and OS/2 attributes. + * + * NOTE: Extended attributes are read randomly but always written + * *atomically*. For ACL's this interface is probably different but not known + * to me yet. + * + * Order of extended attributes in a space: + * ECMA 167 EAs + * Non block aligned Implementation Use EAs + * Block aligned Implementation Use EAs + * Application Use EAs + */ + +int +udf_impl_extattr_check(struct impl_extattr_entry *implext) +{ + uint16_t *spos; + + if (strncmp((char *) implext->imp_id.id, "*UDF", 4) == 0) { + /* checksum valid? */ + spos = (uint16_t *) implext->data; + if (udf_rw16(*spos) != udf_ea_cksum((uint8_t *) implext)) + return EINVAL; + } + return 0; +} + +void +udf_calc_impl_extattr_checksum(struct impl_extattr_entry *implext) +{ + uint16_t *spos; + + if (strncmp((char *) implext->imp_id.id, "*UDF", 4) == 0) { + /* set checksum */ + spos = (uint16_t *) implext->data; + *spos = udf_rw16(udf_ea_cksum((uint8_t *) implext)); + } +} + + +int +udf_extattr_search_intern(union dscrptr *dscr, + uint32_t sattr, char const *sattrname, + uint32_t *offsetp, uint32_t *lengthp) +{ + struct extattrhdr_desc *eahdr; + struct extattr_entry *attrhdr; + struct impl_extattr_entry *implext; + uint32_t offset, a_l, sector_size; + uint32_t l_ea; + uint8_t *pos; + int tag_id, error; + + sector_size = context.sector_size; + + /* get information from fe/efe */ + tag_id = udf_rw16(dscr->tag.id); + if (tag_id == TAGID_FENTRY) { + l_ea = udf_rw32(dscr->fe.l_ea); + eahdr = (struct extattrhdr_desc *) dscr->fe.data; + } else { + assert(tag_id == TAGID_EXTFENTRY); + l_ea = udf_rw32(dscr->efe.l_ea); + eahdr = (struct extattrhdr_desc *) dscr->efe.data; + } + + /* something recorded here? */ + if (l_ea == 0) + return ENOENT; + + /* check extended attribute tag; what to do if it fails? */ + error = udf_check_tag(eahdr); + if (error) + return EINVAL; + if (udf_rw16(eahdr->tag.id) != TAGID_EXTATTR_HDR) + return EINVAL; + error = udf_check_tag_payload(eahdr, sizeof(struct extattrhdr_desc)); + if (error) + return EINVAL; + + /* looking for Ecma-167 attributes? */ + offset = sizeof(struct extattrhdr_desc); + + /* looking for either implementation use or application use */ + if (sattr == 2048) { /* [4/48.10.8] */ + offset = udf_rw32(eahdr->impl_attr_loc); + if (offset == UDF_IMPL_ATTR_LOC_NOT_PRESENT) + return ENOENT; + } + if (sattr == 65536) { /* [4/48.10.9] */ + offset = udf_rw32(eahdr->appl_attr_loc); + if (offset == UDF_APPL_ATTR_LOC_NOT_PRESENT) + return ENOENT; + } + + /* paranoia check offset and l_ea */ + if (l_ea + offset >= sector_size - sizeof(struct extattr_entry)) + return EINVAL; + + /* find our extended attribute */ + l_ea -= offset; + pos = (uint8_t *) eahdr + offset; + + while (l_ea >= sizeof(struct extattr_entry)) { + attrhdr = (struct extattr_entry *) pos; + implext = (struct impl_extattr_entry *) pos; + + /* get complete attribute length and check for roque values */ + a_l = udf_rw32(attrhdr->a_l); + if ((a_l == 0) || (a_l > l_ea)) + return EINVAL; + + if (udf_rw32(attrhdr->type) != sattr) + goto next_attribute; + + /* we might have found it! */ + if (udf_rw32(attrhdr->type) < 2048) { /* Ecma-167 attribute */ + *offsetp = offset; + *lengthp = a_l; + return 0; /* success */ + } + + /* + * Implementation use and application use extended attributes + * have a name to identify. They share the same structure only + * UDF implementation use extended attributes have a checksum + * we need to check + */ + + if (strcmp((char *) implext->imp_id.id, sattrname) == 0) { + /* we have found our appl/implementation attribute */ + *offsetp = offset; + *lengthp = a_l; + return 0; /* success */ + } + +next_attribute: + /* next attribute */ + pos += a_l; + l_ea -= a_l; + offset += a_l; + } + /* not found */ + return ENOENT; +} + + +static void +udf_extattr_insert_internal(union dscrptr *dscr, struct extattr_entry *extattr) +{ + struct file_entry *fe; + struct extfile_entry *efe; + struct extattrhdr_desc *extattrhdr; + struct impl_extattr_entry *implext; + uint32_t impl_attr_loc, appl_attr_loc, l_ea, l_ad, a_l; + uint16_t *spos; + uint8_t *bpos, *data; + void *l_eap; + + if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { + fe = &dscr->fe; + data = fe->data; + l_eap = &fe->l_ea; + l_ad = udf_rw32(fe->l_ad); + } else if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { + efe = &dscr->efe; + data = efe->data; + l_eap = &efe->l_ea; + l_ad = udf_rw32(efe->l_ad); + } else { + errx(1, "internal error, bad tag in %s", __func__); + } + + /* should have a header! */ + extattrhdr = (struct extattrhdr_desc *) data; + memcpy(&l_ea, l_eap, sizeof(l_ea)); + l_ea = udf_rw32(l_ea); + if (l_ea == 0) { + uint32_t exthdr_len; + assert(l_ad == 0); + /* create empty extended attribute header */ + l_ea = sizeof(struct extattrhdr_desc); + exthdr_len = udf_rw32(l_ea); + + udf_inittag(&extattrhdr->tag, TAGID_EXTATTR_HDR, /* loc */ 0); + extattrhdr->impl_attr_loc = exthdr_len; + extattrhdr->appl_attr_loc = exthdr_len; + extattrhdr->tag.desc_crc_len = udf_rw16(8); + + /* record extended attribute header length */ + memcpy(l_eap, &exthdr_len, sizeof(exthdr_len)); + } + + /* extract locations */ + impl_attr_loc = udf_rw32(extattrhdr->impl_attr_loc); + appl_attr_loc = udf_rw32(extattrhdr->appl_attr_loc); + if (impl_attr_loc == UDF_IMPL_ATTR_LOC_NOT_PRESENT) + impl_attr_loc = l_ea; + if (appl_attr_loc == UDF_IMPL_ATTR_LOC_NOT_PRESENT) + appl_attr_loc = l_ea; + + /* Ecma 167 EAs */ + if (udf_rw32(extattr->type) < 2048) { + assert(impl_attr_loc == l_ea); + assert(appl_attr_loc == l_ea); + } + + /* implementation use extended attributes */ + if (udf_rw32(extattr->type) == 2048) { + assert(appl_attr_loc == l_ea); + + /* calculate and write extended attribute header checksum */ + implext = (struct impl_extattr_entry *) extattr; + assert(udf_rw32(implext->iu_l) == 4); /* [UDF 3.3.4.5] */ + spos = (uint16_t *) implext->data; + *spos = udf_rw16(udf_ea_cksum((uint8_t *) implext)); + } + + /* application use extended attributes */ + assert(udf_rw32(extattr->type) != 65536); + assert(appl_attr_loc == l_ea); + + /* append the attribute at the end of the current space */ + bpos = data + l_ea; + a_l = udf_rw32(extattr->a_l); + + /* update impl. attribute locations */ + if (udf_rw32(extattr->type) < 2048) { + impl_attr_loc = l_ea + a_l; + appl_attr_loc = l_ea + a_l; + } + if (udf_rw32(extattr->type) == 2048) { + appl_attr_loc = l_ea + a_l; + } + + /* copy and advance */ + memcpy(bpos, extattr, a_l); + l_ea += a_l; + l_ea = udf_rw32(l_ea); + memcpy(l_eap, &l_ea, sizeof(l_ea)); + + /* do the `dance` again backwards */ + if (context.dscrver != 2) { + if (impl_attr_loc == l_ea) + impl_attr_loc = UDF_IMPL_ATTR_LOC_NOT_PRESENT; + if (appl_attr_loc == l_ea) + appl_attr_loc = UDF_APPL_ATTR_LOC_NOT_PRESENT; + } + + /* store offsets */ + extattrhdr->impl_attr_loc = udf_rw32(impl_attr_loc); + extattrhdr->appl_attr_loc = udf_rw32(appl_attr_loc); + + /* make sure the header sums stays correct */ + udf_validate_tag_and_crc_sums((union dscrptr *) extattrhdr); +} + +/* --------------------------------------------------------------------- */ + +int +udf_create_new_fe(struct file_entry **fep, int file_type, struct stat *st) +{ + struct file_entry *fe; + struct icb_tag *icb; + struct timestamp birthtime; + struct filetimes_extattr_entry *ft_extattr; + uint32_t crclen; /* XXX: should be 16; need to detect overflow */ + uint16_t icbflags; + + *fep = NULL; + fe = calloc(1, context.sector_size); + if (fe == NULL) + return ENOMEM; + + udf_inittag(&fe->tag, TAGID_FENTRY, /* loc */ 0); + icb = &fe->icbtag; + + /* + * Always use strategy type 4 unless on WORM wich we don't support + * (yet). Fill in defaults and set for internal allocation of data. + */ + icb->strat_type = udf_rw16(4); + icb->max_num_entries = udf_rw16(1); + icb->file_type = file_type; /* 8 bit */ + icb->flags = udf_rw16(UDF_ICB_INTERN_ALLOC); + + fe->perm = udf_rw32(0x7fff); /* all is allowed */ + fe->link_cnt = udf_rw16(0); /* explicit setting */ + + fe->ckpoint = udf_rw32(1); /* user supplied file version */ + + udf_set_timestamp_now(&birthtime); + udf_set_timestamp_now(&fe->atime); + udf_set_timestamp_now(&fe->attrtime); + udf_set_timestamp_now(&fe->mtime); + + /* set attributes */ + if (st) { + +#if !HAVE_NBTOOL_CONFIG_H +#if 0 + udf_set_timestamp(&birthtime, st->st_birthtime); +#else +#endif + udf_set_timestamp(&birthtime, 0); +#endif + udf_set_timestamp(&fe->atime, st->st_atime); + udf_set_timestamp(&fe->attrtime, st->st_ctime); + udf_set_timestamp(&fe->mtime, st->st_mtime); + fe->uid = udf_rw32(st->st_uid); + fe->gid = udf_rw32(st->st_gid); + + fe->perm = udf_rw32(unix_mode_to_udf_perm(st->st_mode)); + + icbflags = udf_rw16(fe->icbtag.flags); + icbflags &= ~UDF_ICB_TAG_FLAGS_SETUID; + icbflags &= ~UDF_ICB_TAG_FLAGS_SETGID; + icbflags &= ~UDF_ICB_TAG_FLAGS_STICKY; + if (st->st_mode & S_ISUID) + icbflags |= UDF_ICB_TAG_FLAGS_SETUID; + if (st->st_mode & S_ISGID) + icbflags |= UDF_ICB_TAG_FLAGS_SETGID; + if (st->st_mode & S_ISVTX) + icbflags |= UDF_ICB_TAG_FLAGS_STICKY; + fe->icbtag.flags = udf_rw16(icbflags); + } + + udf_set_regid(&fe->imp_id, context.impl_name); + udf_add_impl_regid(&fe->imp_id); + fe->unique_id = udf_rw64(context.unique_id); + udf_advance_uniqueid(); + + fe->l_ea = udf_rw32(0); + + /* create extended attribute to record our creation time */ + ft_extattr = calloc(1, UDF_FILETIMES_ATTR_SIZE(1)); + ft_extattr->hdr.type = udf_rw32(UDF_FILETIMES_ATTR_NO); + ft_extattr->hdr.subtype = 1; /* [4/48.10.5] */ + ft_extattr->hdr.a_l = udf_rw32(UDF_FILETIMES_ATTR_SIZE(1)); + ft_extattr->d_l = udf_rw32(UDF_TIMESTAMP_SIZE); /* one item */ + ft_extattr->existence = UDF_FILETIMES_FILE_CREATION; + ft_extattr->times[0] = birthtime; + + udf_extattr_insert_internal((union dscrptr *) fe, + (struct extattr_entry *) ft_extattr); + free(ft_extattr); + + /* record fidlength information */ + fe->inf_len = udf_rw64(0); + fe->l_ad = udf_rw32(0); + fe->logblks_rec = udf_rw64(0); /* intern */ + + crclen = sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH; + crclen += udf_rw32(fe->l_ea); + + /* make sure the header sums stays correct */ + fe->tag.desc_crc_len = udf_rw16(crclen); + udf_validate_tag_and_crc_sums((union dscrptr *) fe); + + *fep = fe; + return 0; +} + + +int +udf_create_new_efe(struct extfile_entry **efep, int file_type, struct stat *st) +{ + struct extfile_entry *efe; + struct icb_tag *icb; + uint32_t crclen; /* XXX: should be 16; need to detect overflow */ + uint16_t icbflags; + + *efep = NULL; + efe = calloc(1, context.sector_size); + if (efe == NULL) + return ENOMEM; + + udf_inittag(&efe->tag, TAGID_EXTFENTRY, /* loc */ 0); + icb = &efe->icbtag; + + /* + * Always use strategy type 4 unless on WORM wich we don't support + * (yet). Fill in defaults and set for internal allocation of data. + */ + icb->strat_type = udf_rw16(4); + icb->max_num_entries = udf_rw16(1); + icb->file_type = file_type; /* 8 bit */ + icb->flags = udf_rw16(UDF_ICB_INTERN_ALLOC); + + efe->perm = udf_rw32(0x7fff); /* all is allowed */ + efe->link_cnt = udf_rw16(0); /* explicit setting */ + + efe->ckpoint = udf_rw32(1); /* user supplied file version */ + + udf_set_timestamp_now(&efe->ctime); + udf_set_timestamp_now(&efe->atime); + udf_set_timestamp_now(&efe->attrtime); + udf_set_timestamp_now(&efe->mtime); + + /* set attributes */ + if (st) { +#if !HAVE_NBTOOL_CONFIG_H +#if 0 + udf_set_timestamp(&efe->ctime, st->st_birthtime); +#else +#endif + udf_set_timestamp(&efe->ctime, 0); +#endif + udf_set_timestamp(&efe->atime, st->st_atime); + udf_set_timestamp(&efe->attrtime, st->st_ctime); + udf_set_timestamp(&efe->mtime, st->st_mtime); + efe->uid = udf_rw32(st->st_uid); + efe->gid = udf_rw32(st->st_gid); + + efe->perm = udf_rw32(unix_mode_to_udf_perm(st->st_mode)); + + icbflags = udf_rw16(efe->icbtag.flags); + icbflags &= ~UDF_ICB_TAG_FLAGS_SETUID; + icbflags &= ~UDF_ICB_TAG_FLAGS_SETGID; + icbflags &= ~UDF_ICB_TAG_FLAGS_STICKY; + if (st->st_mode & S_ISUID) + icbflags |= UDF_ICB_TAG_FLAGS_SETUID; + if (st->st_mode & S_ISGID) + icbflags |= UDF_ICB_TAG_FLAGS_SETGID; + if (st->st_mode & S_ISVTX) + icbflags |= UDF_ICB_TAG_FLAGS_STICKY; + efe->icbtag.flags = udf_rw16(icbflags); + } + + udf_set_regid(&efe->imp_id, context.impl_name); + udf_add_impl_regid(&efe->imp_id); + + efe->unique_id = udf_rw64(context.unique_id); + udf_advance_uniqueid(); + + /* record fidlength information */ + efe->inf_len = udf_rw64(0); + efe->obj_size = udf_rw64(0); + efe->l_ad = udf_rw32(0); + efe->logblks_rec = udf_rw64(0); + + crclen = sizeof(struct extfile_entry) - 1 - UDF_DESC_TAG_LENGTH; + + /* make sure the header sums stays correct */ + efe->tag.desc_crc_len = udf_rw16(crclen); + udf_validate_tag_and_crc_sums((union dscrptr *) efe); + + *efep = efe; + return 0; +} + +/* --------------------------------------------------------------------- */ + +/* for METADATA file appending only */ +static void +udf_append_meta_mapping_part_to_efe(struct extfile_entry *efe, + struct short_ad *mapping) +{ + struct icb_tag *icb; + uint64_t inf_len, obj_size, logblks_rec; + uint32_t l_ad, l_ea; + uint16_t crclen; + uintptr_t bpos; + + inf_len = udf_rw64(efe->inf_len); + obj_size = udf_rw64(efe->obj_size); + logblks_rec = udf_rw64(efe->logblks_rec); + l_ad = udf_rw32(efe->l_ad); + l_ea = udf_rw32(efe->l_ea); + crclen = udf_rw16(efe->tag.desc_crc_len); + icb = &efe->icbtag; + + /* set our allocation to shorts if not already done */ + icb->flags = udf_rw16(UDF_ICB_SHORT_ALLOC); + + /* append short_ad */ + bpos = (uintptr_t)efe->data + l_ea + l_ad; + memcpy((void *)bpos, mapping, sizeof(struct short_ad)); + + l_ad += sizeof(struct short_ad); + crclen += sizeof(struct short_ad); + inf_len += UDF_EXT_LEN(udf_rw32(mapping->len)); + obj_size += UDF_EXT_LEN(udf_rw32(mapping->len)); + logblks_rec = UDF_ROUNDUP(inf_len, context.sector_size) / + context.sector_size; + + efe->l_ad = udf_rw32(l_ad); + efe->inf_len = udf_rw64(inf_len); + efe->obj_size = udf_rw64(obj_size); + efe->logblks_rec = udf_rw64(logblks_rec); + efe->tag.desc_crc_len = udf_rw16(crclen); +} + + +/* for METADATA file appending only */ +static void +udf_append_meta_mapping_to_efe(struct extfile_entry *efe, + uint16_t partnr, uint32_t lb_num, + uint64_t len) +{ + struct short_ad mapping; + uint64_t max_len, part_len; + + /* calculate max length meta allocation sizes */ + max_len = UDF_EXT_MAXLEN / context.sector_size; /* in sectors */ + max_len = (max_len / layout.meta_blockingnr) * layout.meta_blockingnr; + max_len = max_len * context.sector_size; + + memset(&mapping, 0, sizeof(mapping)); + while (len) { + part_len = MIN(len, max_len); + mapping.lb_num = udf_rw32(lb_num); + mapping.len = udf_rw32(part_len); + + udf_append_meta_mapping_part_to_efe(efe, &mapping); + + lb_num += part_len / context.sector_size; + len -= part_len; + } +} + + +int +udf_create_meta_files(void) +{ + struct extfile_entry *efe; + struct long_ad meta_icb; + uint64_t bytes; + uint32_t sector_size; + int filetype, error; + + sector_size = context.sector_size; + + memset(&meta_icb, 0, sizeof(meta_icb)); + meta_icb.len = udf_rw32(sector_size); + meta_icb.loc.part_num = udf_rw16(context.data_part); + + /* create metadata file */ + meta_icb.loc.lb_num = udf_rw32(layout.meta_file); + filetype = UDF_ICB_FILETYPE_META_MAIN; + error = udf_create_new_efe(&efe, filetype, NULL); + if (error) + return error; + context.meta_file = efe; + context.meta_file->unique_id = udf_rw64(0); + + /* create metadata mirror file */ + meta_icb.loc.lb_num = udf_rw32(layout.meta_mirror); + filetype = UDF_ICB_FILETYPE_META_MIRROR; + error = udf_create_new_efe(&efe, filetype, NULL); + if (error) + return error; + context.meta_mirror = efe; + context.meta_mirror->unique_id = udf_rw64(0); + + if (!(context.format_flags & FORMAT_READONLY)) { + /* create metadata bitmap file */ + meta_icb.loc.lb_num = udf_rw32(layout.meta_bitmap); + filetype = UDF_ICB_FILETYPE_META_BITMAP; + error = udf_create_new_efe(&efe, filetype, NULL); + if (error) + return error; + context.meta_bitmap = efe; + context.meta_bitmap->unique_id = udf_rw64(0); + } + + /* restart unique id */ + context.unique_id = 0x10; + + /* XXX no support for metadata mirroring yet */ + /* insert extents */ + efe = context.meta_file; + udf_append_meta_mapping_to_efe(efe, context.data_part, + layout.meta_part_start_lba, + (uint64_t) layout.meta_part_size_lba * sector_size); + + efe = context.meta_mirror; + udf_append_meta_mapping_to_efe(efe, context.data_part, + layout.meta_part_start_lba, + (uint64_t) layout.meta_part_size_lba * sector_size); + + if (context.meta_bitmap) { + efe = context.meta_bitmap; + bytes = udf_space_bitmap_len(layout.meta_part_size_lba); + udf_append_meta_mapping_to_efe(efe, context.data_part, + layout.meta_bitmap_space, bytes); + } + + return 0; +} + + +/* --------------------------------------------------------------------- */ + +int +udf_create_new_rootdir(union dscrptr **dscr) +{ + struct file_entry *fe; + struct extfile_entry *efe; + struct long_ad root_icb; + int filetype, error; + + memset(&root_icb, 0, sizeof(root_icb)); + root_icb.len = udf_rw32(context.sector_size); + root_icb.loc.lb_num = udf_rw32(layout.rootdir); + root_icb.loc.part_num = udf_rw16(context.metadata_part); + + filetype = UDF_ICB_FILETYPE_DIRECTORY; + if (context.dscrver == 2) { + error = udf_create_new_fe(&fe, filetype, NULL); + *dscr = (union dscrptr *) fe; + } else { + error = udf_create_new_efe(&efe, filetype, NULL); + *dscr = (union dscrptr *) efe; + } + if (error) + return error; + + /* append '..' */ + udf_append_parentfid(*dscr, &root_icb); + + /* rootdir has explicit only one link on creation; '..' is no link */ + if (context.dscrver == 2) { + fe->link_cnt = udf_rw16(1); + } else { + efe->link_cnt = udf_rw16(1); + } + + context.num_directories++; + assert(context.num_directories == 1); + + return 0; +} + + +void +udf_prepend_VAT_file(void) +{ + /* old style VAT has no prepend */ + if (context.dscrver == 2) { + context.vat_start = 0; + context.vat_size = 0; + return; + } + + context.vat_start = offsetof(struct udf_vat, data); + context.vat_size = offsetof(struct udf_vat, data); +} + + +void +udf_vat_update(uint32_t virt, uint32_t phys) +{ + uint32_t *vatpos; + uint32_t new_size; + + if (context.vtop_tp[context.metadata_part] != UDF_VTOP_TYPE_VIRT) + return; + + new_size = MAX(context.vat_size, + (context.vat_start + (virt+1)*sizeof(uint32_t))); + + if (new_size > context.vat_allocated) { + context.vat_allocated = + UDF_ROUNDUP(new_size, context.sector_size); + context.vat_contents = realloc(context.vat_contents, + context.vat_allocated); + assert(context.vat_contents); + /* XXX could also report error */ + } + vatpos = (uint32_t *) (context.vat_contents + context.vat_start); + vatpos[virt] = udf_rw32(phys); + + context.vat_size = MAX(context.vat_size, + (context.vat_start + (virt+1)*sizeof(uint32_t))); +} + + +int +udf_append_VAT_file(void) +{ + struct udf_oldvat_tail *oldvat_tail; + struct udf_vat *vathdr; + int32_t len_diff; + + /* new style VAT has VAT LVInt analog in front */ + if (context.dscrver == 3) { + /* set up VATv2 descriptor */ + vathdr = (struct udf_vat *) context.vat_contents; + vathdr->header_len = udf_rw16(sizeof(struct udf_vat) - 1); + vathdr->impl_use_len = udf_rw16(0); + memcpy(vathdr->logvol_id, context.logical_vol->logvol_id, 128); + vathdr->prev_vat = udf_rw32(UDF_NO_PREV_VAT); + vathdr->num_files = udf_rw32(context.num_files); + vathdr->num_directories = udf_rw32(context.num_directories); + + vathdr->min_udf_readver = udf_rw16(context.min_udf); + vathdr->min_udf_writever = udf_rw16(context.min_udf); + vathdr->max_udf_writever = udf_rw16(context.max_udf); + + return 0; + } + + /* old style VAT has identifier appended */ + + /* append "*UDF Virtual Alloc Tbl" id and prev. VAT location */ + len_diff = context.vat_allocated - context.vat_size; + assert(len_diff >= 0); + if (len_diff < (int32_t) sizeof(struct udf_oldvat_tail)) { + context.vat_allocated += context.sector_size; + context.vat_contents = realloc(context.vat_contents, + context.vat_allocated); + assert(context.vat_contents); + /* XXX could also report error */ + } + + oldvat_tail = (struct udf_oldvat_tail *) (context.vat_contents + + context.vat_size); + + udf_set_regid(&oldvat_tail->id, "*UDF Virtual Alloc Tbl"); + udf_add_udf_regid(&oldvat_tail->id); + oldvat_tail->prev_vat = udf_rw32(UDF_NO_PREV_VAT); + + context.vat_size += sizeof(struct udf_oldvat_tail); + + return 0; +} + + +int +udf_create_VAT(union dscrptr **vat_dscr, struct long_ad *vatdata_loc) +{ + struct impl_extattr_entry *implext; + struct vatlvext_extattr_entry *vatlvext; + struct long_ad *allocpos; + uint8_t *bpos, *extattr; + uint32_t ea_len, inf_len, vat_len, blks; + int filetype; + int error; + + assert((layout.rootdir < 2) && (layout.fsd < 2)); + + if (context.dscrver == 2) { + struct file_entry *fe; + + /* old style VAT */ + filetype = UDF_ICB_FILETYPE_UNKNOWN; + error = udf_create_new_fe(&fe, filetype, NULL); + if (error) + return error; + + /* append VAT LVExtension attribute */ + ea_len = sizeof(struct impl_extattr_entry) - 2 + 4 + + sizeof(struct vatlvext_extattr_entry); + + extattr = calloc(1, ea_len); + + implext = (struct impl_extattr_entry *) extattr; + implext->hdr.type = udf_rw32(2048); /* [4/48.10.8] */ + implext->hdr.subtype = 1; /* [4/48.10.8.2] */ + implext->hdr.a_l = udf_rw32(ea_len); /* VAT LVext EA size */ + /* use 4 bytes of imp use for UDF checksum [UDF 3.3.4.5] */ + implext->iu_l = udf_rw32(4); + udf_set_regid(&implext->imp_id, "*UDF VAT LVExtension"); + udf_add_udf_regid(&implext->imp_id); + + /* VAT LVExtension data follows UDF IU space */ + bpos = ((uint8_t *) implext->data) + 4; + vatlvext = (struct vatlvext_extattr_entry *) bpos; + + vatlvext->unique_id_chk = fe->unique_id; + vatlvext->num_files = udf_rw32(context.num_files); + vatlvext->num_directories = udf_rw32(context.num_directories); + memcpy(vatlvext->logvol_id, context.logical_vol->logvol_id,128); + + udf_extattr_insert_internal((union dscrptr *) fe, + (struct extattr_entry *) extattr); + + free(extattr); + + fe->icbtag.flags = udf_rw16(UDF_ICB_LONG_ALLOC); + + allocpos = (struct long_ad *) (fe->data + udf_rw32(fe->l_ea)); + *allocpos = *vatdata_loc; + + /* set length */ + inf_len = context.vat_size; + fe->inf_len = udf_rw64(inf_len); + allocpos->len = udf_rw32(inf_len); + fe->l_ad = udf_rw32(sizeof(struct long_ad)); + blks = UDF_ROUNDUP(inf_len, context.sector_size) / + context.sector_size; + fe->logblks_rec = udf_rw64(blks); + + /* update vat descriptor's CRC length */ + vat_len = sizeof(struct file_entry) - 1 - UDF_DESC_TAG_LENGTH; + vat_len += udf_rw32(fe->l_ad) + udf_rw32(fe->l_ea); + fe->tag.desc_crc_len = udf_rw16(vat_len); + + *vat_dscr = (union dscrptr *) fe; + } else { + /* the choice is between an EFE or an FE as VAT */ +#if 1 + struct extfile_entry *efe; + + /* new style VAT on FE */ + filetype = UDF_ICB_FILETYPE_VAT; + error = udf_create_new_efe(&efe, filetype, NULL); + if (error) + return error; + + efe->icbtag.flags = udf_rw16(UDF_ICB_LONG_ALLOC); + + allocpos = (struct long_ad *) efe->data; + *allocpos = *vatdata_loc; + + /* set length */ + inf_len = context.vat_size; + efe->inf_len = udf_rw64(inf_len); + allocpos->len = udf_rw32(inf_len); + efe->obj_size = udf_rw64(inf_len); + efe->l_ad = udf_rw32(sizeof(struct long_ad)); + blks = UDF_ROUNDUP(inf_len, context.sector_size) / + context.sector_size; + efe->logblks_rec = udf_rw32(blks); + + vat_len = sizeof(struct extfile_entry)-1 - UDF_DESC_TAG_LENGTH; + vat_len += udf_rw32(efe->l_ad); + efe->tag.desc_crc_len = udf_rw16(vat_len); + + *vat_dscr = (union dscrptr *) efe; +#else + struct file_entry *fe; + uint32_t l_ea; + + /* new style VAT on EFE */ + filetype = UDF_ICB_FILETYPE_VAT; + error = udf_create_new_fe(&fe, filetype, NULL); + if (error) + return error; + + fe->icbtag.flags = udf_rw16(UDF_ICB_LONG_ALLOC); + + l_ea = udf_rw32(fe->l_ea); + allocpos = (struct long_ad *) (fe->data + l_ea); + *allocpos = *vatdata_loc; + + /* set length */ + inf_len = context.vat_size; + fe->inf_len = udf_rw64(inf_len); + allocpos->len = udf_rw32(inf_len); + fe->l_ad = udf_rw32(sizeof(struct long_ad)); + blks = UDF_ROUNDUP(inf_len, context.sector_size) / + context.sector_size; + fe->logblks_rec = udf_rw64(blks); + + vat_len = sizeof(struct file_entry)-1 - UDF_DESC_TAG_LENGTH; + vat_len += udf_rw32(fe->l_ad) + udf_rw32(fe->l_ea); + fe->tag.desc_crc_len = udf_rw16(vat_len); + + *vat_dscr = (union dscrptr *) fe; +#endif + } + + return 0; +} + + +int +udf_writeout_VAT(void) +{ + union dscrptr *vat_dscr; + struct long_ad vatdata; + uint32_t loc, phys, ext, sects; + int rel_block, rest_block, error; + + vat_dscr = NULL; + /* update lvint to reflect the newest values (no writeout) */ + udf_update_lvintd(UDF_INTEGRITY_CLOSED); + + error = udf_append_VAT_file(); + if (error) + return error; + + /* write out VAT data */ + sects = UDF_ROUNDUP(context.vat_size, context.sector_size) / + context.sector_size; + layout.vat = context.alloc_pos[context.data_part]; + udf_data_alloc(sects, &vatdata); +//printf("layout.vat %d\n", layout.vat + udf_rw32(context.partitions[context.data_part]->start_loc)); + + loc = udf_rw32(vatdata.loc.lb_num); + udf_translate_vtop(loc, context.data_part, &phys, &ext); + + error = udf_write_phys(context.vat_contents, phys, sects); + if (error) + return error; + loc += sects; + + /* create new VAT descriptor */ + error = udf_create_VAT(&vat_dscr, &vatdata); + if (error) + return error; + +//printf("VAT data at %d\n", vatdata.loc.lb_num); +//printf("VAT itself at %d\n", loc + udf_rw32(context.partitions[context.data_part]->start_loc)); + + /* at least one */ + error = udf_write_dscr_virt(vat_dscr, loc, context.data_part, 1); + loc++; + + error = udf_translate_vtop(loc, context.data_part, &phys, &ext); + assert(!error); + + rel_block = phys - (UDF_ROUNDDOWN(phys, layout.blockingnr) + wrtrack_skew); + rest_block = layout.blockingnr - rel_block; + + for (int i = 0; i < rest_block; i++) { + error = udf_write_dscr_virt(vat_dscr, loc, context.data_part, 1); + loc++; + } + free(vat_dscr); + + return error; +} + + +/* --------------------------------------------------------------------- */ +/* + * mmc_discinfo and mmc_trackinfo readers modified from origional in udf main + * code in sys/fs/udf/ + */ + +void +udf_dump_discinfo(struct mmc_discinfo *di) +{ +#ifdef DEBUG + char bits[128]; + + printf("Device/media info :\n"); + printf("\tMMC profile 0x%02x\n", di->mmc_profile); + printf("\tderived class %d\n", di->mmc_class); + printf("\tsector size %d\n", di->sector_size); + printf("\tdisc state %d\n", di->disc_state); + printf("\tlast ses state %d\n", di->last_session_state); + printf("\tbg format state %d\n", di->bg_format_state); + printf("\tfrst track %d\n", di->first_track); + printf("\tfst on last ses %d\n", di->first_track_last_session); + printf("\tlst on last ses %d\n", di->last_track_last_session); + printf("\tlink block penalty %d\n", di->link_block_penalty); + snprintb(bits, sizeof(bits), MMC_DFLAGS_FLAGBITS, (uint64_t) di->disc_flags); + printf("\tdisc flags %s\n", bits); + printf("\tdisc id %x\n", di->disc_id); + printf("\tdisc barcode %"PRIx64"\n", di->disc_barcode); + + printf("\tnum sessions %d\n", di->num_sessions); + printf("\tnum tracks %d\n", di->num_tracks); + + snprintb(bits, sizeof(bits), MMC_CAP_FLAGBITS, di->mmc_cur); + printf("\tcapabilities cur %s\n", bits); + snprintb(bits, sizeof(bits), MMC_CAP_FLAGBITS, di->mmc_cap); + printf("\tcapabilities cap %s\n", bits); + printf("\n"); + printf("\tlast_possible_lba %d\n", di->last_possible_lba); + printf("\n"); +#endif +} + + +void +udf_synchronise_caches(void) +{ +#if !HAVE_NBTOOL_CONFIG_H + struct mmc_op mmc_op; + + bzero(&mmc_op, sizeof(struct mmc_op)); + mmc_op.operation = MMC_OP_SYNCHRONISECACHE; + + /* this device might not know this ioct, so just be ignorant */ + (void) ioctl(dev_fd, MMCOP, &mmc_op); +#endif +} + + +/* + * General Idea: + * + * stat the dev_fd + * + * If a S_ISREG(), we emulate using the emul_* settings. + * + * If its a device : + * try the MMCGETDISCINFO ioctl() and be done. + * + * If that fails, its a regular disc and set the type to disc media. + * + */ + + +int +udf_update_discinfo(void) +{ + off_t size, last_sector, secsize; + int error; + + memset(&mmc_discinfo, 0, sizeof(struct mmc_discinfo)); + +#if !HAVE_NBTOOL_CONFIG_H + /* check if we're on a MMC capable device, i.e. CD/DVD */ + error = ioctl(dev_fd, MMCGETDISCINFO, &mmc_discinfo); + if (error == 0) { + if ((emul_mmc_profile != -1) && + (emul_mmc_profile != mmc_discinfo.mmc_profile)) { + errno = EINVAL; + perror("media and specified disc type mismatch"); + return errno; + } + emul_size = 0; + return 0; + } +#endif + + if (S_ISREG(dev_fd_stat.st_mode)) { + /* file support; we pick the minimum sector size allowed */ + if (emul_mmc_profile < 0) + emul_mmc_profile = 0x01; + if (emul_size == 0) + emul_size = dev_fd_stat.st_size; + size = emul_size; + secsize = emul_sectorsize; + last_sector = (size / secsize) - 1; + if (ftruncate(dev_fd, size)) { + perror("can't resize file"); + return EXIT_FAILURE; + } + } else { +#if !HAVE_NBTOOL_CONFIG_H +#if 0 + struct disk_geom geo; + struct dkwedge_info dkw; + + /* sanity */ + if (emul_mmc_profile <= 0) + emul_mmc_profile = 0x01; + if (emul_mmc_profile != 0x01) { + warnx("format incompatible with disc partition"); + return EXIT_FAILURE; + } + + /* get our disc info */ + error = getdiskinfo(dev_name, dev_fd, NULL, &geo, &dkw); + if (error) { + warn("retrieving disc info failed"); + return EXIT_FAILURE; + } + secsize = emul_sectorsize; + last_sector = (dkw.dkw_size - 1) * geo.dg_secsize / secsize; +#endif +#else + warnx("disk partitions only usable outside tools"); + return EIO; +#endif + } + + /* commons */ + mmc_discinfo.mmc_profile = emul_mmc_profile; + mmc_discinfo.disc_state = MMC_STATE_CLOSED; + mmc_discinfo.last_session_state = MMC_STATE_CLOSED; + mmc_discinfo.bg_format_state = MMC_BGFSTATE_COMPLETED; + mmc_discinfo.link_block_penalty = 0; + + mmc_discinfo.disc_flags = MMC_DFLAGS_UNRESTRICTED; + + mmc_discinfo.last_possible_lba = last_sector; + mmc_discinfo.sector_size = secsize; + + mmc_discinfo.num_sessions = 1; + mmc_discinfo.num_tracks = 1; + + mmc_discinfo.first_track = 1; + mmc_discinfo.first_track_last_session = mmc_discinfo.last_track_last_session = 1; + + mmc_discinfo.mmc_cur = MMC_CAP_RECORDABLE | MMC_CAP_ZEROLINKBLK; + switch (emul_mmc_profile) { + case 0x00: /* unknown, treat as CDROM */ + case 0x08: /* CDROM */ + case 0x10: /* DVDROM */ + case 0x40: /* BDROM */ + /* FALLTHROUGH */ + case 0x01: /* disc */ + /* set up a disc info profile for partitions/files */ + mmc_discinfo.mmc_class = MMC_CLASS_DISC; + mmc_discinfo.mmc_cur |= MMC_CAP_REWRITABLE | MMC_CAP_HW_DEFECTFREE; + break; + case 0x09: /* CD-R */ + mmc_discinfo.mmc_class = MMC_CLASS_CD; + mmc_discinfo.mmc_cur |= MMC_CAP_SEQUENTIAL; + mmc_discinfo.disc_state = MMC_STATE_EMPTY; + break; + case 0x0a: /* CD-RW + CD-MRW (regretably) */ + mmc_discinfo.mmc_class = MMC_CLASS_CD; + mmc_discinfo.mmc_cur |= MMC_CAP_REWRITABLE; + break; + case 0x13: /* DVD-RW */ + case 0x1a: /* DVD+RW */ + mmc_discinfo.mmc_class = MMC_CLASS_DVD; + mmc_discinfo.mmc_cur |= MMC_CAP_REWRITABLE; + break; + case 0x11: /* DVD-R */ + case 0x14: /* DVD-RW sequential */ + case 0x1b: /* DVD+R */ + case 0x2b: /* DVD+R DL */ + case 0x51: /* HD DVD-R */ + mmc_discinfo.mmc_class = MMC_CLASS_DVD; + mmc_discinfo.mmc_cur |= MMC_CAP_SEQUENTIAL; + mmc_discinfo.disc_state = MMC_STATE_EMPTY; + break; + case 0x41: /* BD-R */ + mmc_discinfo.mmc_class = MMC_CLASS_BD; + mmc_discinfo.mmc_cur |= MMC_CAP_SEQUENTIAL | MMC_CAP_HW_DEFECTFREE; + mmc_discinfo.disc_state = MMC_STATE_EMPTY; + break; + case 0x43: /* BD-RE */ + mmc_discinfo.mmc_class = MMC_CLASS_BD; + mmc_discinfo.mmc_cur |= MMC_CAP_REWRITABLE | MMC_CAP_HW_DEFECTFREE; + break; + default: + errno = EINVAL; + perror("unknown or unimplemented device type"); + return errno; + } + mmc_discinfo.mmc_cap = mmc_discinfo.mmc_cur; + + return 0; +} + + +int +udf_update_trackinfo(struct mmc_trackinfo *ti) +{ + int error, class; + +#if !HAVE_NBTOOL_CONFIG_H + class = mmc_discinfo.mmc_class; + if (class != MMC_CLASS_DISC) { + /* tracknr specified in struct ti */ + error = ioctl(dev_fd, MMCGETTRACKINFO, ti); + if (!error) + return 0; + } +#endif + + /* discs partition support */ + if (ti->tracknr != 1) + return EIO; + + /* create fake ti (TODO check for resized vnds) */ + ti->sessionnr = 1; + + ti->track_mode = 0; /* XXX */ + ti->data_mode = 0; /* XXX */ + ti->flags = MMC_TRACKINFO_LRA_VALID | MMC_TRACKINFO_NWA_VALID; + + ti->track_start = 0; + ti->packet_size = emul_packetsize; + + /* TODO support for resizable vnd */ + ti->track_size = mmc_discinfo.last_possible_lba; + ti->next_writable = mmc_discinfo.last_possible_lba + 1; //0; + ti->last_recorded = ti->next_writable; + ti->free_blocks = 0; + + return 0; +} + + +int +udf_opendisc(const char *device, int open_flags) +{ + /* set global variable to the passed name */ + dev_name = strdup(device); + + /* open device */ + if (open_flags & O_RDONLY) { + dev_fd_rdonly = 1; + if ((dev_fd = open(dev_name, O_RDONLY, 0)) == -1) { + warn("device/image not found"); + return EXIT_FAILURE; + } + } else { + dev_fd_rdonly = 0; + if ((dev_fd = open(dev_name, O_RDWR, 0)) == -1) { + /* check if we need to create a file */ + dev_fd = open(dev_name, O_RDONLY, 0); + if (dev_fd > 0) { + warn("device is there but can't be opened for " + "read/write"); + return EXIT_FAILURE; + } + if ((open_flags & O_CREAT) == 0) { + warnx("device/image not found"); + return EXIT_FAILURE; + } + /* need to create a file */ + dev_fd = open(dev_name, O_RDWR | O_CREAT | O_TRUNC, 0666); + if (dev_fd == -1) { + warn("can't create image file"); + return EXIT_FAILURE; + } + } + } + + /* stat the device/image */ + if (fstat(dev_fd, &dev_fd_stat) != 0) { + warn("can't stat the disc image"); + return EXIT_FAILURE; + } + + /* sanity check and resizing of file */ + if (S_ISREG(dev_fd_stat.st_mode)) { + if (emul_size == 0) + emul_size = dev_fd_stat.st_size; + /* sanitise arguments */ + emul_sectorsize &= ~511; + if (emul_size & (emul_sectorsize-1)) { + warnx("size of file is not a multiple of sector size, " + "shrinking"); + emul_size -= emul_size & (emul_sectorsize-1); + } + + /* grow the image */ + if (ftruncate(dev_fd, emul_size)) { + warn("can't resize file"); + return EXIT_FAILURE; + } + /* restat the device/image */ + if (fstat(dev_fd, &dev_fd_stat) != 0) { + warn("can't re-stat the disc image"); + return EXIT_FAILURE; + } + } else { + if (!S_ISCHR(dev_fd_stat.st_mode)) { + warnx("%s is not a raw device", dev_name); + return EXIT_FAILURE; + } + } + + /* just in case something went wrong, synchronise the drive's cache */ + udf_synchronise_caches(); + if (udf_update_discinfo()) { + warnx("update discinfo failed"); + return EXIT_FAILURE; + } + + /* honour minimum sector size of the device */ + if (mmc_discinfo.sector_size > context.sector_size) + context.sector_size = mmc_discinfo.sector_size; + + if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) + udf_init_writequeue(UDF_WRITE_SEQUENTIAL); + else { + udf_init_writequeue(UDF_WRITE_PACKET); + } + return 0; +} + + +void +udf_closedisc(void) +{ + if (!write_queue_suspend) { + udf_writeout_writequeue(true); + assert(write_queuelen == 0); + } + + udf_synchronise_caches(); + if (dev_fd) + close(dev_fd); +} + +/* --------------------------------------------------------------------- */ + +static int +udf_setup_writeparams(void) +{ +#if !HAVE_NBTOOL_CONFIG_H + struct mmc_writeparams mmc_writeparams; + int error; + + if (mmc_discinfo.mmc_class == MMC_CLASS_DISC) + return 0; + + if (S_ISREG(dev_fd_stat.st_mode)) + return 0; + + /* + * only CD burning normally needs setting up, but other disc types + * might need other settings to be made. The MMC framework will set up + * the necessary recording parameters according to the disc + * characteristics read in. Modifications can be made in the discinfo + * structure passed to change the nature of the disc. + */ + memset(&mmc_writeparams, 0, sizeof(struct mmc_writeparams)); + mmc_writeparams.mmc_class = mmc_discinfo.mmc_class; + mmc_writeparams.mmc_cur = mmc_discinfo.mmc_cur; + + /* + * UDF dictates first track to determine track mode for the whole + * disc. [UDF 1.50/6.10.1.1, UDF 1.50/6.10.2.1] + * To prevent problems with a `reserved' track in front we start with + * the 2nd track and if that is not valid, go for the 1st. + */ + mmc_writeparams.tracknr = 2; + mmc_writeparams.data_mode = MMC_DATAMODE_DEFAULT; /* XA disc */ + mmc_writeparams.track_mode = MMC_TRACKMODE_DEFAULT; /* data */ + + error = ioctl(dev_fd, MMCSETUPWRITEPARAMS, &mmc_writeparams); + if (error) { + mmc_writeparams.tracknr = 1; + error = ioctl(dev_fd, MMCSETUPWRITEPARAMS, &mmc_writeparams); + } + return error; +#else + return 0; +#endif +} + + +/* + * On sequential recordable media, we might need to close the last session to + * be able to write new anchors/new fs. + */ +static int +udf_open_new_session(void) +{ +#if !HAVE_NBTOOL_CONFIG_H + struct mmc_trackinfo ti; + struct mmc_op op; + int tracknr, error; + + /* if the drive is not sequential, we're done */ + if ((mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) == 0) + return 0; + + /* close the last session if its still open */ + if (mmc_discinfo.last_session_state == MMC_STATE_INCOMPLETE) { + /* + * Leave the disc alone if force format is not set, it will + * error out later + */ + if (!context.create_new_session) + return 0; + +// printf("Closing last open session if present\n"); + /* close all associated tracks */ + tracknr = mmc_discinfo.first_track_last_session; + while (tracknr <= mmc_discinfo.last_track_last_session) { + ti.tracknr = tracknr; + error = udf_update_trackinfo(&ti); + if (error) + return error; +// printf("\tClosing open track %d\n", tracknr); + memset(&op, 0, sizeof(op)); + op.operation = MMC_OP_CLOSETRACK; + op.mmc_profile = mmc_discinfo.mmc_profile; + op.tracknr = tracknr; + error = ioctl(dev_fd, MMCOP, &op); + if (error) + return error; + tracknr ++; + } +// printf("Closing session\n"); + memset(&op, 0, sizeof(op)); + op.operation = MMC_OP_CLOSESESSION; + op.mmc_profile = mmc_discinfo.mmc_profile; + op.sessionnr = mmc_discinfo.num_sessions; + error = ioctl(dev_fd, MMCOP, &op); + if (error) + return error; + + /* update discinfo since it changed by the operations */ + error = udf_update_discinfo(); + if (error) + return error; + } +#endif + return 0; +} + + +/* bit paranoid but tracks may need repair before they can be written to */ +static void +udf_repair_tracks(void) +{ +#if !HAVE_NBTOOL_CONFIG_H + struct mmc_trackinfo ti; + struct mmc_op op; + int tracknr, error; + + tracknr = mmc_discinfo.first_track_last_session; + while (tracknr <= mmc_discinfo.last_track_last_session) { + ti.tracknr = tracknr; + error = udf_update_trackinfo(&ti); + if (error) { + warnx("error updating track information for track %d", + tracknr); + /* resume */ + tracknr++; + continue; + } + + if (ti.flags & MMC_TRACKINFO_DAMAGED) { + /* + * Need to repair last track before anything can be done. + * this is an optional command, so ignore its error but report + * warning. + */ + memset(&op, 0, sizeof(op)); + op.operation = MMC_OP_REPAIRTRACK; + op.mmc_profile = mmc_discinfo.mmc_profile; + op.tracknr = ti.tracknr; + error = ioctl(dev_fd, MMCOP, &op); + + if (error) + warnx("drive notifies it can't explicitly repair " + "damaged track, but it might autorepair\n"); + } + tracknr++; + } + /* tracks (if any) might not be damaged now, operations are ok now */ +#endif +} + + +int +udf_prepare_disc(void) +{ +#if !HAVE_NBTOOL_CONFIG_H + int error; + + /* setup write parameters from discinfo */ + error = udf_setup_writeparams(); + if (error) + return error; + + udf_repair_tracks(); + + /* open new session if needed */ + return udf_open_new_session(); +#endif + return 0; +} + + +/* --------------------------------------------------------------------- */ + +/* + * write queue implementation + */ + +void +udf_suspend_writing(void) +{ + write_queue_suspend = 1; +} + + +void +udf_allow_writing(void) +{ + write_queue_suspend = 0; +} + + +static void +udf_init_writequeue(int write_strategy) +{ + context.write_strategy = write_strategy; + write_queue_suspend = 0; + + /* setup sector writeout queue's */ + TAILQ_INIT(&write_queue); + write_queuelen = 0; +} + + +int +udf_write_sector(void *sector, uint64_t location) +{ + struct wrpacket *packet, *found_packet; + uint64_t rel_loc; + uint64_t blockingnr = layout.blockingnr; + int error; + + assert(!dev_fd_rdonly); + assert(blockingnr >= 1); + assert(blockingnr <= 64); + + /* + * We have a write strategy but in practice packet writing is + * preferable for all media types. + */ + +again: + /* search location */ + found_packet = NULL; + TAILQ_FOREACH_REVERSE(packet, &write_queue, wrpacket_list, next) { + if (packet->start_sectornr <= location) { + found_packet = packet; + break; + } + } + + /* are we in a current packet? */ + if (found_packet) { + uint64_t base = found_packet->start_sectornr; + if ((location >= base) && (location -base < blockingnr)) { + /* fill in existing packet */ + rel_loc = location - base; + memcpy(found_packet->packet_data + + rel_loc * context.sector_size, + sector, context.sector_size); + found_packet->present |= ((uint64_t) 1 << rel_loc); + return 0; + } + } + + if ((write_queuelen > UDF_MAX_QUEUELEN) && !write_queue_suspend) { + /* we purge the queue and reset found_packet! */ + error = udf_writeout_writequeue(false); + if (error) + return error; + goto again; + } + + /* create new packet */ + packet = calloc(1, sizeof(struct wrpacket)); + if (packet == NULL) + return errno; + packet->packet_data = calloc(1, context.sector_size * blockingnr); + if (packet->packet_data == NULL) { + free(packet); + return errno; + } + packet->start_sectornr = + UDF_ROUNDDOWN(location, blockingnr) + wrtrack_skew; + rel_loc = location - packet->start_sectornr; + + memcpy(packet->packet_data + + rel_loc * context.sector_size, + sector, context.sector_size); + packet->present = ((uint64_t) 1 << rel_loc); + + if (found_packet) { + TAILQ_INSERT_AFTER(&write_queue, found_packet, packet, next); + } else { + TAILQ_INSERT_HEAD(&write_queue, packet, next); + } + write_queuelen++; + + return 0; +} + + +int +udf_read_sector(void *sector, uint64_t location) +{ + struct wrpacket *packet, *found_packet; + ssize_t ret; + uint64_t rpos, rel_loc; + uint64_t blockingnr = layout.blockingnr; + + rpos = (uint64_t) location * context.sector_size; + + /* search location */ + found_packet = NULL; + TAILQ_FOREACH_REVERSE(packet, &write_queue, wrpacket_list, next) { + if (packet->start_sectornr <= location) { + found_packet = packet; + break; + } + } + + /* are we in a current packet? */ + if (found_packet) { + uint64_t base = found_packet->start_sectornr; + if ((location >= base) && (location -base < blockingnr)) { + /* fill in existing packet */ + rel_loc = location - base; + if (found_packet->present & ((uint64_t) 1 << rel_loc)) { + memcpy(sector, found_packet->packet_data + + rel_loc * context.sector_size, + context.sector_size); + } else { + ret = pread(dev_fd, sector, context.sector_size, rpos); + if (ret == -1) + return errno; + if (ret < (int) context.sector_size) + return EIO; + memcpy(found_packet->packet_data + + rel_loc * context.sector_size, + sector, context.sector_size); + found_packet->present |= ((uint64_t) 1 << rel_loc); + return 0; + } + } + } + /* don't create a packet just for we read something */ + ret = pread(dev_fd, sector, context.sector_size, rpos); + if (ret == -1) + return errno; + if (ret < (int) context.sector_size) + return EIO; + return 0; +} + + +/* + * Now all write requests are queued in the TAILQ, write them out to the + * disc/file image. Special care needs to be taken for devices that are only + * strict overwritable i.e. only in packet size chunks + * + * XXX support for growing vnd? + */ + +static int +udf_writeout_writequeue(bool complete) +{ + struct wrpacket *packet, *next_packet; + int blockingnr = layout.blockingnr; + int linesize, offset, ret; + uint8_t *linebuf; + uint64_t present, all_present = -1; + uint64_t rpos, wpos; + static int t = 0; + + if (write_queuelen == 0) + return 0; + + if (blockingnr < 64) + all_present = ((uint64_t) 1 << blockingnr) -1; + linesize = blockingnr * context.sector_size; + linebuf = calloc(1, linesize); + assert(linebuf); + + /* fill in blanks if needed */ + if (complete && (context.write_strategy != UDF_WRITE_SEQUENTIAL)) { + TAILQ_FOREACH(packet, &write_queue, next) { + present = packet->present; + if (present != all_present) { + printf("%c", "\\|/-"[t++ % 4]); fflush(stdout);fflush(stderr); +//printf("%16lu : readin %08lx\n", packet->start_sectornr, packet->present ^ all_present); + rpos = (uint64_t) packet->start_sectornr * context.sector_size; + ret = pread(dev_fd, linebuf, linesize, rpos); + if (ret == -1) { + printf("\b"); + warn("error reading in blanks, " + "could indicate bad disc"); + printf(" "); + } + for (int i = 0; i < blockingnr; i++) { +//printf("present %08lx, testing bit %08lx, value %08lx\n", present, ((uint64_t) 1 << i), (present & ((uint64_t) 1 << i))); + if ((present & ((uint64_t) 1 << i)) > 0) + continue; +//printf("NOT PRESENT\n"); + offset = i * context.sector_size; + memcpy(packet->packet_data + offset, + linebuf + offset, + context.sector_size); + packet->present |= ((uint64_t) 1<present == all_present); + } + } + + /* writeout */ + TAILQ_FOREACH(packet, &write_queue, next) { + if (complete || (packet->present == all_present)) { + printf("%c", "\\|/-"[t++ % 4]); fflush(stdout);fflush(stderr); +//printf("write %lu + %d\n", packet->start_sectornr, linesize / context.sector_size); + wpos = (uint64_t) packet->start_sectornr * context.sector_size; + ret = pwrite(dev_fd, packet->packet_data, linesize, wpos); + printf("\b"); + if (ret == -1) + warn("error writing packet, " + "could indicate bad disc"); + } + } +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + /* removing completed packets */ + TAILQ_FOREACH_SAFE(packet, &write_queue, next, next_packet) { + if (complete || (packet->present == all_present)) { + TAILQ_REMOVE(&write_queue, packet, next); + free(packet->packet_data); + free(packet); + write_queuelen--; + } + } + if (complete) { + assert(TAILQ_EMPTY(&write_queue)); + write_queuelen = 0; + } + + free(linebuf); + return 0; +} + + +/* --------------------------------------------------------------------- */ + +/* simplified version of kernel routine */ +int +udf_translate_vtop(uint32_t lb_num, uint16_t vpart, + uint32_t *lb_numres, uint32_t *extres) +{ + struct part_desc *pdesc; + struct spare_map_entry *sme; + struct short_ad *short_ad; + struct extfile_entry *efe; + uint32_t ext, len, lb_rel, lb_packet, vat_off; + uint32_t start_lb, lb_offset, end_lb_offset; + uint32_t udf_rw32_lbmap; + uint32_t flags; + uint8_t *vat_pos, *data_pos; + int dscr_size, l_ea, l_ad, icbflags, addr_type; + int rel, part; + + if (vpart > UDF_VTOP_RAWPART) + return EINVAL; + + ext = INT_MAX; +translate_again: + part = context.vtop[vpart]; + pdesc = context.partitions[part]; + + switch (context.vtop_tp[vpart]) { + case UDF_VTOP_TYPE_RAW : + /* 1:1 to the end of the device */ + *lb_numres = lb_num; + *extres = MIN(ext, INT_MAX); + return 0; + case UDF_VTOP_TYPE_PHYS : + /* transform into its disc logical block */ + if (lb_num > udf_rw32(pdesc->part_len)) + return EINVAL; + *lb_numres = lb_num + udf_rw32(pdesc->start_loc); + + /* extent from here to the end of the partition */ + *extres = MIN(ext, udf_rw32(pdesc->part_len) - lb_num); + if (*extres == 0) + return EINVAL; + return 0; + case UDF_VTOP_TYPE_VIRT : + /* only maps one logical block, lookup in VAT */ + if (lb_num * 4 >= context.vat_size) + return EINVAL; + vat_off = context.vat_start + lb_num * 4; + vat_pos = context.vat_contents + vat_off; + udf_rw32_lbmap = *((uint32_t *) vat_pos); + + if (vat_off >= context.vat_size) /* XXX > or >= ? */ + return EINVAL; + lb_num = udf_rw32(udf_rw32_lbmap); + + /* transform into its disc logical block */ + if (lb_num > udf_rw32(pdesc->part_len)) + return EINVAL; + *lb_numres = lb_num + udf_rw32(pdesc->start_loc); + + /* just one logical block */ + *extres = 1; + return 0; + case UDF_VTOP_TYPE_SPAREABLE : + /* check if the packet containing the lb_num is remapped */ + lb_packet = lb_num / layout.spareable_blockingnr; + lb_rel = lb_num % layout.spareable_blockingnr; + + for (rel = 0; rel < udf_rw16(context.sparing_table->rt_l); rel++) { + sme = &context.sparing_table->entries[rel]; + if (lb_packet == udf_rw32(sme->org)) { + /* NOTE maps to absolute disc logical block! */ + *lb_numres = udf_rw32(sme->map) + lb_rel; + *extres = layout.spareable_blockingnr - lb_rel; + return 0; + } + } + + /* transform into its disc logical block */ + if (lb_num > udf_rw32(pdesc->part_len)) + return EINVAL; + *lb_numres = lb_num + udf_rw32(pdesc->start_loc); + + /* rest of block */ + *extres = MIN(ext, layout.spareable_blockingnr - lb_rel); + return 0; + case UDF_VTOP_TYPE_META : + /* we have to look into the file's allocation descriptors */ + + /* get first overlapping extent */ + efe = context.meta_file; + dscr_size = sizeof(struct extfile_entry) - 1; + l_ea = udf_rw32(efe->l_ea); + l_ad = udf_rw32(efe->l_ad); + + icbflags = udf_rw16(efe->icbtag.flags); + addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; + if (addr_type != UDF_ICB_SHORT_ALLOC) { + warnx("specification violation: metafile not using" + "short allocs"); + return EINVAL; + } + + data_pos = (uint8_t *) context.meta_file + dscr_size + l_ea; + short_ad = (struct short_ad *) data_pos; + lb_offset = 0; + while (l_ad > 0) { + len = udf_rw32(short_ad->len); + start_lb = udf_rw32(short_ad->lb_num); + flags = UDF_EXT_FLAGS(len); + len = UDF_EXT_LEN(len); + if (flags == UDF_EXT_REDIRECT) { + warnx("implementation limit: no support for " + "extent redirection in metadata file"); + return EINVAL; + } + end_lb_offset = lb_offset + len / context.sector_size; + /* overlap? */ + if (end_lb_offset > lb_num) + break; + short_ad++; + lb_offset = end_lb_offset; + l_ad -= sizeof(struct short_ad); + } + if (l_ad <= 0) { + warnx("looking up outside metadata partition!"); + return EINVAL; + } + lb_num = start_lb + (lb_num - lb_offset); + vpart = part; + ext = end_lb_offset - lb_num; + /* + * vpart and lb_num are updated, translate again since we + * might be mapped on spareable media + */ + goto translate_again; + default: + printf("UDF vtop translation scheme %d unimplemented yet\n", + context.vtop_tp[vpart]); + } + + return EINVAL; +} + +/* --------------------------------------------------------------------- */ + +int +udf_read_phys(void *blob, uint32_t location, uint32_t sects) +{ + uint32_t phys, cnt; + uint8_t *bpos; + int error; + + for (cnt = 0; cnt < sects; cnt++) { + bpos = (uint8_t *) blob; + bpos += context.sector_size * cnt; + + phys = location + cnt; + error = udf_read_sector(bpos, phys); + if (error) + return error; + } + return 0; +} + + +int +udf_write_phys(void *blob, uint32_t location, uint32_t sects) +{ + uint32_t phys, cnt; + uint8_t *bpos; + int error; + + for (cnt = 0; cnt < sects; cnt++) { + bpos = (uint8_t *) blob; + bpos += context.sector_size * cnt; + + phys = location + cnt; + error = udf_write_sector(bpos, phys); + if (error) + return error; + } + return 0; +} + + +int +udf_read_virt(void *blob, uint32_t location, uint16_t vpart, + uint32_t sectors) +{ + uint32_t phys, ext; + uint8_t *data; + int error; + + /* determine physical location */ + data = (uint8_t *) blob; + while (sectors) { + if (udf_translate_vtop(location, vpart, &phys, &ext)) { + // warnx("internal error: bad translation"); + return EINVAL; + } + ext = MIN(sectors, ext); + error = udf_read_phys(data, phys, ext); + if (error) + return error; + location += ext; + data += ext * context.sector_size; + sectors -= ext; + } + return 0; +} + + +int +udf_write_virt(void *blob, uint32_t location, uint16_t vpart, + uint32_t sectors) +{ + uint32_t phys, ext, alloc_pos; + uint8_t *data; + int error; + + /* determine physical location */ + if (context.vtop_tp[vpart] == UDF_VTOP_TYPE_VIRT) { + assert(sectors == 1); + alloc_pos = context.alloc_pos[context.data_part]; + udf_vat_update(location, alloc_pos); + udf_translate_vtop(alloc_pos, context.vtop[vpart], &phys, &ext); + context.alloc_pos[context.data_part]++; + return udf_write_phys(blob, phys, sectors); + } + + data = (uint8_t *) blob; + while (sectors) { + if (udf_translate_vtop(location, vpart, &phys, &ext)) { + warnx("internal error: bad translation"); + return EINVAL; + } + ext = MIN(sectors, ext); + error = udf_write_phys(data, phys, ext); + if (error) + return error; + location += ext; + data += ext * context.sector_size; + sectors -= ext; + } + return 0; +} + + +int +udf_read_dscr_phys(uint32_t sector, union dscrptr **dstp) +{ + union dscrptr *dst, *new_dst; + uint8_t *pos; + uint32_t sectors, dscrlen, sector_size; + int error; + + sector_size = context.sector_size; + + *dstp = dst = NULL; + dscrlen = sector_size; + + /* read initial piece */ + dst = malloc(sector_size); + assert(dst); + error = udf_read_sector(dst, sector); +// if (error) +// warn("read error"); + + if (!error) { + /* check if its an empty block */ + if (is_zero(dst, sector_size)) { + /* return no error but with no dscrptr */ + /* dispose first block */ + free(dst); + return 0; + } + /* check if its a valid tag */ + error = udf_check_tag(dst); + if (error) { + free(dst); + return 0; + } + /* calculate descriptor size */ + dscrlen = udf_tagsize(dst, sector_size); + } + + if (!error && (dscrlen > sector_size)) { + /* read the rest of descriptor */ + + new_dst = realloc(dst, dscrlen); + if (new_dst == NULL) { + free(dst); + return ENOMEM; + } + dst = new_dst; + + sectors = dscrlen / sector_size; + pos = (uint8_t *) dst + sector_size; + error = udf_read_phys(pos, sector + 1, sectors-1); + if (error) + warnx("read error"); + } + if (!error) + error = udf_check_tag_payload(dst, dscrlen); + if (error && dst) { + free(dst); + dst = NULL; + } + *dstp = dst; + + return error; +} + + +int +udf_write_dscr_phys(union dscrptr *dscr, uint32_t location, + uint32_t sectors) +{ + dscr->tag.tag_loc = udf_rw32(location); + (void) udf_validate_tag_and_crc_sums(dscr); + + assert(sectors == udf_tagsize(dscr, context.sector_size) / context.sector_size); + return udf_write_phys(dscr, location, sectors); +} + + +int +udf_read_dscr_virt(uint32_t sector, uint16_t vpart, union dscrptr **dstp) +{ + union dscrptr *dst, *new_dst; + uint8_t *pos; + uint32_t sectors, dscrlen, sector_size; + int error; + + sector_size = context.sector_size; + + *dstp = dst = NULL; + dscrlen = sector_size; + + /* read initial piece */ + dst = calloc(1, sector_size); + assert(dst); + error = udf_read_virt(dst, sector, vpart, 1); + if (error) + return error; + + if (!error) { + /* check if its a valid tag */ + error = udf_check_tag(dst); + if (error) { + /* check if its an empty block */ + if (is_zero(dst, sector_size)) { + /* return no error but with no dscrptr */ + /* dispose first block */ + free(dst); + return 0; + } + } + /* calculate descriptor size */ + dscrlen = udf_tagsize(dst, sector_size); + } + + if (!error && (dscrlen > sector_size)) { + /* read the rest of descriptor */ + + new_dst = realloc(dst, dscrlen); + if (new_dst == NULL) { + free(dst); + return ENOMEM; + } + dst = new_dst; + + sectors = dscrlen / sector_size; + pos = (uint8_t *) dst + sector_size; + error = udf_read_virt(pos, sector + 1, vpart, sectors-1); + if (error) + warn("read error"); + } + if (!error) + error = udf_check_tag_payload(dst, dscrlen); + if (error && dst) { + free(dst); + dst = NULL; + } + *dstp = dst; + + return error; +} + + +int +udf_write_dscr_virt(union dscrptr *dscr, uint32_t location, uint16_t vpart, + uint32_t sectors) +{ + struct file_entry *fe; + struct extfile_entry *efe; + struct extattrhdr_desc *extattrhdr; + + extattrhdr = NULL; + if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { + fe = (struct file_entry *) dscr; + if (udf_rw32(fe->l_ea) > 0) + extattrhdr = (struct extattrhdr_desc *) fe->data; + } + if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) { + efe = (struct extfile_entry *) dscr; + if (udf_rw32(efe->l_ea) > 0) + extattrhdr = (struct extattrhdr_desc *) efe->data; + } + if (extattrhdr) { + extattrhdr->tag.tag_loc = udf_rw32(location); + udf_validate_tag_and_crc_sums((union dscrptr *) extattrhdr); + } + + dscr->tag.tag_loc = udf_rw32(location); + udf_validate_tag_and_crc_sums(dscr); + + assert(sectors >= (udf_tagsize(dscr, context.sector_size) / context.sector_size)); + return udf_write_virt(dscr, location, vpart, sectors); +} + + +int +is_zero(void *blob, int size) { + uint8_t *p = blob; + for (int i = 0; i < size; i++, p++) + if (*p) + return 0; + return 1; +} + +/* --------------------------------------------------------------------- */ + +static void +udf_partition_alloc(int nblk, int vpart, struct long_ad *pos) +{ + memset(pos, 0, sizeof(*pos)); + pos->len = udf_rw32(nblk * context.sector_size); + pos->loc.lb_num = udf_rw32(context.alloc_pos[vpart]); + pos->loc.part_num = udf_rw16(vpart); + + udf_mark_allocated(context.alloc_pos[vpart], vpart, nblk); + context.alloc_pos[vpart] += nblk; +} + + +void +udf_metadata_alloc(int nblk, struct long_ad *pos) +{ + udf_partition_alloc(nblk, context.metadata_part, pos); +} + + +void +udf_data_alloc(int nblk, struct long_ad *pos) +{ + udf_partition_alloc(nblk, context.data_part, pos); +} + + +void +udf_fids_alloc(int nblk, struct long_ad *pos) +{ + udf_partition_alloc(nblk, context.fids_part, pos); +} + + +/* --------------------------------------------------------------------- */ + +/* + * udf_derive_format derives the format_flags from the disc's mmc_discinfo. + * The resulting flags uniquely define a disc format. Note there are at least + * 7 distinct format types defined in UDF. + */ + +#define UDF_VERSION(a) \ + (((a) == 0x102) || ((a) == 0x150) || ((a) == 0x200) || \ + ((a) == 0x201) || ((a) == 0x250) || ((a) == 0x260)) + +int +udf_derive_format(int req_enable, int req_disable) +{ + int format_flags; + int media_accesstype; + + /* disc writability, formatted, appendable */ + if ((mmc_discinfo.mmc_cur & MMC_CAP_RECORDABLE) == 0) { + warnx("can't newfs readonly device"); + return EROFS; + } + if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) { + /* sequentials need sessions appended */ + if (mmc_discinfo.disc_state == MMC_STATE_CLOSED) { + warnx("can't append session to a closed disc"); + return EROFS; + } + if ((mmc_discinfo.disc_state != MMC_STATE_EMPTY) && + !context.create_new_session) { + warnx("disc not empty! Use -F to force " + "initialisation"); + return EROFS; + } + } else { + /* check if disc (being) formatted or has been started on */ + if (mmc_discinfo.disc_state == MMC_STATE_EMPTY) { + warnx("disc is not formatted"); + return EROFS; + } + } + + /* determine UDF format */ + format_flags = 0; + if (mmc_discinfo.mmc_cur & MMC_CAP_REWRITABLE) { + /* all rewritable media */ + format_flags |= FORMAT_REWRITABLE; + if (context.min_udf >= 0x0250) { + /* standard dictates meta as default */ + format_flags |= FORMAT_META; + } + + if ((mmc_discinfo.mmc_cur & MMC_CAP_HW_DEFECTFREE) == 0) { + /* spareables for defect management */ + if (context.min_udf >= 0x150) + format_flags |= FORMAT_SPAREABLE; + } + } else { + /* all once recordable media */ + format_flags |= FORMAT_WRITEONCE; + if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) { + format_flags |= FORMAT_SEQUENTIAL; + + if (mmc_discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE) { + /* logical overwritable */ + format_flags |= FORMAT_LOW; + } else { + /* have to use VAT for overwriting */ + format_flags |= FORMAT_VAT; + } + } else { + /* rare WORM devices, but BluRay has one, strat4096 */ + format_flags |= FORMAT_WORM; + } + } + + /* enable/disable requests */ + if (req_disable & FORMAT_META) { + format_flags &= ~(FORMAT_META | FORMAT_LOW); + req_disable &= ~FORMAT_META; + } + if ((format_flags & FORMAT_VAT) & UDF_512_TRACK) + format_flags |= FORMAT_TRACK512; + + if (req_enable & FORMAT_READONLY) { + format_flags |= FORMAT_READONLY; + } + + /* determine partition/media access type */ + media_accesstype = UDF_ACCESSTYPE_NOT_SPECIFIED; + if (mmc_discinfo.mmc_cur & MMC_CAP_REWRITABLE) { + media_accesstype = UDF_ACCESSTYPE_OVERWRITABLE; + if (mmc_discinfo.mmc_cur & MMC_CAP_ERASABLE) + media_accesstype = UDF_ACCESSTYPE_REWRITEABLE; + } else { + /* all once recordable media */ + media_accesstype = UDF_ACCESSTYPE_WRITE_ONCE; + } + if (mmc_discinfo.mmc_cur & MMC_CAP_PSEUDOOVERWRITE) + media_accesstype = UDF_ACCESSTYPE_PSEUDO_OVERWITE; + + /* patch up media accesstype */ + if (req_enable & FORMAT_READONLY) { + /* better now */ + media_accesstype = UDF_ACCESSTYPE_READ_ONLY; + } + + /* adjust minimum version limits */ + if (format_flags & FORMAT_VAT) + context.min_udf = MAX(context.min_udf, 0x0150); + if (format_flags & FORMAT_SPAREABLE) + context.min_udf = MAX(context.min_udf, 0x0150); + if (format_flags & FORMAT_META) + context.min_udf = MAX(context.min_udf, 0x0250); + if (format_flags & FORMAT_LOW) + context.min_udf = MAX(context.min_udf, 0x0260); + + /* adjust maximum version limits not to tease or break things */ + if (!(format_flags & (FORMAT_META | FORMAT_LOW | FORMAT_VAT)) && + (context.max_udf > 0x200)) + context.max_udf = 0x201; + + if ((format_flags & (FORMAT_VAT | FORMAT_SPAREABLE)) == 0) + if (context.max_udf <= 0x150) + context.min_udf = 0x102; + + /* limit Ecma 167 descriptor if possible/needed */ + context.dscrver = 3; + if ((context.min_udf < 0x200) || (context.max_udf < 0x200)) { + context.dscrver = 2; + context.max_udf = 0x150; /* last version < 0x200 */ + } + + /* is it possible ? */ + if (context.min_udf > context.max_udf) { + warnx("initialisation prohibited by specified maximum " + "UDF version 0x%04x. Minimum version required 0x%04x", + context.max_udf, context.min_udf); + return EPERM; + } + + if (!UDF_VERSION(context.min_udf) || !UDF_VERSION(context.max_udf)) { + warnx("internal error, invalid min/max udf versionsi in %s", + __func__); + return EPERM; + } + context.format_flags = format_flags; + context.media_accesstype = media_accesstype; + + return 0; +} + +#undef UDF_VERSION + + +/* --------------------------------------------------------------------- */ + +int +udf_proces_names(void) +{ + struct timeval time_of_day; + uint32_t primary_nr; + uint64_t volset_nr; + + if (context.logvol_name == NULL) + context.logvol_name = strdup("anonymous"); + if (context.primary_name == NULL) { + if (mmc_discinfo.disc_flags & MMC_DFLAGS_DISCIDVALID) { + primary_nr = mmc_discinfo.disc_id; + } else { + primary_nr = (uint32_t) random(); + } + context.primary_name = calloc(32, 1); + sprintf(context.primary_name, "%08lx", primary_nr); + } + if (context.volset_name == NULL) { + if (mmc_discinfo.disc_flags & MMC_DFLAGS_BARCODEVALID) { + volset_nr = mmc_discinfo.disc_barcode; + } else { + (void)gettimeofday(&time_of_day, NULL); + volset_nr = (uint64_t) random(); + volset_nr |= ((uint64_t) time_of_day.tv_sec) << 32; + } + context.volset_name = calloc(128,1); + sprintf(context.volset_name, "%016llx", volset_nr); + } + if (context.fileset_name == NULL) + context.fileset_name = strdup("anonymous"); + + /* check passed/created identifiers */ + if (strlen(context.logvol_name) > 128) { + warnx("logical volume name too long"); + return EINVAL; + } + if (strlen(context.primary_name) > 32) { + warnx("primary volume name too long"); + return EINVAL; + } + if (strlen(context.volset_name) > 128) { + warnx("volume set name too long"); + return EINVAL; + } + if (strlen(context.fileset_name) > 32) { + warnx("fileset name too long"); + return EINVAL; + } + + /* signal all OK */ + return 0; +} + +/* --------------------------------------------------------------------- */ + +int +udf_write_iso9660_vrs(void) +{ + struct vrs_desc *iso9660_vrs_desc; + uint32_t pos; + int error, cnt, dpos; + + /* create ISO/Ecma-167 identification descriptors */ + if ((iso9660_vrs_desc = calloc(1, context.sector_size)) == NULL) + return ENOMEM; + + /* + * All UDF formats should have their ISO/Ecma-167 descriptors written + * except when not possible due to track reservation in the case of + * VAT + */ + if ((context.format_flags & FORMAT_TRACK512) == 0) { + dpos = (2048 + context.sector_size - 1) / context.sector_size; + + /* wipe at least 6 times 2048 byte `sectors' */ + for (cnt = 0; cnt < 6 *dpos; cnt++) { + pos = layout.iso9660_vrs + cnt; + if ((error = udf_write_sector(iso9660_vrs_desc, pos))) { + free(iso9660_vrs_desc); + return error; + } + } + + /* common VRS fields in all written out ISO descriptors */ + iso9660_vrs_desc->struct_type = 0; + iso9660_vrs_desc->version = 1; + pos = layout.iso9660_vrs; + + /* BEA01, NSR[23], TEA01 */ + memcpy(iso9660_vrs_desc->identifier, "BEA01", 5); + if ((error = udf_write_sector(iso9660_vrs_desc, pos))) { + free(iso9660_vrs_desc); + return error; + } + pos += dpos; + + if (context.dscrver == 2) + memcpy(iso9660_vrs_desc->identifier, "NSR02", 5); + else + memcpy(iso9660_vrs_desc->identifier, "NSR03", 5); + ; + if ((error = udf_write_sector(iso9660_vrs_desc, pos))) { + free(iso9660_vrs_desc); + return error; + } + pos += dpos; + + memcpy(iso9660_vrs_desc->identifier, "TEA01", 5); + if ((error = udf_write_sector(iso9660_vrs_desc, pos))) { + free(iso9660_vrs_desc); + return error; + } + } + + free(iso9660_vrs_desc); + /* return success */ + return 0; +} + + +/* --------------------------------------------------------------------- */ + +int +udf_get_blockingnr(struct mmc_trackinfo *ti) +{ + int blockingnr; + + /* determine blockingnr */ + blockingnr = ti->packet_size; + if (blockingnr <= 1) { + /* paranoia on blockingnr */ + switch (mmc_discinfo.mmc_profile) { + case 0x01 : /* DISC */ + blockingnr = 64; + break; + case 0x08 : /* CDROM */ + case 0x09 : /* CD-R */ + case 0x0a : /* CD-RW */ + blockingnr = 32; /* UDF requirement */ + break; + case 0x10 : /* DVDROM */ + case 0x11 : /* DVD-R (DL) */ + case 0x12 : /* DVD-RAM */ + case 0x1b : /* DVD+R */ + case 0x2b : /* DVD+R Dual layer */ + case 0x13 : /* DVD-RW restricted overwrite */ + case 0x14 : /* DVD-RW sequential */ + case 0x1a : /* DVD+RW */ + blockingnr = 16; /* SCSI definition */ + break; + case 0x40 : /* BDROM */ + case 0x41 : /* BD-R Sequential recording (SRM) */ + case 0x42 : /* BD-R Random recording (RRM) */ + case 0x43 : /* BD-RE */ + case 0x51 : /* HD DVD-R */ + case 0x52 : /* HD DVD-RW */ + blockingnr = 32; /* SCSI definition */ + break; + default: + break; + } + } + return blockingnr; +} + + +int +udf_spareable_blocks(void) +{ + if (mmc_discinfo.mmc_class == MMC_CLASS_CD) { + /* not too much for CD-RW, still 20MiB */ + return 32; + } else { + /* take a value for DVD*RW mainly, BD is `defect free' */ + return 512; + } +} + + +int +udf_spareable_blockingnr(void) +{ + struct mmc_trackinfo ti; + int spareable_blockingnr; + int error; + + /* determine span/size */ + ti.tracknr = mmc_discinfo.first_track_last_session; + error = udf_update_trackinfo(&ti); + spareable_blockingnr = udf_get_blockingnr(&ti); + if (error) + spareable_blockingnr = 32; + + /* + * Note that for (bug) compatibility with version UDF 2.00 + * (fixed in 2.01 and higher) the blocking size needs to be 32 + * sectors otherwise the drive's blockingnr. + */ + if (context.min_udf <= 0x200) + spareable_blockingnr = 32; + return spareable_blockingnr; +} + + +/* + * Main function that creates and writes out disc contents based on the + * format_flags's that uniquely define the type of disc to create. + */ + +int +udf_do_newfs_prefix(void) +{ + union dscrptr *zero_dscr; + union dscrptr *dscr; + struct mmc_trackinfo ti; + uint32_t blockingnr; + uint32_t cnt, loc, len; + int sectcopy; + int error, integrity_type; + int data_part, metadata_part; + int format_flags; + + /* init */ + format_flags = context.format_flags; + + /* determine span/size */ + ti.tracknr = mmc_discinfo.first_track_last_session; + error = udf_update_trackinfo(&ti); + if (error) + return error; + + if (mmc_discinfo.sector_size > context.sector_size) { + warnx("impossible to format: " + "sector size %d too small for media sector size %d", + context.sector_size, mmc_discinfo.sector_size); + return EIO; + } + + /* determine blockingnr */ + blockingnr = udf_get_blockingnr(&ti); + if (blockingnr <= 0) { + warnx("can't fixup blockingnumber for device " + "type %d", mmc_discinfo.mmc_profile); + warnx("device is not returning valid blocking" + " number and media type is unknown"); + return EINVAL; + } + + wrtrack_skew = 0; + if (mmc_discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) + wrtrack_skew = ti.next_writable % blockingnr; + + /* get layout */ + error = udf_calculate_disc_layout(context.min_udf, + ti.track_start, mmc_discinfo.last_possible_lba, + context.sector_size, blockingnr); + + /* cache partition for we need it often */ + data_part = context.data_part; + metadata_part = context.metadata_part; + + /* Create sparing table descriptor if applicable */ + if (format_flags & FORMAT_SPAREABLE) { + if ((error = udf_create_sparing_tabled())) + return error; + + if (context.check_surface) { + if ((error = udf_surface_check())) + return error; + } + } + + /* Create a generic terminator descriptor (later reused) */ + terminator_dscr = calloc(1, context.sector_size); + if (terminator_dscr == NULL) + return ENOMEM; + udf_create_terminator(terminator_dscr, 0); + + /* + * Create the two Volume Descriptor Sets (VDS) each containing the + * following descriptors : primary volume, partition space, + * unallocated space, logical volume, implementation use and the + * terminator + */ + + /* start of volume recognition sequence building */ + context.vds_seq = 0; + + /* Create primary volume descriptor */ + if ((error = udf_create_primaryd())) + return error; + + /* Create partition descriptor */ + if ((error = udf_create_partitiond(context.data_part))) + return error; + + /* Create unallocated space descriptor */ + if ((error = udf_create_unalloc_spaced())) + return error; + + /* Create logical volume descriptor */ + if ((error = udf_create_logical_dscr())) + return error; + + /* Create implementation use descriptor */ + /* TODO input of fields 1,2,3 and passing them */ + if ((error = udf_create_impvold(NULL, NULL, NULL))) + return error; + + /* Create anchors */ + for (cnt = 0; cnt < 3; cnt++) { + if ((error = udf_create_anchor(cnt))) { + return error; + } + } + + /* + * Write out what we've created so far. + * + * Start with wipeout of VRS1 upto start of partition. This allows + * formatting for sequentials with the track reservation and it + * cleans old rubbish on rewritables. For sequentials without the + * track reservation all is wiped from track start. + */ + if ((zero_dscr = calloc(1, context.sector_size)) == NULL) + return ENOMEM; + + loc = (format_flags & FORMAT_TRACK512) ? layout.vds1 : ti.track_start; + for (; loc < layout.part_start_lba; loc++) { + if ((error = udf_write_sector(zero_dscr, loc))) { + free(zero_dscr); + return error; + } + } + free(zero_dscr); + + /* writeout iso9660 vrs */ + if ((error = udf_write_iso9660_vrs())) + return error; + + /* Writeout anchors */ + for (cnt = 0; cnt < 3; cnt++) { + dscr = (union dscrptr *) context.anchors[cnt]; + loc = layout.anchors[cnt]; + if ((error = udf_write_dscr_phys(dscr, loc, 1))) { + err(1, "ERR!"); + return error; + } + + /* sequential media has only one anchor */ + if (format_flags & FORMAT_SEQUENTIAL) + break; + } + + /* write out main and secondary VRS */ + for (sectcopy = 1; sectcopy <= 2; sectcopy++) { + loc = (sectcopy == 1) ? layout.vds1 : layout.vds2; + + /* primary volume descriptor */ + dscr = (union dscrptr *) context.primary_vol; + error = udf_write_dscr_phys(dscr, loc, 1); + if (error) + return error; + loc++; + + /* partition descriptor(s) */ + for (cnt = 0; cnt < UDF_PARTITIONS; cnt++) { + dscr = (union dscrptr *) context.partitions[cnt]; + if (dscr) { + error = udf_write_dscr_phys(dscr, loc, 1); + if (error) + return error; + loc++; + } + } + + /* unallocated space descriptor */ + dscr = (union dscrptr *) context.unallocated; + error = udf_write_dscr_phys(dscr, loc, 1); + if (error) + return error; + loc++; + + /* logical volume descriptor */ + dscr = (union dscrptr *) context.logical_vol; + error = udf_write_dscr_phys(dscr, loc, 1); + if (error) + return error; + loc++; + + /* implementation use descriptor */ + dscr = (union dscrptr *) context.implementation; + error = udf_write_dscr_phys(dscr, loc, 1); + if (error) + return error; + loc++; + + /* terminator descriptor */ + error = udf_write_dscr_phys(terminator_dscr, loc, 1); + if (error) + return error; + loc++; + } + + /* writeout the two spareable table descriptors (if needed) */ + if (format_flags & FORMAT_SPAREABLE) { + for (sectcopy = 1; sectcopy <= 2; sectcopy++) { + loc = (sectcopy == 1) ? layout.spt_1 : layout.spt_2; + dscr = (union dscrptr *) context.sparing_table; + len = udf_tagsize(dscr, context.sector_size) / + context.sector_size; + + /* writeout */ + error = udf_write_dscr_phys(dscr, loc, len); + if (error) + return error; + } + } + + /* + * Create unallocated space bitmap descriptor. Sequential recorded + * media report their own free/used space; no free/used space tables + * should be recorded for these. + */ + if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) { + error = udf_create_space_bitmap( + layout.alloc_bitmap_dscr_size, + layout.part_size_lba, + &context.part_unalloc_bits[data_part]); + if (error) + return error; + /* TODO: freed space bitmap if applicable */ + + /* mark space allocated for the unallocated space bitmap */ + udf_mark_allocated(layout.unalloc_space, data_part, + layout.alloc_bitmap_dscr_size); + } + + /* + * Create metadata partition file entries and allocate and init their + * space and free space maps. + */ + if (format_flags & FORMAT_META) { + error = udf_create_meta_files(); + if (error) + return error; + + /* mark space allocated for meta partition and its bitmap */ + udf_mark_allocated(layout.meta_file, data_part, 1); + udf_mark_allocated(layout.meta_mirror, data_part, 1); + udf_mark_allocated(layout.meta_part_start_lba, data_part, + layout.meta_part_size_lba); + + if (context.meta_bitmap) { + /* metadata bitmap creation and accounting */ + error = udf_create_space_bitmap( + layout.meta_bitmap_dscr_size, + layout.meta_part_size_lba, + &context.part_unalloc_bits[metadata_part]); + if (error) + return error; + + udf_mark_allocated(layout.meta_bitmap, data_part, 1); + /* mark space allocated for the unallocated space bitmap */ + udf_mark_allocated(layout.meta_bitmap_space, + data_part, + layout.meta_bitmap_dscr_size); + } + } + + /* create logical volume integrity descriptor */ + context.num_files = 0; + context.num_directories = 0; + integrity_type = UDF_INTEGRITY_OPEN; + if ((error = udf_create_lvintd(integrity_type))) + return error; + + /* writeout initial open integrity sequence + terminator */ + loc = layout.lvis; + dscr = (union dscrptr *) context.logvol_integrity; + error = udf_write_dscr_phys(dscr, loc, 1); + if (error) + return error; + loc++; + error = udf_write_dscr_phys(terminator_dscr, loc, 1); + if (error) + return error; + + /* create VAT if needed */ + if (format_flags & FORMAT_VAT) { + context.vat_allocated = context.sector_size; + context.vat_contents = malloc(context.vat_allocated); + assert(context.vat_contents); + + udf_prepend_VAT_file(); + } + + /* create FSD and writeout */ + if ((error = udf_create_fsd())) + return error; + udf_mark_allocated(layout.fsd, metadata_part, 1); + + dscr = (union dscrptr *) context.fileset_desc; + error = udf_write_dscr_virt(dscr, layout.fsd, metadata_part, 1); + + return error; +} + + +/* specific routine for newfs to create empty rootdirectory */ +int +udf_do_rootdir(void) +{ + union dscrptr *root_dscr; + int error; + + /* create root directory and write out */ + assert(context.unique_id == 0x10); + context.unique_id = 0; + if ((error = udf_create_new_rootdir(&root_dscr))) + return error; + udf_mark_allocated(layout.rootdir, context.metadata_part, 1); + + error = udf_write_dscr_virt(root_dscr, + layout.rootdir, context.metadata_part, 1); + + free(root_dscr); + + return error; +} + + +int +udf_do_newfs_postfix(void) +{ + union dscrptr *dscr; + uint32_t loc, len; + int data_part, metadata_part; + int format_flags = context.format_flags; + int error; + + /* cache partition for we need it often */ + data_part = context.data_part; + metadata_part = context.metadata_part; + + if ((format_flags & FORMAT_SEQUENTIAL) == 0) { + /* update lvint and mark it closed */ + udf_update_lvintd(UDF_INTEGRITY_CLOSED); + + /* overwrite initial terminator */ + loc = layout.lvis+1; + dscr = (union dscrptr *) context.logvol_integrity; + error = udf_write_dscr_phys(dscr, loc, 1); + if (error) + return error; + loc++; + + /* mark end of integrity descriptor sequence again */ + error = udf_write_dscr_phys(terminator_dscr, loc, 1); + if (error) + return error; + } + + /* write out unallocated space bitmap on non sequential media */ + if ((format_flags & (FORMAT_SEQUENTIAL | FORMAT_READONLY)) == 0) { + /* writeout unallocated space bitmap */ + loc = layout.unalloc_space; + dscr = (union dscrptr *) (context.part_unalloc_bits[data_part]); + len = layout.alloc_bitmap_dscr_size; + error = udf_write_dscr_virt(dscr, loc, data_part, len); + if (error) + return error; + } + + if (format_flags & FORMAT_META) { + loc = layout.meta_file; + dscr = (union dscrptr *) context.meta_file; + error = udf_write_dscr_virt(dscr, loc, data_part, 1); + if (error) + return error; + + loc = layout.meta_mirror; + dscr = (union dscrptr *) context.meta_mirror; + error = udf_write_dscr_virt(dscr, loc, data_part, 1); + if (error) + return error; + + if (context.meta_bitmap) { + loc = layout.meta_bitmap; + dscr = (union dscrptr *) context.meta_bitmap; + error = udf_write_dscr_virt(dscr, loc, data_part, 1); + if (error) + return error; + + /* writeout unallocated space bitmap */ + loc = layout.meta_bitmap_space; + dscr = (union dscrptr *) + (context.part_unalloc_bits[metadata_part]); + len = layout.meta_bitmap_dscr_size; + error = udf_write_dscr_virt(dscr, loc, data_part, len); + if (error) + return error; + } + } + + /* create and writeout a VAT */ + if (format_flags & FORMAT_VAT) + udf_writeout_VAT(); + + /* done */ + return 0; +} diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf_core.h b/vendor/bdj-sdk/host/src/makefs_termux/udf_core.h new file mode 100644 index 0000000..2f8f39e --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf_core.h @@ -0,0 +1,414 @@ +/* $NetBSD: udf_core.h,v 1.2 2022/04/09 09:58:11 riastradh Exp $ */ + +/* + * Copyright (c) 2006, 2008, 2021, 2022 Reinoud Zandijk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 AUTHOR ``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 AUTHOR 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. + * + */ + +#ifndef _FS_UDF_CORE_H_ +#define _FS_UDF_CORE_H_ + + +#if 0 +# ifndef DEBUG +# define DEBUG +# endif +#endif + + +#include +#include +#include "udf_bswap.h" +#include "udf_osta.h" + +#if !HAVE_NBTOOL_CONFIG_H +#define _EXPOSE_MMC +#include "cdio.h" +#include "ecma167-udf.h" +#else +#include "udf/cdio_mmc_structs.h" +#include "../../sys/fs/udf/ecma167-udf.h" +#endif + + +/* format flags indicating properties of disc to create */ +#define FORMAT_WRITEONCE 0x00001 +#define FORMAT_SEQUENTIAL 0x00002 +#define FORMAT_REWRITABLE 0x00004 +#define FORMAT_SPAREABLE 0x00008 +#define FORMAT_META 0x00010 +#define FORMAT_LOW 0x00020 +#define FORMAT_VAT 0x00040 +#define FORMAT_WORM 0x00080 +#define FORMAT_TRACK512 0x00100 +#define FORMAT_INVALID 0x00200 +#define FORMAT_READONLY 0x00400 +#define FORMAT_FLAGBITS \ + "\10\1WRITEONCE\2SEQUENTIAL\3REWRITABLE\4SPAREABLE\5META\6LOW" \ + "\7VAT\10WORM\11TRACK512\12INVALID\13READONLY" + +/* writing strategy */ +#define UDF_WRITE_SEQUENTIAL 1 +#define UDF_WRITE_PACKET 2 /* with fill-in if needed */ +#define UDF_MAX_QUEUELEN 400 /* must hold all pre-partition space */ + +/* structure space */ +#define UDF_ANCHORS 4 /* 256, 512, N-256, N */ +#define UDF_PARTITIONS 4 /* overkill */ +#define UDF_PMAPS 4 /* overkill */ + +/* misc constants */ +#define UDF_MAX_NAMELEN 255 /* as per SPEC */ +#define UDF_LVDINT_SEGMENTS 10 /* big overkill */ +#define UDF_LVINT_LOSSAGE 4 /* lose 2 openings */ +#define UDF_MAX_ALLOC_EXTENTS 5 /* overkill */ + +/* translation constants */ +#define UDF_VTOP_RAWPART UDF_PMAPS /* [0..UDF_PMAPS> are normal */ + +/* virtual to physical mapping types */ +#define UDF_VTOP_TYPE_RAW 0 +#define UDF_VTOP_TYPE_UNKNOWN 0 +#define UDF_VTOP_TYPE_PHYS 1 +#define UDF_VTOP_TYPE_VIRT 2 +#define UDF_VTOP_TYPE_SPAREABLE 3 +#define UDF_VTOP_TYPE_META 4 + +#define UDF_TRANS_ZERO ((uint64_t) -1) +#define UDF_TRANS_UNMAPPED ((uint64_t) -2) +#define UDF_TRANS_INTERN ((uint64_t) -3) +#define UDF_MAX_SECTOR ((uint64_t) -10) /* high water mark */ + +/* handys */ +#define UDF_ROUNDUP(val, gran) \ + ((uint64_t) (gran) * (((uint64_t)(val) + (gran)-1) / (gran))) + +#define UDF_ROUNDDOWN(val, gran) \ + ((uint64_t) (gran) * (((uint64_t)(val)) / (gran))) + +/* default */ +#define UDF_META_PERC 20 /* picked */ + + +/* disc offsets for various structures and their sizes */ +struct udf_disclayout { + uint32_t wrtrack_skew; + + uint32_t iso9660_vrs; + uint32_t anchors[UDF_ANCHORS]; + uint32_t vds1_size, vds2_size, vds1, vds2; + uint32_t lvis_size, lvis; + + uint32_t first_lba, last_lba; + uint32_t blockingnr, align_blockingnr, spareable_blockingnr; + uint32_t meta_blockingnr, meta_alignment; + + /* spareables */ + uint32_t spareable_blocks; + uint32_t spareable_area, spareable_area_size; + uint32_t sparing_table_dscr_lbas; + uint32_t spt_1, spt_2; + + /* metadata partition */ + uint32_t meta_file, meta_mirror, meta_bitmap; + uint32_t meta_part_start_lba, meta_part_size_lba; + uint32_t meta_bitmap_dscr_size; + uint32_t meta_bitmap_space; + + /* main partition */ + uint32_t part_start_lba, part_size_lba; + uint32_t alloc_bitmap_dscr_size; + uint32_t unalloc_space, freed_space; + + /* main structures */ + uint32_t fsd, rootdir, vat; + +}; + + +struct udf_lvintq { + uint32_t start; + uint32_t end; + uint32_t pos; + uint32_t wpos; +}; + + +/* all info about discs and descriptors building */ +struct udf_create_context { + /* descriptors */ + int dscrver; /* 2 or 3 */ + int min_udf; /* hex */ + int max_udf; /* hex */ + int serialnum; /* format serialno */ + + int gmtoff; /* in minutes */ + int meta_perc; /* format paramter */ + int check_surface; /* for spareables */ + int create_new_session; /* for non empty recordables */ + + uint32_t sector_size; + int media_accesstype; + int format_flags; + int write_strategy; + + /* identification */ + char *logvol_name; + char *primary_name; + char *volset_name; + char *fileset_name; + + char const *app_name; + char const *impl_name; + int app_version_main; + int app_version_sub; + + /* building */ + int vds_seq; /* for building functions */ + + /* constructed structures */ + struct anchor_vdp *anchors[UDF_ANCHORS]; /* anchors to VDS */ + struct pri_vol_desc *primary_vol; /* identification */ + struct logvol_desc *logical_vol; /* main mapping v->p */ + struct unalloc_sp_desc *unallocated; /* free UDF space */ + struct impvol_desc *implementation; /* likely reduntant */ + struct logvol_int_desc *logvol_integrity; /* current integrity */ + struct part_desc *partitions[UDF_PARTITIONS]; /* partitions */ + + struct space_bitmap_desc*part_unalloc_bits[UDF_PARTITIONS]; + struct space_bitmap_desc*part_freed_bits [UDF_PARTITIONS]; + + /* track information */ + struct mmc_trackinfo first_ti_partition; + struct mmc_trackinfo first_ti; + struct mmc_trackinfo last_ti; + + /* current partitions for allocation */ + int data_part; + int metadata_part; + int fids_part; + + /* current highest file unique_id */ + uint64_t unique_id; + + /* block numbers as offset in partition, building ONLY! */ + uint32_t alloc_pos[UDF_PARTITIONS]; + + /* derived; points *into* other structures */ + struct udf_logvol_info *logvol_info; /* inside integrity */ + + /* fileset and root directories */ + struct fileset_desc *fileset_desc; /* normally one */ + + /* logical to physical translations */ + int vtop[UDF_PMAPS+1]; /* vpartnr trans */ + int vtop_tp[UDF_PMAPS+1]; /* type of trans */ + + /* spareable */ + struct udf_sparing_table*sparing_table; /* replacements */ + + /* VAT file */ + uint32_t vat_size; /* length */ + uint32_t vat_allocated; /* allocated length */ + uint32_t vat_start; /* offset 1st entry */ + uint8_t *vat_contents; /* the VAT */ + + /* meta data partition */ + struct extfile_entry *meta_file; + struct extfile_entry *meta_mirror; + struct extfile_entry *meta_bitmap; + + /* lvint */ + uint32_t num_files; + uint32_t num_directories; + uint32_t part_size[UDF_PARTITIONS]; + uint32_t part_free[UDF_PARTITIONS]; + + /* fsck */ + union dscrptr *vds_buf; + int vds_size; + struct udf_lvintq lvint_trace[UDF_LVDINT_SEGMENTS]; /* fsck */ + uint8_t *lvint_history; /* fsck */ + int lvint_history_len; /* fsck */ + int lvint_history_wpos; /* fsck */ + int lvint_history_ondisc_len; /* fsck */ +}; + + +/* global variables describing disc and format */ +extern struct udf_create_context context; +extern struct udf_disclayout layout; +extern struct mmc_discinfo mmc_discinfo; /* device: disc info */ + +extern int dev_fd_rdonly; /* device: open readonly! */ +extern int dev_fd; /* device: file descriptor */ +extern struct stat dev_fd_stat; /* device: last stat info */ +extern char *dev_name; /* device: name */ +extern int emul_mmc_profile; /* for files */ +extern int emul_packetsize; /* for discs and files */ +extern int emul_sectorsize; /* for files */ +extern off_t emul_size; /* for files */ +extern uint32_t wrtrack_skew; /* offset for write sector0 */ + + +/* prototypes */ +extern void udf_init_create_context(void); +extern int a_udf_version(const char *s, const char *id_type); +extern int is_zero(void *blob, int size); +extern uint32_t udf_bytes_to_sectors(uint64_t bytes); + +extern int udf_calculate_disc_layout(int min_udf, + uint32_t first_lba, uint32_t last_lba, + uint32_t sector_size, uint32_t blockingnr); +extern void udf_dump_layout(void); +extern int udf_spareable_blocks(void); +extern int udf_spareable_blockingnr(void); + +extern void udf_osta_charset(struct charspec *charspec); +extern void udf_encode_osta_id(char *osta_id, uint16_t len, char *text); +extern void udf_to_unix_name(char *result, int result_len, char *id, int len, + struct charspec *chsp); +extern void unix_to_udf_name(char *result, uint8_t *result_len, + char const *name, int name_len, struct charspec *chsp); + +extern void udf_set_regid(struct regid *regid, char const *name); +extern void udf_add_domain_regid(struct regid *regid); +extern void udf_add_udf_regid(struct regid *regid); +extern void udf_add_impl_regid(struct regid *regid); +extern void udf_add_app_regid(struct regid *regid); + +extern int udf_check_tag(void *blob); +extern int udf_check_tag_payload(void *blob, uint32_t max_length); +extern int udf_check_tag_and_location(void *blob, uint32_t location); +extern int udf_validate_tag_sum(union dscrptr *dscr); +extern int udf_validate_tag_and_crc_sums(union dscrptr *dscr); + +extern void udf_set_timestamp_now(struct timestamp *timestamp); +extern void udf_timestamp_to_timespec(struct timestamp *timestamp, + struct timespec *timespec); +extern void udf_timespec_to_timestamp(struct timespec *timespec, + struct timestamp *timestamp); + +extern void udf_inittag(struct desc_tag *tag, int tagid, uint32_t loc); +extern int udf_create_anchor(int num); + +extern void udf_create_terminator(union dscrptr *dscr, uint32_t loc); +extern int udf_create_primaryd(void); +extern int udf_create_partitiond(int part_num); +extern int udf_create_unalloc_spaced(void); +extern int udf_create_sparing_tabled(void); +extern int udf_create_space_bitmap(uint32_t dscr_size, uint32_t part_size_lba, + struct space_bitmap_desc **sbdp); +extern int udf_create_logical_dscr(void); +extern int udf_create_impvold(char *field1, char *field2, char *field3); +extern int udf_create_fsd(void); +extern int udf_create_lvintd(int type); +extern void udf_update_lvintd(int type); +extern uint16_t udf_find_raw_phys(uint16_t raw_phys_part); + +extern int udf_register_bad_block(uint32_t location); +extern void udf_mark_allocated(uint32_t start_lb, int partnr, uint32_t blocks); + +extern int udf_impl_extattr_check(struct impl_extattr_entry *implext); +extern void udf_calc_impl_extattr_checksum(struct impl_extattr_entry *implext); +extern int udf_extattr_search_intern(union dscrptr *dscr, + uint32_t sattr, char const *sattrname, + uint32_t *offsetp, uint32_t *lengthp); + +extern int udf_create_new_fe(struct file_entry **fep, int file_type, + struct stat *st); +extern int udf_create_new_efe(struct extfile_entry **efep, int file_type, + struct stat *st); + +extern int udf_encode_symlink(uint8_t **pathbufp, uint32_t *pathlenp, char *target); + +extern void udf_advance_uniqueid(void); +extern uint32_t udf_tagsize(union dscrptr *dscr, uint32_t lb_size); +extern int udf_fidsize(struct fileid_desc *fid); +extern void udf_create_fid(uint32_t diroff, struct fileid_desc *fid, + char *name, int namelen, struct long_ad *ref); +extern int udf_create_parentfid(struct fileid_desc *fid, struct long_ad *parent); + +extern int udf_create_meta_files(void); +extern int udf_create_new_rootdir(union dscrptr **dscr); + +extern int udf_create_VAT(union dscrptr **vat_dscr, struct long_ad *vatdata_loc); +extern void udf_prepend_VAT_file(void); +extern void udf_vat_update(uint32_t virt, uint32_t phys); +extern int udf_append_VAT_file(void); +extern int udf_writeout_VAT(void); + +extern int udf_opendisc(const char *device, int open_flags); +extern void udf_closedisc(void); +extern int udf_prepare_disc(void); +extern int udf_update_discinfo(void); +extern int udf_update_trackinfo(struct mmc_trackinfo *ti); +extern int udf_get_blockingnr(struct mmc_trackinfo *ti); +extern void udf_synchronise_caches(void); +extern void udf_suspend_writing(void); +extern void udf_allow_writing(void); + +extern int udf_write_iso9660_vrs(void); + +/* address translation */ +extern int udf_translate_vtop(uint32_t lb_num, uint16_t vpart, + uint32_t *lb_numres, uint32_t *extres); + +/* basic sector read/write with caching */ +extern int udf_read_sector(void *sector, uint64_t location); +extern int udf_write_sector(void *sector, uint64_t location); + +/* extent reading and writing */ +extern int udf_read_phys(void *blob, uint32_t location, uint32_t sects); +extern int udf_write_phys(void *blob, uint32_t location, uint32_t sects); + +extern int udf_read_virt(void *blob, uint32_t location, uint16_t vpart, + uint32_t sectors); +extern int udf_write_virt(void *blob, uint32_t location, uint16_t vpart, + uint32_t sectors); + +extern int udf_read_dscr_phys(uint32_t sector, union dscrptr **dstp); +extern int udf_write_dscr_phys(union dscrptr *dscr, uint32_t location, + uint32_t sects); + +extern int udf_read_dscr_virt(uint32_t sector, uint16_t vpart, + union dscrptr **dstp); +extern int udf_write_dscr_virt(union dscrptr *dscr, + uint32_t location, uint16_t vpart, uint32_t sects); + +extern void udf_metadata_alloc(int nblk, struct long_ad *pos); +extern void udf_data_alloc(int nblk, struct long_ad *pos); +extern void udf_fids_alloc(int nblk, struct long_ad *pos); + +extern int udf_derive_format(int req_enable, int req_disable); +extern int udf_proces_names(void); +extern int udf_surface_check(void); + +extern int udf_do_newfs_prefix(void); +extern int udf_do_rootdir(void); +extern int udf_do_newfs_postfix(void); + +extern void udf_dump_discinfo(struct mmc_discinfo *di); + +#endif /* _UDF_CORE_H_ */ diff --git a/vendor/bdj-sdk/host/src/makefs_termux/udf_osta.c b/vendor/bdj-sdk/host/src/makefs_termux/udf_osta.c new file mode 100644 index 0000000..1976389 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/udf_osta.c @@ -0,0 +1,514 @@ +/* $NetBSD: udf_osta.c,v 1.10 2013/08/05 17:02:54 joerg Exp $ */ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif +#include +#include +// __KERNEL_RCSID(0, "$NetBSD: udf_osta.c,v 1.10 2013/08/05 17:02:54 joerg Exp $"); + +/* + * Various routines from the OSTA 2.01 specs. Copyrights are included with + * each code segment. Slight whitespace modifications have been made for + * formatting purposes. Typos/bugs have been fixed. + * + */ + +#include "udf_osta.h" + +#ifndef _KERNEL +#include +#endif + +/*****************************************************************************/ +/*********************************************************************** + * OSTA compliant Unicode compression, uncompression routines. + * Copyright 1995 Micro Design International, Inc. + * Written by Jason M. Rinn. + * Micro Design International gives permission for the free use of the + * following source code. + */ + +/*********************************************************************** + * Takes an OSTA CS0 compressed unicode name, and converts + * it to Unicode. + * The Unicode output will be in the byte order + * that the local compiler uses for 16-bit values. + * NOTE: This routine only performs error checking on the compID. + * It is up to the user to ensure that the unicode buffer is large + * enough, and that the compressed unicode name is correct. + * + * RETURN VALUE + * + * The number of unicode characters which were uncompressed. + * A -1 is returned if the compression ID is invalid. + */ +int +udf_UncompressUnicode( + int numberOfBytes, /* (Input) number of bytes read from media. */ + byte *UDFCompressed, /* (Input) bytes read from media. */ + unicode_t *unicode) /* (Output) uncompressed unicode characters. */ +{ + unsigned int compID; + int returnValue, unicodeIndex, byteIndex; + + /* Use UDFCompressed to store current byte being read. */ + compID = UDFCompressed[0]; + + /* First check for valid compID. */ + if (compID != 8 && compID != 16) { + returnValue = -1; + } else { + unicodeIndex = 0; + byteIndex = 1; + + /* Loop through all the bytes. */ + while (byteIndex < numberOfBytes) { + if (compID == 16) { + /* Move the first byte to the high bits of the + * unicode char. + */ + unicode[unicodeIndex] = + UDFCompressed[byteIndex++] << 8; + } else { + unicode[unicodeIndex] = 0; + } + if (byteIndex < numberOfBytes) { + /*Then the next byte to the low bits. */ + unicode[unicodeIndex] |= + UDFCompressed[byteIndex++]; + } + unicodeIndex++; + } + returnValue = unicodeIndex; + } + return(returnValue); +} + +/*********************************************************************** + * DESCRIPTION: + * Takes a string of unicode wide characters and returns an OSTA CS0 + * compressed unicode string. The unicode MUST be in the byte order of + * the compiler in order to obtain correct results. Returns an error + * if the compression ID is invalid. + * + * NOTE: This routine assumes the implementation already knows, by + * the local environment, how many bits are appropriate and + * therefore does no checking to test if the input characters fit + * into that number of bits or not. + * + * RETURN VALUE + * + * The total number of bytes in the compressed OSTA CS0 string, + * including the compression ID. + * A -1 is returned if the compression ID is invalid. + */ +int +udf_CompressUnicode( + int numberOfChars, /* (Input) number of unicode characters. */ + int compID, /* (Input) compression ID to be used. */ + unicode_t *unicode, /* (Input) unicode characters to compress. */ + byte *UDFCompressed) /* (Output) compressed string, as bytes. */ +{ + int byteIndex, unicodeIndex; + + if (compID != 8 && compID != 16) { + byteIndex = -1; /* Unsupported compression ID ! */ + } else { + /* Place compression code in first byte. */ + UDFCompressed[0] = compID; + + byteIndex = 1; + unicodeIndex = 0; + while (unicodeIndex < numberOfChars) { + if (compID == 16) { + /* First, place the high bits of the char + * into the byte stream. + */ + UDFCompressed[byteIndex++] = + (unicode[unicodeIndex] & 0xFF00) >> 8; + } + /*Then place the low bits into the stream. */ + UDFCompressed[byteIndex++] = + unicode[unicodeIndex] & 0x00FF; + unicodeIndex++; + } + } + return(byteIndex); +} + +/*****************************************************************************/ +/* + * CRC 010041 + */ +static unsigned short crc_table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 +}; + +unsigned short +udf_cksum(unsigned char *s, int n) +{ + unsigned short crc=0; + + while (n-- > 0) + crc = crc_table[(crc>>8 ^ *s++) & 0xff] ^ (crc<<8); + return crc; +} + +/* UNICODE Checksum */ +unsigned short +udf_unicode_cksum(unsigned short *s, int n) +{ + unsigned short crc=0; + + while (n-- > 0) { + /* Take high order byte first--corresponds to a big endian + * byte stream. + */ + crc = crc_table[(crc>>8 ^ (*s>>8)) & 0xff] ^ (crc<<8); + crc = crc_table[(crc>>8 ^ (*s++ & 0xff)) & 0xff] ^ (crc<<8); + } + return crc; +} + + +/* + * Calculates a 16-bit checksum of the Implementation Use + * Extended Attribute header or Application Use Extended Attribute + * header. The fields AttributeType through ImplementationIdentifier + * (or ApplicationIdentifier) inclusively represent the + * data covered by the checksum (48 bytes). + * + */ +uint16_t udf_ea_cksum(uint8_t *data) { + uint16_t checksum = 0; + int count; + + for (count = 0; count < 48; count++) { + checksum += *data++; + } + + return checksum; +} + + +#ifdef MAIN +unsigned char bytes[] = { 0x70, 0x6A, 0x77 }; + +main(void) +{ + unsigned short x; + x = cksum(bytes, sizeof bytes); + printf("checksum: calculated=%4.4x, correct=%4.4x\en", x, 0x3299); + exit(0); +} +#endif + +/*****************************************************************************/ +/* #ifdef NEEDS_ISPRINT */ +/*********************************************************************** + * OSTA UDF compliant file name translation routine for OS/2, + * Windows 95, Windows NT, Macintosh and UNIX. + * Copyright 1995 Micro Design International, Inc. + * Written by Jason M. Rinn. + * Micro Design International gives permission for the free use of the + * following source code. + */ + +/*********************************************************************** + * To use these routines with different operating systems. + * + * OS/2 + * Define OS2 + * Define MAXLEN = 254 + * + * Windows 95 + * Define WIN_95 + * Define MAXLEN = 255 + * + * Windows NT + * Define WIN_NT + * Define MAXLEN = 255 + * + * Macintosh: + * Define MAC. + * Define MAXLEN = 31. + * + * UNIX + * Define UNIX. + * Define MAXLEN as specified by unix version. + */ + +#define ILLEGAL_CHAR_MARK 0x005F +#define CRC_MARK 0x0023 +#define EXT_SIZE 5 +#define PERIOD 0x002E +#define SPACE 0x0020 + +/*** PROTOTYPES ***/ +int IsIllegal(unicode_t ch); + +/* Define a function or macro which determines if a Unicode character is + * printable under your implementation. + */ + + +/* #include */ +static int UnicodeIsPrint(unicode_t ch) { + return (ch >=' ') && (ch != 127); +} + + +int UnicodeLength(unicode_t *string) { + int length; + length = 0; + while (*string++) length++; + + return length; +} + + +#ifdef _KERNEL +static int isprint(int c) { + return (c >= ' ') && (c != 127); +} +#endif + + +/*********************************************************************** + * Translates a long file name to one using a MAXLEN and an illegal + * char set in accord with the OSTA requirements. Assumes the name has + * already been translated to Unicode. + * + * RETURN VALUE + * + * Number of unicode characters in translated name. + */ +int UDFTransName( + unicode_t *newName, /* (Output)Translated name. Must be of length + * MAXLEN */ + unicode_t *udfName, /* (Input) Name from UDF volume.*/ + int udfLen) /* (Input) Length of UDF Name. */ +{ + int Index, newIndex = 0, needsCRC = false; /* index is shadowed */ + int extIndex = 0, newExtIndex = 0, hasExt = false; +#if defined OS2 || defined WIN_95 || defined WIN_NT + int trailIndex = 0; +#endif + unsigned short valueCRC; + unicode_t current; + const char hexChar[] = "0123456789ABCDEF"; + + for (Index = 0; Index < udfLen; Index++) { + current = udfName[Index]; + + if (IsIllegal(current) || !UnicodeIsPrint(current)) { + needsCRC = true; + /* Replace Illegal and non-displayable chars with + * underscore. + */ + current = ILLEGAL_CHAR_MARK; + /* Skip any other illegal or non-displayable + * characters. + */ + while(Index+1 < udfLen && (IsIllegal(udfName[Index+1]) + || !UnicodeIsPrint(udfName[Index+1]))) { + Index++; + } + } + + /* Record position of extension, if one is found. */ + if (current == PERIOD && (udfLen - Index -1) <= EXT_SIZE) { + if (udfLen == Index + 1) { + /* A trailing period is NOT an extension. */ + hasExt = false; + } else { + hasExt = true; + extIndex = Index; + newExtIndex = newIndex; + } + } + +#if defined OS2 || defined WIN_95 || defined WIN_NT + /* Record position of last char which is NOT period or space. */ + else if (current != PERIOD && current != SPACE) { + trailIndex = newIndex; + } +#endif + + if (newIndex < MAXLEN) { + newName[newIndex++] = current; + } else { + needsCRC = true; + } + } + +#if defined OS2 || defined WIN_95 || defined WIN_NT + /* For OS2, 95 & NT, truncate any trailing periods and\or spaces. */ + if (trailIndex != newIndex - 1) { + newIndex = trailIndex + 1; + needsCRC = true; + hasExt = false; /* Trailing period does not make an + * extension. */ + } +#endif + + if (needsCRC) { + unicode_t ext[EXT_SIZE]; + int localExtIndex = 0; + if (hasExt) { + int maxFilenameLen; + /* Translate extension, and store it in ext. */ + for(Index = 0; Index maxFilenameLen) { + newIndex = maxFilenameLen; + } else { + newIndex = newExtIndex; + } + } else if (newIndex > MAXLEN - 5) { + /*If no extension, make sure to leave room for CRC. */ + newIndex = MAXLEN - 5; + } + newName[newIndex++] = CRC_MARK; /* Add mark for CRC. */ + + /*Calculate CRC from original filename from FileIdentifier. */ + valueCRC = udf_unicode_cksum(udfName, udfLen); + /* Convert 16-bits of CRC to hex characters. */ + newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12]; + newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8]; + newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4]; + newName[newIndex++] = hexChar[(valueCRC & 0x000f)]; + + /* Place a translated extension at end, if found. */ + if (hasExt) { + newName[newIndex++] = PERIOD; + for (Index = 0;Index < localExtIndex ;Index++ ) { + newName[newIndex++] = ext[Index]; + } + } + } + return(newIndex); +} + +#if defined OS2 || defined WIN_95 || defined WIN_NT +/*********************************************************************** + * Decides if a Unicode character matches one of a list + * of ASCII characters. + * Used by OS2 version of IsIllegal for readability, since all of the + * illegal characters above 0x0020 are in the ASCII subset of Unicode. + * Works very similarly to the standard C function strchr(). + * + * RETURN VALUE + * + * Non-zero if the Unicode character is in the given ASCII string. + */ +int UnicodeInString( + unsigned char *string, /* (Input) String to search through. */ + unicode_t ch) /* (Input) Unicode char to search for. */ +{ + int found = false; + while (*string != '\0' && found == false) { + /* These types should compare, since both are unsigned + * numbers. */ + if (*string == ch) { + found = true; + } + string++; + } + return(found); +} +#endif /* OS2 */ + +/*********************************************************************** + * Decides whether the given character is illegal for a given OS. + * + * RETURN VALUE + * + * Non-zero if char is illegal. + */ +int IsIllegal(unicode_t ch) +{ +#ifdef MAC + /* Only illegal character on the MAC is the colon. */ + if (ch == 0x003A) { + return(1); + } else { + return(0); + } + +#elif defined UNIX + /* Illegal UNIX characters are NULL and slash. */ + if (ch == 0x0000 || ch == 0x002F) { + return(1); + } else { + return(0); + } + +#elif defined OS2 || defined WIN_95 || defined WIN_NT + /* Illegal char's for OS/2 according to WARP toolkit. */ + if (ch < 0x0020 || UnicodeInString("\\/:*?\"<>|", ch)) { + return(1); + } else { + return(0); + } +#endif +} +/* #endif*/ /* NEEDS_ISPRINT */ + diff --git a/vendor/bdj-sdk/host/src/makefs_termux/util.h b/vendor/bdj-sdk/host/src/makefs_termux/util.h new file mode 100644 index 0000000..992cfdb --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/util.h @@ -0,0 +1,171 @@ +/* $NetBSD: util.h,v 1.69 2016/04/10 19:05:50 roy Exp $ */ + +/*- + * Copyright (c) 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include +#include +//#include +#include + +#ifdef _BSD_TIME_T_ +typedef _BSD_TIME_T_ time_t; +#undef _BSD_TIME_T_ +#endif +#ifdef _BSD_SIZE_T_ +typedef _BSD_SIZE_T_ size_t; +#undef _BSD_SIZE_T_ +#endif + +#if defined(_POSIX_C_SOURCE) +#ifndef __VA_LIST_DECLARED +//typedef __va_list va_list; +#define __VA_LIST_DECLARED +#endif +#endif + +#define PIDLOCK_NONBLOCK 1 +#define PIDLOCK_USEHOSTNAME 2 + +#define PW_POLICY_BYSTRING 0 +#define PW_POLICY_BYPASSWD 1 +#define PW_POLICY_BYGROUP 2 + +__BEGIN_DECLS +struct disklabel; +struct iovec; +struct passwd; +struct termios; +struct utmp; +struct utmpx; +struct winsize; +struct sockaddr; + +char *flags_to_string(unsigned long, const char *); +pid_t forkpty(int *, char *, struct termios *, struct winsize *); +const char *getbootfile(void); +int getbyteorder(void); +off_t getlabeloffset(void); +int getlabelsector(void); +int getlabelusesmbr(void); +int getmaxpartitions(void); +int getrawpartition(void); +const char *getdiskrawname(char *, size_t, const char *); +const char *getdiskcookedname(char *, size_t, const char *); +const char *getfstypename(int); +const char *getfsspecname(char *, size_t, const char *); +struct kinfo_vmentry *kinfo_getvmmap(pid_t, size_t *); +#if 0 +//#ifndef __LIBC12_SOURCE__ +void login(const struct utmp *) __RENAME(__login50); +void loginx(const struct utmpx *) __RENAME(__loginx50); +#endif +int login_tty(int); +int logout(const char *); +int logoutx(const char *, int, int); +void logwtmp(const char *, const char *, const char *); +void logwtmpx(const char *, const char *, const char *, int, int); +int opendisk(const char *, int, char *, size_t, int); +int opendisk1(const char *, int, char *, size_t, int, + int (*)(const char *, int, ...)); +int openpty(int *, int *, char *, struct termios *, + struct winsize *); +#if 0 +//#ifndef __LIBC12_SOURCE__ +time_t parsedate(const char *, const time_t *, const int *) + __RENAME(__parsedate50); +#endif +int pidfile(const char *); +pid_t pidfile_lock(const char *); +pid_t pidfile_read(const char *); +int pidfile_clean(void); +int pidlock(const char *, int, pid_t *, const char *); +int pw_abort(void); +#if 0 +//#ifndef __LIBC12_SOURCE__ +void pw_copy(int, int, struct passwd *, struct passwd *) + __RENAME(__pw_copy50); +int pw_copyx(int, int, struct passwd *, struct passwd *, + char *, size_t) __RENAME(__pw_copyx50); +#endif +void pw_edit(int, const char *); +//__dead void pw_error(const char *, int, int); +void pw_getconf(char *, size_t, const char *, const char *); +#if 0 +//#ifndef __LIBC12_SOURCE__ +void pw_getpwconf(char *, size_t, const struct passwd *, + const char *) __RENAME(__pw_getpwconf50); +#endif +const char *pw_getprefix(void); +void pw_init(void); +int pw_lock(int); +int pw_mkdb(const char *, int); +void pw_prompt(void); +int pw_setprefix(const char *); +int raise_default_signal(int); +int secure_path(const char *); +int snprintb_m(char *, size_t, const char *, uint64_t, size_t); +int snprintb(char *, size_t, const char *, uint64_t); +int sockaddr_snprintf(char *, size_t, const char *, + const struct sockaddr *); +char *strpct(char *, size_t, uintmax_t, uintmax_t, size_t); +char *strspct(char *, size_t, intmax_t, intmax_t, size_t); +int string_to_flags(char **, unsigned long *, unsigned long *); +int ttyaction(const char *, const char *, const char *); +int ttylock(const char *, int, pid_t *); +char *ttymsg(struct iovec *, int, const char *, int); +int ttyunlock(const char *); + +uint16_t disklabel_dkcksum(struct disklabel *); +int disklabel_scan(struct disklabel *, char *, size_t); + +/* Error checked functions */ +void (*esetfunc(void (*)(int, const char *, ...))) + (int, const char *, ...); +size_t estrlcpy(char *, const char *, size_t); +size_t estrlcat(char *, const char *, size_t); +char *estrdup(const char *); +char *estrndup(const char *, size_t); +intmax_t estrtoi(const char *, int, intmax_t, intmax_t); +uintmax_t estrtou(const char *, int, uintmax_t, uintmax_t); +void *ecalloc(size_t, size_t); +void *emalloc(size_t); +void *erealloc(void *, size_t); +void ereallocarr(void *, size_t, size_t); +struct __sFILE *efopen(const char *, const char *); +//int easprintf(char ** __restrict, const char * __restrict, ...) +// __printflike(2, 3); +//int evasprintf(char ** __restrict, const char * __restrict, +// __va_list) __printflike(2, 0); +__END_DECLS + +#endif /* !_UTIL_H_ */ diff --git a/vendor/bdj-sdk/host/src/makefs_termux/v7fs.c b/vendor/bdj-sdk/host/src/makefs_termux/v7fs.c new file mode 100644 index 0000000..7c479a3 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/v7fs.c @@ -0,0 +1,191 @@ +/* $NetBSD: v7fs.c,v 1.8 2013/01/29 15:52:25 christos Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if defined(__RCSID) && !defined(__lint) +__RCSID("$NetBSD: v7fs.c,v 1.8 2013/01/29 15:52:25 christos Exp $"); +#endif /* !__lint */ + +#include +#include +#include +#include +#include +#include + +#include "makefs.h" +#include "v7fs.h" +#include "v7fs_impl.h" +#include "v7fs_makefs.h" +#include "newfs_v7fs.h" + + +#ifndef HAVE_NBTOOL_CONFIG_H +#include "progress.h" +static bool progress_bar_enable; +#endif +int v7fs_newfs_verbose; + +void +v7fs_prep_opts(fsinfo_t *fsopts) +{ + v7fs_opt_t *v7fs_opts = ecalloc(1, sizeof(*v7fs_opts)); + const option_t v7fs_options[] = { + { 'p', "pdp", &v7fs_opts->pdp_endian, OPT_INT32, false, true, + "PDP endian" }, + { 'P', "progress", &v7fs_opts->progress, OPT_INT32, false, true, + "Progress bar" }, + { .name = NULL } + }; + + fsopts->fs_specific = v7fs_opts; + fsopts->fs_options = copy_opts(v7fs_options); +} + +void +v7fs_cleanup_opts(fsinfo_t *fsopts) +{ + free(fsopts->fs_specific); + free(fsopts->fs_options); +} + +int +v7fs_parse_opts(const char *option, fsinfo_t *fsopts) +{ + + return set_option_var(fsopts->fs_options, option, "1", NULL, 0) != -1; +} + +void +v7fs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) +{ + struct v7fs_mount_device v7fs_mount; + int fd, endian, error = 1; + v7fs_opt_t *v7fs_opts = fsopts->fs_specific; + + v7fs_newfs_verbose = debug; +#ifndef HAVE_NBTOOL_CONFIG_H + if ((progress_bar_enable = v7fs_opts->progress)) { + progress_switch(progress_bar_enable); + progress_init(); + progress(&(struct progress_arg){ .cdev = image }); + } +#endif + + /* Determine filesystem image size */ + v7fs_estimate(dir, root, fsopts); + printf("Calculated size of `%s': %lld bytes, %ld inodes\n", + image, (long long)fsopts->size, (long)fsopts->inodes); + + if ((fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { + err(EXIT_FAILURE, "%s", image); + } + if (lseek(fd, fsopts->size - 1, SEEK_SET) == -1) { + goto err_exit; + } + if (write(fd, &fd, 1) != 1) { + goto err_exit; + } + if (lseek(fd, 0, SEEK_SET) == -1) { + goto err_exit; + } + fsopts->fd = fd; + v7fs_mount.device.fd = fd; + +#if !defined BYTE_ORDER +#error +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + if (fsopts->needswap) + endian = BIG_ENDIAN; + else + endian = LITTLE_ENDIAN; +#else + if (fsopts->needswap) + endian = LITTLE_ENDIAN; + else + endian = BIG_ENDIAN; +#endif + if (v7fs_opts->pdp_endian) { + endian = PDP_ENDIAN; + } + + v7fs_mount.endian = endian; + v7fs_mount.sectors = fsopts->size >> V7FS_BSHIFT; + if (v7fs_newfs(&v7fs_mount, fsopts->inodes) != 0) { + goto err_exit; + } + + if (v7fs_populate(dir, root, fsopts, &v7fs_mount) != 0) { + error = 2; /* some files couldn't add */ + goto err_exit; + } + + close(fd); + return; + + err_exit: + close(fd); + err(error, "%s", image); +} + +void +progress(const struct progress_arg *p) +{ +#ifndef HAVE_NBTOOL_CONFIG_H + static struct progress_arg Progress; + static char cdev[32]; + static char label[32]; + + if (!progress_bar_enable) + return; + + if (p) { + Progress = *p; + if (p->cdev) + strcpy(cdev, p->cdev); + if (p->label) + strcpy(label, p->label); + } + + if (!Progress.tick) + return; + if (++Progress.cnt > Progress.tick) { + Progress.cnt = 0; + Progress.total++; + progress_bar(cdev, label, Progress.total, PROGRESS_BAR_GRANULE); + } +#endif +} diff --git a/vendor/bdj-sdk/host/src/makefs_termux/v7fs_makefs.h b/vendor/bdj-sdk/host/src/makefs_termux/v7fs_makefs.h new file mode 100644 index 0000000..1c047ca --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/v7fs_makefs.h @@ -0,0 +1,49 @@ +/* $NetBSD: v7fs_makefs.h,v 1.2 2011/08/10 11:31:49 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by UCHIYAMA Yasushi. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#ifndef _MAKEFS_V7FS_H_ +#define _MAKEFS_V7FS_H_ + +typedef struct { + int pdp_endian; + int progress; + v7fs_daddr_t npuredatablk; /* for progress bar */ +} v7fs_opt_t; + +__BEGIN_DECLS +void v7fs_estimate(const char *, fsnode *, fsinfo_t *); +int v7fs_populate(const char *, fsnode *, fsinfo_t *, + const struct v7fs_mount_device *); +struct progress_arg; +void progress(const struct progress_arg *); +extern int v7fs_newfs_verbose; +__END_DECLS +#endif /*!_MAKEFS_V7FS_H_*/ diff --git a/vendor/bdj-sdk/host/src/makefs_termux/walk.c b/vendor/bdj-sdk/host/src/makefs_termux/walk.c new file mode 100644 index 0000000..08fe6f3 --- /dev/null +++ b/vendor/bdj-sdk/host/src/makefs_termux/walk.c @@ -0,0 +1,765 @@ + +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Luke Mewburn for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if defined(__RCSID) && !defined(__lint) +__RCSID("$NetBSD: walk.c,v 1.28 2013/02/03 06:16:53 christos Exp $"); +#endif /* !__lint */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" + +#include "makefs.h" +#include "mtree.h" +#ifndef ALLPERMS +# define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) +#endif + +u_int +nodetoino(u_int type) +{ + + switch (type) { + case F_BLOCK: + return S_IFBLK; + case F_CHAR: + return S_IFCHR; + case F_DIR: + return S_IFDIR; + case F_FIFO: + return S_IFIFO; + case F_FILE: + return S_IFREG; + case F_LINK: + return S_IFLNK; +#ifdef S_IFSOCK + case F_SOCK: + return S_IFSOCK; +#endif + default: + printf("unknown type %d", type); + abort(); + } + /* NOTREACHED */ +} + +const char * +nodetype(u_int type) +{ + + return (inotype(nodetoino(type))); +} + + +const char * +inotype(u_int type) +{ + + switch (type & S_IFMT) { + case S_IFBLK: + return ("block"); + case S_IFCHR: + return ("char"); + case S_IFDIR: + return ("dir"); + case S_IFIFO: + return ("fifo"); + case S_IFREG: + return ("file"); + case S_IFLNK: + return ("link"); +#ifdef S_IFSOCK + case S_IFSOCK: + return ("socket"); +#endif +#ifdef S_IFDOOR + case S_IFDOOR: + return ("door"); +#endif + default: + return ("unknown"); + } + /* NOTREACHED */ +} + + +#define HAVE_STRUCT_STAT_ST_FLAGS 0 + +static void apply_specdir(const char *, NODE *, fsnode *, int); +static void apply_specentry(const char *, NODE *, fsnode *); +static fsnode *create_fsnode(const char *, const char *, const char *, + struct stat *); +static fsinode *link_check(fsinode *); + + +/* + * walk_dir -- + * build a tree of fsnodes from `root' and `dir', with a parent + * fsnode of `parent' (which may be NULL for the root of the tree). + * append the tree to a fsnode of `join' if it is not NULL. + * each "level" is a directory, with the "." entry guaranteed to be + * at the start of the list, and without ".." entries. + */ +fsnode * +walk_dir(const char *root, const char *dir, fsnode *parent, fsnode *join, + int replace) +{ + fsnode *first, *cur, *prev, *last; + DIR *dirp; + struct dirent *dent; + char path[MAXPATHLEN + 1]; + struct stat stbuf; + char *name, *rp; + int dot, len; + + assert(root != NULL); + assert(dir != NULL); + + len = snprintf(path, sizeof(path), "%s/%s", root, dir); + if (len >= (int)sizeof(path)) + errx(1, "Pathname too long."); + if (debug & DEBUG_WALK_DIR) + printf("walk_dir: %s %p\n", path, parent); + if ((dirp = opendir(path)) == NULL) + err(1, "Can't opendir `%s'", path); + rp = path + strlen(root) + 1; + if (join != NULL) { + first = cur = join; + while (cur->next != NULL) + cur = cur->next; + prev = last = cur; + } else + last = first = prev = NULL; + while ((dent = readdir(dirp)) != NULL) { + name = dent->d_name; + dot = 0; + if (name[0] == '.') + switch (name[1]) { + case '\0': /* "." */ + if (join != NULL) + continue; + dot = 1; + break; + case '.': /* ".." */ + if (name[2] == '\0') + continue; + /* FALLTHROUGH */ + default: + dot = 0; + } + if (debug & DEBUG_WALK_DIR_NODE) + printf("scanning %s/%s/%s\n", root, dir, name); + if (snprintf(path + len, sizeof(path) - len, "/%s", name) >= + (int)sizeof(path) - len) + errx(1, "Pathname too long."); + if (lstat(path, &stbuf) == -1) + err(1, "Can't lstat `%s'", path); +#ifdef S_ISSOCK + if (S_ISSOCK(stbuf.st_mode & S_IFMT)) { + if (debug & DEBUG_WALK_DIR_NODE) + printf(" skipping socket %s\n", path); + continue; + } +#endif + + if (join != NULL) { + cur = join->next; + for (;;) { + if (cur == NULL || strcmp(cur->name, name) == 0) + break; + if (cur == last) { + cur = NULL; + break; + } + cur = cur->next; + } + if (cur != NULL) { + if (S_ISDIR(cur->type) && + S_ISDIR(stbuf.st_mode)) { + if (debug & DEBUG_WALK_DIR_NODE) + printf("merging %s with %p\n", + path, cur->child); + cur->child = walk_dir(root, rp, cur, + cur->child, replace); + continue; + } + if (!replace) + errx(1, "Can't merge %s `%s' with " + "existing %s", + inode_type(stbuf.st_mode), path, + inode_type(cur->type)); + else { + if (debug & DEBUG_WALK_DIR_NODE) + printf("replacing %s %s\n", + inode_type(stbuf.st_mode), + path); + if (cur == join->next) + join->next = cur->next; + else { + fsnode *p; + for (p = join->next; + p->next != cur; p = p->next) + continue; + p->next = cur->next; + } + free(cur); + } + } + } + + cur = create_fsnode(root, dir, name, &stbuf); + cur->parent = parent; + if (dot) { + /* ensure "." is at the start of the list */ + cur->next = first; + first = cur; + if (! prev) + prev = cur; + cur->first = first; + } else { /* not "." */ + if (prev) + prev->next = cur; + prev = cur; + if (!first) + first = cur; + cur->first = first; + if (S_ISDIR(cur->type)) { + cur->child = walk_dir(root, rp, cur, NULL, + replace); + continue; + } + } + if (stbuf.st_nlink > 1) { + fsinode *curino; + + curino = link_check(cur->inode); + if (curino != NULL) { + free(cur->inode); + cur->inode = curino; + cur->inode->nlink++; + if (debug & DEBUG_WALK_DIR_LINKCHECK) + printf("link_check: found [%llu, %llu]\n", + (unsigned long long)curino->st.st_dev, + (unsigned long long)curino->st.st_ino); + } + } + if (S_ISLNK(cur->type)) { + char slink[PATH_MAX+1]; + int llen; + + llen = readlink(path, slink, sizeof(slink) - 1); + if (llen == -1) + err(1, "Readlink `%s'", path); + slink[llen] = '\0'; + cur->symlink = strdup(slink); + } + } + assert(first != NULL); + if (join == NULL) + for (cur = first->next; cur != NULL; cur = cur->next) + cur->first = first; + if (closedir(dirp) == -1) + err(1, "Can't closedir `%s/%s'", root, dir); + return (first); +} + +static fsnode * +create_fsnode(const char *root, const char *path, const char *name, + struct stat *stbuf) +{ + fsnode *cur; + + cur = calloc(1, sizeof(*cur)); + cur->path = strdup(path); + cur->name = strdup(name); + cur->inode = calloc(1, sizeof(*cur->inode)); + cur->root = root; + cur->type = stbuf->st_mode & S_IFMT; + cur->inode->nlink = 1; + cur->inode->st = *stbuf; + return (cur); +} + +/* + * free_fsnodes -- + * Removes node from tree and frees it and all of + * its decendents. + */ +void +free_fsnodes(fsnode *node) +{ + fsnode *cur, *next; + + assert(node != NULL); + + /* for ".", start with actual parent node */ + if (node->first == node) { + assert(node->name[0] == '.' && node->name[1] == '\0'); + if (node->parent) { + assert(node->parent->child == node); + node = node->parent; + } + } + + /* Find ourselves in our sibling list and unlink */ + if (node->first != node) { + for (cur = node->first; cur->next; cur = cur->next) { + if (cur->next == node) { + cur->next = node->next; + node->next = NULL; + break; + } + } + } + + for (cur = node; cur != NULL; cur = next) { + next = cur->next; + if (cur->child) { + cur->child->parent = NULL; + free_fsnodes(cur->child); + } + if (cur->inode->nlink-- == 1) + free(cur->inode); + if (cur->symlink) + free(cur->symlink); + free(cur->path); + free(cur->name); + free(cur); + } +} +#if 0 +/* + * apply_specfile -- + * read in the mtree(8) specfile, and apply it to the tree + * at dir,parent. parameters in parent on equivalent types + * will be changed to those found in specfile, and missing + * entries will be added. + */ +void +apply_specfile(const char *specfile, const char *dir, fsnode *parent, int speconly) +{ + struct timeval start; + FILE *fp; + NODE *root; + + assert(specfile != NULL); + assert(parent != NULL); + + if (debug & DEBUG_APPLY_SPECFILE) + printf("apply_specfile: %s, %s %p\n", specfile, dir, parent); + + /* read in the specfile */ + if ((fp = fopen(specfile, "r")) == NULL) + err(1, "Can't open `%s'", specfile); + TIMER_START(start); + root = spec(fp); + TIMER_RESULTS(start, "spec"); + if (fclose(fp) == EOF) + err(1, "Can't close `%s'", specfile); + + /* perform some sanity checks */ + if (root == NULL) + errx(1, "Specfile `%s' did not contain a tree", specfile); + assert(strcmp(root->name, ".") == 0); + assert(root->type == F_DIR); + + /* merge in the changes */ + apply_specdir(dir, root, parent, speconly); + + free_nodes(root); +} +#endif +static void +apply_specdir(const char *dir, NODE *specnode, fsnode *dirnode, int speconly) +{ + char path[MAXPATHLEN + 1]; + NODE *curnode; + fsnode *curfsnode; + + assert(specnode != NULL); + assert(dirnode != NULL); + + if (debug & DEBUG_APPLY_SPECFILE) + printf("apply_specdir: %s %p %p\n", dir, specnode, dirnode); + + if (specnode->type != F_DIR) + errx(1, "Specfile node `%s/%s' is not a directory", + dir, specnode->name); + if (dirnode->type != S_IFDIR) + errx(1, "Directory node `%s/%s' is not a directory", + dir, dirnode->name); + + apply_specentry(dir, specnode, dirnode); + + /* Remove any filesystem nodes not found in specfile */ + /* XXX inefficient. This is O^2 in each dir and it would + * have been better never to have walked this part of the tree + * to begin with + */ + if (speconly) { + fsnode *next; + assert(dirnode->name[0] == '.' && dirnode->name[1] == '\0'); + for (curfsnode = dirnode->next; curfsnode != NULL; curfsnode = next) { + next = curfsnode->next; + for (curnode = specnode->child; curnode != NULL; + curnode = curnode->next) { + if (strcmp(curnode->name, curfsnode->name) == 0) + break; + } + if (curnode == NULL) { + if (debug & DEBUG_APPLY_SPECONLY) { + printf("apply_specdir: trimming %s/%s %p\n", dir, curfsnode->name, curfsnode); + } + free_fsnodes(curfsnode); + } + } + } + + /* now walk specnode->child matching up with dirnode */ + for (curnode = specnode->child; curnode != NULL; + curnode = curnode->next) { + if (debug & DEBUG_APPLY_SPECENTRY) + printf("apply_specdir: spec %s\n", + curnode->name); + for (curfsnode = dirnode->next; curfsnode != NULL; + curfsnode = curfsnode->next) { +#if 0 /* too verbose for now */ + if (debug & DEBUG_APPLY_SPECENTRY) + printf("apply_specdir: dirent %s\n", + curfsnode->name); +#endif + if (strcmp(curnode->name, curfsnode->name) == 0) + break; + } + if ((size_t)snprintf(path, sizeof(path), "%s/%s", + dir, curnode->name) >= sizeof(path)) + errx(1, "Pathname too long."); + if (curfsnode == NULL) { /* need new entry */ + struct stat stbuf; + + /* + * don't add optional spec entries + * that lack an existing fs entry + */ + if ((curnode->flags & F_OPT) && + lstat(path, &stbuf) == -1) + continue; + + /* check that enough info is provided */ +#define NODETEST(t, m) \ + if (!(t)) \ + errx(1, "`%s': %s not provided", path, m) + NODETEST(curnode->flags & F_TYPE, "type"); + NODETEST(curnode->flags & F_MODE, "mode"); + /* XXX: require F_TIME ? */ + NODETEST(curnode->flags & F_GID || + curnode->flags & F_GNAME, "group"); + NODETEST(curnode->flags & F_UID || + curnode->flags & F_UNAME, "user"); + if (curnode->type == F_BLOCK || curnode->type == F_CHAR) + NODETEST(curnode->flags & F_DEV, + "device number"); +#undef NODETEST +#define HAVE_STRUCT_STAT_ST_MTIMENSEC 0 + if (debug & DEBUG_APPLY_SPECFILE) + printf("apply_specdir: adding %s\n", + curnode->name); + /* build minimal fsnode */ + memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_mode = nodetoino(curnode->type); + stbuf.st_nlink = 1; + stbuf.st_mtime = stbuf.st_atime = + stbuf.st_ctime = start_time.tv_sec; +#if HAVE_STRUCT_STAT_ST_MTIMENSEC + stbuf.st_mtimensec = stbuf.st_atimensec = + stbuf.st_ctimensec = start_time.tv_nsec; +#endif + curfsnode = create_fsnode(".", ".", curnode->name, + &stbuf); + curfsnode->parent = dirnode->parent; + curfsnode->first = dirnode; + curfsnode->next = dirnode->next; + dirnode->next = curfsnode; + if (curfsnode->type == S_IFDIR) { + /* for dirs, make "." entry as well */ + curfsnode->child = create_fsnode(".", ".", ".", + &stbuf); + curfsnode->child->parent = curfsnode; + curfsnode->child->first = curfsnode->child; + } + if (curfsnode->type == S_IFLNK) { + assert(curnode->slink != NULL); + /* for symlinks, copy the target */ + curfsnode->symlink = strdup(curnode->slink); + } + } + apply_specentry(dir, curnode, curfsnode); + if (curnode->type == F_DIR) { + if (curfsnode->type != S_IFDIR) + errx(1, "`%s' is not a directory", path); + assert (curfsnode->child != NULL); + apply_specdir(path, curnode, curfsnode->child, speconly); + } + } +} + +static void +apply_specentry(const char *dir, NODE *specnode, fsnode *dirnode) +{ + + assert(specnode != NULL); + assert(dirnode != NULL); + + if (nodetoino(specnode->type) != dirnode->type) + errx(1, "`%s/%s' type mismatch: specfile %s, tree %s", + dir, specnode->name, inode_type(nodetoino(specnode->type)), + inode_type(dirnode->type)); + + if (debug & DEBUG_APPLY_SPECENTRY) + printf("apply_specentry: %s/%s\n", dir, dirnode->name); + +#define ASEPRINT(t, b, o, n) \ + if (debug & DEBUG_APPLY_SPECENTRY) \ + printf("\t\t\tchanging %s from " b " to " b "\n", \ + t, o, n) + + if (specnode->flags & (F_GID | F_GNAME)) { + ASEPRINT("gid", "%d", + dirnode->inode->st.st_gid, specnode->st_gid); + dirnode->inode->st.st_gid = specnode->st_gid; + } + if (specnode->flags & F_MODE) { + ASEPRINT("mode", "%#o", + dirnode->inode->st.st_mode & ALLPERMS, specnode->st_mode); + dirnode->inode->st.st_mode &= ~ALLPERMS; + dirnode->inode->st.st_mode |= (specnode->st_mode & ALLPERMS); + } + /* XXX: ignoring F_NLINK for now */ + if (specnode->flags & F_SIZE) { + ASEPRINT("size", "%lld", + (long long)dirnode->inode->st.st_size, + (long long)specnode->st_size); + dirnode->inode->st.st_size = specnode->st_size; + } + if (specnode->flags & F_SLINK) { + assert(dirnode->symlink != NULL); + assert(specnode->slink != NULL); + ASEPRINT("symlink", "%s", dirnode->symlink, specnode->slink); + free(dirnode->symlink); + dirnode->symlink = strdup(specnode->slink); + } + if (specnode->flags & F_TIME) { + ASEPRINT("time", "%ld", + (long)dirnode->inode->st.st_mtime, + (long)specnode->st_mtimespec.tv_sec); + dirnode->inode->st.st_mtime = specnode->st_mtimespec.tv_sec; + dirnode->inode->st.st_atime = specnode->st_mtimespec.tv_sec; + dirnode->inode->st.st_ctime = start_time.tv_sec; +#if HAVE_STRUCT_STAT_ST_MTIMENSEC + dirnode->inode->st.st_mtimensec = specnode->st_mtimespec.tv_nsec; + dirnode->inode->st.st_atimensec = specnode->st_mtimespec.tv_nsec; + dirnode->inode->st.st_ctimensec = start_time.tv_nsec; +#endif + } + if (specnode->flags & (F_UID | F_UNAME)) { + ASEPRINT("uid", "%d", + dirnode->inode->st.st_uid, specnode->st_uid); + dirnode->inode->st.st_uid = specnode->st_uid; + } +#if HAVE_STRUCT_STAT_ST_FLAGS + if (specnode->flags & F_FLAGS) { + ASEPRINT("flags", "%#lX", + (unsigned long)dirnode->inode->st.st_flags, + (unsigned long)specnode->st_flags); + dirnode->inode->st.st_flags = specnode->st_flags; + } +#endif + if (specnode->flags & F_DEV) { + ASEPRINT("rdev", "%#llx", + (unsigned long long)dirnode->inode->st.st_rdev, + (unsigned long long)specnode->st_rdev); + dirnode->inode->st.st_rdev = specnode->st_rdev; + } +#undef ASEPRINT + + dirnode->flags |= FSNODE_F_HASSPEC; +} + + +/* + * dump_fsnodes -- + * dump the fsnodes from `cur' + */ +void +dump_fsnodes(fsnode *root) +{ + fsnode *cur; + char path[MAXPATHLEN + 1]; + + printf("dump_fsnodes: %s %p\n", root->path, root); + for (cur = root; cur != NULL; cur = cur->next) { + if (snprintf(path, sizeof(path), "%s/%s", cur->path, + cur->name) >= (int)sizeof(path)) + errx(1, "Pathname too long."); + + if (debug & DEBUG_DUMP_FSNODES_VERBOSE) + printf("cur=%8p parent=%8p first=%8p ", + cur, cur->parent, cur->first); + printf("%7s: %s", inode_type(cur->type), path); + if (S_ISLNK(cur->type)) { + assert(cur->symlink != NULL); + printf(" -> %s", cur->symlink); + } else { + assert (cur->symlink == NULL); + } + if (cur->inode->nlink > 1) + printf(", nlinks=%d", cur->inode->nlink); + putchar('\n'); + + if (cur->child) { + assert (cur->type == S_IFDIR); + dump_fsnodes(cur->child); + } + } + printf("dump_fsnodes: finished %s/%s\n", root->path, root->name); +} + + +/* + * inode_type -- + * for a given inode type `mode', return a descriptive string. + * for most cases, uses inotype() from mtree/misc.c + */ +const char * +inode_type(mode_t mode) +{ + + if (S_ISLNK(mode)) + return ("symlink"); /* inotype() returns "link"... */ + return (inotype(mode)); +} + + +/* + * link_check -- + * return pointer to fsinode matching `entry's st_ino & st_dev if it exists, + * otherwise add `entry' to table and return NULL + */ +/* This was borrowed from du.c and tweaked to keep an fsnode + * pointer instead. -- dbj@netbsd.org + */ +static fsinode * +link_check(fsinode *entry) +{ + static struct entry { + fsinode *data; + } *htable; + static int htshift; /* log(allocated size) */ + static int htmask; /* allocated size - 1 */ + static int htused; /* 2*number of insertions */ + int h, h2; + uint64_t tmp; + /* this constant is (1<<64)/((1+sqrt(5))/2) + * aka (word size)/(golden ratio) + */ + const uint64_t HTCONST = 11400714819323198485ULL; + const int HTBITS = 64; + + /* Never store zero in hashtable */ + assert(entry); + + /* Extend hash table if necessary, keep load under 0.5 */ + if (htused<<1 >= htmask) { + struct entry *ohtable; + + if (!htable) + htshift = 10; /* starting hashtable size */ + else + htshift++; /* exponential hashtable growth */ + + htmask = (1 << htshift) - 1; + htused = 0; + + ohtable = htable; + htable = calloc(htmask+1, sizeof(*htable)); + /* populate newly allocated hashtable */ + if (ohtable) { + int i; + for (i = 0; i <= htmask>>1; i++) + if (ohtable[i].data) + link_check(ohtable[i].data); + free(ohtable); + } + } + + /* multiplicative hashing */ + tmp = entry->st.st_dev; + tmp <<= HTBITS>>1; + tmp |= entry->st.st_ino; + tmp *= HTCONST; + h = tmp >> (HTBITS - htshift); + h2 = 1 | ( tmp >> (HTBITS - (htshift<<1) - 1)); /* must be odd */ + + /* open address hashtable search with double hash probing */ + while (htable[h].data) { + if ((htable[h].data->st.st_ino == entry->st.st_ino) && + (htable[h].data->st.st_dev == entry->st.st_dev)) { + return htable[h].data; + } + h = (h + h2) & htmask; + } + + /* Insert the current entry into hashtable */ + htable[h].data = entry; + htused++; + return NULL; +} diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/AUXDATA/00000.otf b/vendor/bdj-sdk/resources/AVCHD/BDMV/AUXDATA/00000.otf new file mode 100644 index 0000000..d4c396e Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/BDMV/AUXDATA/00000.otf differ diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/AUXDATA/00001.otf b/vendor/bdj-sdk/resources/AVCHD/BDMV/AUXDATA/00001.otf new file mode 100755 index 0000000..b0fce64 Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/BDMV/AUXDATA/00001.otf differ diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/AUXDATA/00002.otf b/vendor/bdj-sdk/resources/AVCHD/BDMV/AUXDATA/00002.otf new file mode 100755 index 0000000..e07e2c3 Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/BDMV/AUXDATA/00002.otf differ diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/AUXDATA/dvb.fontindex b/vendor/bdj-sdk/resources/AVCHD/BDMV/AUXDATA/dvb.fontindex new file mode 100755 index 0000000..9dd81af --- /dev/null +++ b/vendor/bdj-sdk/resources/AVCHD/BDMV/AUXDATA/dvb.fontindex @@ -0,0 +1,23 @@ + + + + + RobotoMono + OTF + 00000.otf + + + + Arial + OTF + 00001.otf + + + + NewsGothicStd + OTF + 00002.otf + + + diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/BACKUP/INDEX.BDM b/vendor/bdj-sdk/resources/AVCHD/BDMV/BACKUP/INDEX.BDM new file mode 100755 index 0000000..df888b6 Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/BDMV/BACKUP/INDEX.BDM differ diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/BACKUP/MOVIEOBJ.BDM b/vendor/bdj-sdk/resources/AVCHD/BDMV/BACKUP/MOVIEOBJ.BDM new file mode 100755 index 0000000..aec3216 Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/BDMV/BACKUP/MOVIEOBJ.BDM differ diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/BACKUP/MovieObject.bdmv b/vendor/bdj-sdk/resources/AVCHD/BDMV/BACKUP/MovieObject.bdmv new file mode 100755 index 0000000..aec3216 Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/BDMV/BACKUP/MovieObject.bdmv differ diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/BACKUP/index.bdmv b/vendor/bdj-sdk/resources/AVCHD/BDMV/BACKUP/index.bdmv new file mode 100755 index 0000000..df888b6 Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/BDMV/BACKUP/index.bdmv differ diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/BDJO/00000.bdjo b/vendor/bdj-sdk/resources/AVCHD/BDMV/BDJO/00000.bdjo new file mode 100755 index 0000000..61bdd14 Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/BDMV/BDJO/00000.bdjo differ diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/CLIPINF/00000.clpi b/vendor/bdj-sdk/resources/AVCHD/BDMV/CLIPINF/00000.clpi new file mode 100755 index 0000000..c8df794 Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/BDMV/CLIPINF/00000.clpi differ diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/MovieObject.bdmv b/vendor/bdj-sdk/resources/AVCHD/BDMV/MovieObject.bdmv new file mode 100755 index 0000000..aec3216 Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/BDMV/MovieObject.bdmv differ diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/PLAYLIST/00000.mpls b/vendor/bdj-sdk/resources/AVCHD/BDMV/PLAYLIST/00000.mpls new file mode 100755 index 0000000..a6fb78c Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/BDMV/PLAYLIST/00000.mpls differ diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/STREAM/00000.m2ts b/vendor/bdj-sdk/resources/AVCHD/BDMV/STREAM/00000.m2ts new file mode 100755 index 0000000..d3eb741 Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/BDMV/STREAM/00000.m2ts differ diff --git a/vendor/bdj-sdk/resources/AVCHD/BDMV/index.bdmv b/vendor/bdj-sdk/resources/AVCHD/BDMV/index.bdmv new file mode 100755 index 0000000..e311ce6 Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/BDMV/index.bdmv differ diff --git a/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/BACKUP/app.discroot.crt b/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/BACKUP/app.discroot.crt new file mode 100755 index 0000000..38fc69d Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/BACKUP/app.discroot.crt differ diff --git a/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/BACKUP/bu.discroot.crt b/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/BACKUP/bu.discroot.crt new file mode 100755 index 0000000..786e56d Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/BACKUP/bu.discroot.crt differ diff --git a/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/BACKUP/id.bdmv b/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/BACKUP/id.bdmv new file mode 100755 index 0000000..339af37 Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/BACKUP/id.bdmv differ diff --git a/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/app.discroot.crt b/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/app.discroot.crt new file mode 100755 index 0000000..38fc69d Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/app.discroot.crt differ diff --git a/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/bu.discroot.crt b/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/bu.discroot.crt new file mode 100755 index 0000000..786e56d Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/bu.discroot.crt differ diff --git a/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/id.bdmv b/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/id.bdmv new file mode 100755 index 0000000..b6d3ec5 Binary files /dev/null and b/vendor/bdj-sdk/resources/AVCHD/CERTIFICATE/id.bdmv differ diff --git a/vendor/bdj-sdk/resources/sig.ks b/vendor/bdj-sdk/resources/sig.ks new file mode 100644 index 0000000..b090de5 Binary files /dev/null and b/vendor/bdj-sdk/resources/sig.ks differ diff --git a/vendor/bdj-sdk/target/.gitignore b/vendor/bdj-sdk/target/.gitignore new file mode 100644 index 0000000..ca5e846 --- /dev/null +++ b/vendor/bdj-sdk/target/.gitignore @@ -0,0 +1,3 @@ +*.class +*.jar + diff --git a/vendor/bdj-sdk/target/Makefile b/vendor/bdj-sdk/target/Makefile new file mode 100644 index 0000000..a442c08 --- /dev/null +++ b/vendor/bdj-sdk/target/Makefile @@ -0,0 +1,18 @@ +MAKEFILE_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) +BDJSDK_HOME ?= $(MAKEFILE_DIR)/../ +JAVA8_HOME ?= $(BDJSDK_HOME)/host/jdk8 +JAVAC := $(JAVA8_HOME)/bin/javac +JAR := $(JAVA8_HOME)/bin/jar + +SOURCES := $(shell find $(MAKEFILE_DIR)/src -name *.java -type f) +JFLAGS := -Xlint:-options -source 1.3 -target 1.3 + + +lib/sony-stubs.jar: $(SOURCES) + $(JAVAC) $(JFLAGS) $(SOURCES) + $(JAR) cf $@ -C src/ . + + +clean: + rm lib/sony-stubs.jar + diff --git a/vendor/bdj-sdk/target/lib/README b/vendor/bdj-sdk/target/lib/README new file mode 100644 index 0000000..1bfcbca --- /dev/null +++ b/vendor/bdj-sdk/target/lib/README @@ -0,0 +1,3 @@ +Origin: + https://github.com/zathras/java.net/raw/master/hdcookbook/lib/stubs/interactive/classes.zip + diff --git a/vendor/bdj-sdk/target/lib/enhanced-stubs.zip b/vendor/bdj-sdk/target/lib/enhanced-stubs.zip new file mode 100644 index 0000000..2c89025 Binary files /dev/null and b/vendor/bdj-sdk/target/lib/enhanced-stubs.zip differ diff --git a/vendor/bdj-sdk/target/lib/interactive-stubs.zip b/vendor/bdj-sdk/target/lib/interactive-stubs.zip new file mode 100755 index 0000000..7411be7 Binary files /dev/null and b/vendor/bdj-sdk/target/lib/interactive-stubs.zip differ diff --git a/vendor/bdj-sdk/target/src/com/sony/gemstack/core/CoreAppContext.java b/vendor/bdj-sdk/target/src/com/sony/gemstack/core/CoreAppContext.java new file mode 100644 index 0000000..4147db9 --- /dev/null +++ b/vendor/bdj-sdk/target/src/com/sony/gemstack/core/CoreAppContext.java @@ -0,0 +1,13 @@ +package com.sony.gemstack.core; + +public class CoreAppContext { + + public static CoreAppContext getContext() { + return null; + } + + public CoreIxcClassLoader getIxcClassLoader() { + return null; + } +} + diff --git a/vendor/bdj-sdk/target/src/com/sony/gemstack/core/CoreIxcClassLoader.java b/vendor/bdj-sdk/target/src/com/sony/gemstack/core/CoreIxcClassLoader.java new file mode 100644 index 0000000..a5e4d35 --- /dev/null +++ b/vendor/bdj-sdk/target/src/com/sony/gemstack/core/CoreIxcClassLoader.java @@ -0,0 +1,6 @@ +package com.sony.gemstack.core; + +public interface CoreIxcClassLoader { + Class findLoadedProxyClass(String str); + Class defineProxyClass(String str, byte[] bytes); +} diff --git a/vendor/bdj-sdk/target/src/com/sony/gemstack/org/dvb/io/ixc/IxcProxy.java b/vendor/bdj-sdk/target/src/com/sony/gemstack/org/dvb/io/ixc/IxcProxy.java new file mode 100644 index 0000000..62a6973 --- /dev/null +++ b/vendor/bdj-sdk/target/src/com/sony/gemstack/org/dvb/io/ixc/IxcProxy.java @@ -0,0 +1,22 @@ +package com.sony.gemstack.org.dvb.io.ixc; + +import com.sony.gemstack.core.CoreIxcClassLoader; +import java.rmi.RemoteException; + +public abstract class IxcProxy { + public abstract Object getRemote(); + public abstract void forgetRemote(); + + protected IxcProxy(CoreIxcClassLoader loader1, CoreIxcClassLoader loader2) { + + } + + protected Object replaceObject(Object obj, CoreIxcClassLoader loader) throws RemoteException { + return null; + } + + protected Object invokeMethod(Object[] objects, String string1, String string2) throws Exception { + return null; + } +} + diff --git a/vendor/bdj-sdk/target/src/jdk/internal/access/JavaIOFileDescriptorAccess.java b/vendor/bdj-sdk/target/src/jdk/internal/access/JavaIOFileDescriptorAccess.java new file mode 100644 index 0000000..d5c6aff --- /dev/null +++ b/vendor/bdj-sdk/target/src/jdk/internal/access/JavaIOFileDescriptorAccess.java @@ -0,0 +1,7 @@ +package jdk.internal.access; + +import java.io.FileDescriptor; + +public interface JavaIOFileDescriptorAccess { + int get(FileDescriptor fd); +} diff --git a/vendor/bdj-sdk/target/src/jdk/internal/access/JavaSecurityAccess.java b/vendor/bdj-sdk/target/src/jdk/internal/access/JavaSecurityAccess.java new file mode 100644 index 0000000..a23174d --- /dev/null +++ b/vendor/bdj-sdk/target/src/jdk/internal/access/JavaSecurityAccess.java @@ -0,0 +1,46 @@ +package jdk.internal.access; + +import java.net.URL; +import java.nio.ByteBuffer; +import java.security.AccessControlContext; +import java.security.CodeSource; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.ProtectionDomain; +import java.security.Provider; +import java.util.Set; +import jdk.internal.security.CodeSigner; +import jdk.internal.security.Entry; +import jdk.internal.security.ProtectionParameter; +import jdk.internal.security.Service; +import jdk.internal.security.keystore.Builder; + +public interface JavaSecurityAccess { + public class ProtectionDomainCache{ + } + + Object doIntersectionPrivilege(PrivilegedAction action, AccessControlContext ctx1, AccessControlContext ctx2); + Object doIntersectionPrivilege(PrivilegedAction action, AccessControlContext ctx); + ProtectionDomainCache getProtectionDomainCache(); + Object doPrivilegedWithCombiner(PrivilegedExceptionAction action, AccessControlContext ctx, Permission[] perms) throws PrivilegedActionException; + Object doPrivileged(PrivilegedAction action, AccessControlContext ctx, Permission[] perms); + Entry getEntry(KeyStore ks, String str, ProtectionParameter pp) throws NoSuchAlgorithmException, GeneralSecurityException; + Service getService(Provider provider, String str1, String str2); + void putService(Provider provider, Service service); + Set getServices(Provider provider); + Provider configure(Provider provider, String str); + Object newInstance(Class clazz, String str, Object obj) throws Exception; + boolean checkEngine(String str); + String getEngineName(String str); + CodeSource newCodeSource(URL url, CodeSigner[] cs); + void update(MessageDigest md, ByteBuffer bb); + Builder newKeyStoreBuilder(KeyStore ks, ProtectionParameter pp); +} diff --git a/vendor/bdj-sdk/target/src/jdk/internal/access/SharedSecrets.java b/vendor/bdj-sdk/target/src/jdk/internal/access/SharedSecrets.java new file mode 100644 index 0000000..f4794d6 --- /dev/null +++ b/vendor/bdj-sdk/target/src/jdk/internal/access/SharedSecrets.java @@ -0,0 +1,14 @@ +package jdk.internal.access; + +public class SharedSecrets { + public static JavaSecurityAccess getJavaSecurityAccess() { + return null; + } + + public static void setJavaSecurityAccess(JavaSecurityAccess access) { + } + + public static JavaIOFileDescriptorAccess getJavaIOFileDescriptorAccess() { + return null; + } +} diff --git a/vendor/bdj-sdk/target/src/jdk/internal/misc/Unsafe.java b/vendor/bdj-sdk/target/src/jdk/internal/misc/Unsafe.java new file mode 100644 index 0000000..f1bb6a6 --- /dev/null +++ b/vendor/bdj-sdk/target/src/jdk/internal/misc/Unsafe.java @@ -0,0 +1,60 @@ +package jdk.internal.misc; + +public final class Unsafe { + private static final Unsafe theUnsafe = new Unsafe(); + + private Unsafe() { + } + + public static Unsafe getUnsafe() { + return theUnsafe; + } + + + public long allocateMemory(long size) { + return 0; + } + + public void freeMemory(long addr) { + } + + public void setMemory(long addr, long length, byte value) { + } + + public void copyMemory(long src_addr, long dst_addr, long length) { + } + + public byte getByte(long addr) { + return 0; + } + + public short getShort(long addr) { + return 0; + } + + public int getInt(long addr) { + return 0; + } + + public long getLong(long addr) { + return 0; + } + + public void putByte(long addr, byte value) { + } + + public void putShort(long addr, short value) { + } + + public void putInt(long addr, int value) { + } + + public void putLong(long addr, long value) { + } + + public int arrayBaseOffset(Class arrayClass) { + return 0; + } + + public native long getLong(Object o, long offset); +} diff --git a/vendor/bdj-sdk/target/src/jdk/internal/security/CodeSigner.java b/vendor/bdj-sdk/target/src/jdk/internal/security/CodeSigner.java new file mode 100644 index 0000000..1c3196d --- /dev/null +++ b/vendor/bdj-sdk/target/src/jdk/internal/security/CodeSigner.java @@ -0,0 +1,4 @@ +package jdk.internal.security; + +public class CodeSigner{ +} diff --git a/vendor/bdj-sdk/target/src/jdk/internal/security/Entry.java b/vendor/bdj-sdk/target/src/jdk/internal/security/Entry.java new file mode 100644 index 0000000..a068a49 --- /dev/null +++ b/vendor/bdj-sdk/target/src/jdk/internal/security/Entry.java @@ -0,0 +1,4 @@ +package jdk.internal.security; + +public class Entry { +} diff --git a/vendor/bdj-sdk/target/src/jdk/internal/security/ProtectionParameter.java b/vendor/bdj-sdk/target/src/jdk/internal/security/ProtectionParameter.java new file mode 100644 index 0000000..c8ce36e --- /dev/null +++ b/vendor/bdj-sdk/target/src/jdk/internal/security/ProtectionParameter.java @@ -0,0 +1,4 @@ +package jdk.internal.security; + +public class ProtectionParameter { +} diff --git a/vendor/bdj-sdk/target/src/jdk/internal/security/Service.java b/vendor/bdj-sdk/target/src/jdk/internal/security/Service.java new file mode 100644 index 0000000..aec5a6f --- /dev/null +++ b/vendor/bdj-sdk/target/src/jdk/internal/security/Service.java @@ -0,0 +1,4 @@ +package jdk.internal.security; + +public class Service { +} diff --git a/vendor/bdj-sdk/target/src/jdk/internal/security/keystore/Builder.java b/vendor/bdj-sdk/target/src/jdk/internal/security/keystore/Builder.java new file mode 100644 index 0000000..bd17016 --- /dev/null +++ b/vendor/bdj-sdk/target/src/jdk/internal/security/keystore/Builder.java @@ -0,0 +1,4 @@ +package jdk.internal.security.keystore; + +public class Builder { +} diff --git a/vendor/bdj-sdk/target/src/sun/awt/io/FileFileIO.java b/vendor/bdj-sdk/target/src/sun/awt/io/FileFileIO.java new file mode 100644 index 0000000..144e5c3 --- /dev/null +++ b/vendor/bdj-sdk/target/src/sun/awt/io/FileFileIO.java @@ -0,0 +1,90 @@ +package sun.awt.io; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +public class FileFileIO { + protected FileFileIO(String filename) { + } + + public String getName() { + return null; + } + + public String getPath() { + return null; + } + + public InputStream getInputStream() throws IOException { + return null; + } + + public OutputStream getOutputStream() throws IOException { + return null; + } + + public String getAbsolutePath() { + return null; + } + + public String getCanonicalPath() { + return null; + } + + public String getParent() { + return null; + } + + public String canonPath(String path) throws IOException { + return null; + } + + public boolean exists() { + return false; + } + + public boolean canWrite() { + return false; + } + + public boolean canRead() { + return false; + } + + public boolean isFile() { + return false; + } + + public boolean isDirectory() { + return false; + } + + public boolean isAbsolute() { + return false; + } + + public long lastModified() { + return 0; + } + + public long length() { + return 0; + } + + public String[] list() { + return null; + } + + public boolean delete() { + return false; + } + + public boolean mkdir() { + return false; + } + + public boolean mkdirs() { + return false; + } +} diff --git a/vendor/bdj-sdk/target/src/sun/net/www/protocol/file/FileURLConnection.java b/vendor/bdj-sdk/target/src/sun/net/www/protocol/file/FileURLConnection.java new file mode 100644 index 0000000..7baf0f5 --- /dev/null +++ b/vendor/bdj-sdk/target/src/sun/net/www/protocol/file/FileURLConnection.java @@ -0,0 +1,19 @@ +package sun.net.www.protocol.file; + +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.net.URL; + +public class FileURLConnection { + + protected FileURLConnection(URL url, File file) { + } + + public void connect() throws IOException { + } + + public synchronized InputStream getInputStream() throws IOException { + return null; + } +}