A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 139 lines 5.1 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * 9 * Copyright (C) 2017, 2020 by William Wilgus 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation; either version 2 14 * of the License, or (at your option) any later version. 15 * 16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 17 * KIND, either express or implied. 18 * 19 ****************************************************************************/ 20 21#include "system.h" 22#include "bootdata.h" 23#include "crc32.h" 24#include "loader_strerror.h" 25#include "file.h" 26#include "disk.h" 27#include <string.h> 28#include <stdio.h> 29 30static void write_bootdata_v0(struct boot_data_t *data, unsigned int boot_volume) 31{ 32 memset(data->payload, 0, data->length); 33 34 data->_boot_volume = boot_volume; 35 data->version = 0; 36} 37 38static void write_bootdata_v1(struct boot_data_t *data, unsigned int boot_volume) 39{ 40 memset(data->payload, 0, data->length); 41 42 data->_boot_volume = 0xff; 43 data->version = 1; 44 data->boot_drive = volume_drive(boot_volume); 45 data->boot_partition = volume_partition(boot_volume); 46} 47 48/* Write bootdata into location in FIRMWARE marked by magic header 49 * Assumes buffer is already loaded with the firmware image 50 * We just need to find the location and write data into the 51 * payload region along with the crc for later verification and use. 52 * Returns payload len on success, 53 * On error returns false 54 */ 55bool write_bootdata(unsigned char* buf, int len, unsigned int boot_volume) 56{ 57 int search_len = MIN(len, BOOT_DATA_SEARCH_SIZE) - sizeof(struct boot_data_t); 58 59 /* search for boot data header prior to search_len */ 60 for(int i = 0; i < search_len; i++) 61 { 62 struct boot_data_t *data = (struct boot_data_t *)&buf[i]; 63 if (data->magic[0] != BOOT_DATA_MAGIC0 || 64 data->magic[1] != BOOT_DATA_MAGIC1) 65 continue; 66 67 /* Ignore it if the length extends past the end of the buffer. */ 68 int data_len = offsetof(struct boot_data_t, payload) + data->length; 69 if (i + data_len > len) 70 continue; 71 72 /* Determine the maximum supported boot protocol version. 73 * Version 0 firmware may use 0 or 0xff, all other versions 74 * declare the highest supported version in the version byte. */ 75 int proto_version = 0; 76 if (data->version < 0xff) 77 proto_version = MIN(BOOT_DATA_VERSION, data->version); 78 79 /* Write boot data according to the selected protocol */ 80 if (proto_version == 0) 81 write_bootdata_v0(data, boot_volume); 82 else if (proto_version == 1) 83 write_bootdata_v1(data, boot_volume); 84 else 85 break; 86 87 /* Calculate payload CRC, used by all protocol versions. */ 88 data->crc = crc_32(data->payload, data->length, 0xffffffff); 89 return true; 90 } 91 92 return false; 93} 94 95#ifdef HAVE_MULTIBOOT 96/* Check in root of this <volume> for rockbox_main.<playername> 97 * if this file empty or there is a single slash '/' 98 * buf = '<volume#>/<rootdir>/<firmware(name)>\0' 99 * If instead '/<*DIRECTORY*>' is supplied 100 * addpath will be set to this DIRECTORY buf = 101 * '/<volume#>/addpath/<rootdir>/<firmware(name)>\0' 102 * On error returns Negative number or 0 103 * On success returns bytes from snprintf 104 * and generated path will be placed in buf 105 * note: if supplied buffer is too small return will be 106 * the number of bytes that would have been written 107 */ 108int get_redirect_dir(char* buf, int buffer_size, int volume, 109 const char* rootdir, const char* firmware) 110{ 111 int fd; 112 size_t f_offset; 113 char add_path[MAX_PATH]; 114 /* Check in root of volume for rockbox_main.<playername> redirect */ 115 snprintf(add_path, sizeof(add_path), "/<%d>/"BOOT_REDIR, volume); 116 fd = open(add_path, O_RDONLY); 117 if (fd < 0) 118 return EFILE_NOT_FOUND; 119 120 /*clear add_path for re-use*/ 121 memset(add_path, 0, sizeof(add_path)); 122 f_offset = read(fd, add_path,sizeof(add_path)); 123 close(fd); 124 125 for(size_t i = f_offset - 1; i < f_offset; i--) 126 { 127 /* strip control chars < SPACE or all if path doesn't start with '/' */ 128 if (add_path[i] < 0x20 || add_path[0] != '/') 129 add_path[i] = '\0'; 130 } 131 /* if '/add_path' is specified in rockbox_main.<playername> 132 path is /<vol#>/add_path/rootdir/firmwarename 133 if add_path is empty or '/' is missing from beginning 134 path is /<vol#>/rootdir/firmwarename 135 */ 136 return snprintf(buf, buffer_size, "/<%d>%s/%s/%s", volume, add_path, 137 rootdir, firmware); 138} 139#endif