| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * This file is part of UBIFS. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2006-2008 Nokia Corporation. |
|---|
| 5 | 6 | * Copyright (C) 2006, 2007 University of Szeged, Hungary |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 8 | | - * under the terms of the GNU General Public License version 2 as published by |
|---|
| 9 | | - * the Free Software Foundation. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 12 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 13 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 14 | | - * more details. |
|---|
| 15 | | - * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License along with |
|---|
| 17 | | - * this program; if not, write to the Free Software Foundation, Inc., 51 |
|---|
| 18 | | - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|---|
| 19 | 7 | * |
|---|
| 20 | 8 | * Authors: Artem Bityutskiy (Битюцкий Артём) |
|---|
| 21 | 9 | * Adrian Hunter |
|---|
| .. | .. |
|---|
| 377 | 365 | return sqnum; |
|---|
| 378 | 366 | } |
|---|
| 379 | 367 | |
|---|
| 368 | +void ubifs_init_node(struct ubifs_info *c, void *node, int len, int pad) |
|---|
| 369 | +{ |
|---|
| 370 | + struct ubifs_ch *ch = node; |
|---|
| 371 | + unsigned long long sqnum = next_sqnum(c); |
|---|
| 372 | + |
|---|
| 373 | + ubifs_assert(c, len >= UBIFS_CH_SZ); |
|---|
| 374 | + |
|---|
| 375 | + ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC); |
|---|
| 376 | + ch->len = cpu_to_le32(len); |
|---|
| 377 | + ch->group_type = UBIFS_NO_NODE_GROUP; |
|---|
| 378 | + ch->sqnum = cpu_to_le64(sqnum); |
|---|
| 379 | + ch->padding[0] = ch->padding[1] = 0; |
|---|
| 380 | + |
|---|
| 381 | + if (pad) { |
|---|
| 382 | + len = ALIGN(len, 8); |
|---|
| 383 | + pad = ALIGN(len, c->min_io_size) - len; |
|---|
| 384 | + ubifs_pad(c, node + len, pad); |
|---|
| 385 | + } |
|---|
| 386 | +} |
|---|
| 387 | + |
|---|
| 388 | +void ubifs_crc_node(struct ubifs_info *c, void *node, int len) |
|---|
| 389 | +{ |
|---|
| 390 | + struct ubifs_ch *ch = node; |
|---|
| 391 | + uint32_t crc; |
|---|
| 392 | + |
|---|
| 393 | + crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8); |
|---|
| 394 | + ch->crc = cpu_to_le32(crc); |
|---|
| 395 | +} |
|---|
| 396 | + |
|---|
| 397 | +/** |
|---|
| 398 | + * ubifs_prepare_node_hmac - prepare node to be written to flash. |
|---|
| 399 | + * @c: UBIFS file-system description object |
|---|
| 400 | + * @node: the node to pad |
|---|
| 401 | + * @len: node length |
|---|
| 402 | + * @hmac_offs: offset of the HMAC in the node |
|---|
| 403 | + * @pad: if the buffer has to be padded |
|---|
| 404 | + * |
|---|
| 405 | + * This function prepares node at @node to be written to the media - it |
|---|
| 406 | + * calculates node CRC, fills the common header, and adds proper padding up to |
|---|
| 407 | + * the next minimum I/O unit if @pad is not zero. if @hmac_offs is positive then |
|---|
| 408 | + * a HMAC is inserted into the node at the given offset. |
|---|
| 409 | + * |
|---|
| 410 | + * This function returns 0 for success or a negative error code otherwise. |
|---|
| 411 | + */ |
|---|
| 412 | +int ubifs_prepare_node_hmac(struct ubifs_info *c, void *node, int len, |
|---|
| 413 | + int hmac_offs, int pad) |
|---|
| 414 | +{ |
|---|
| 415 | + int err; |
|---|
| 416 | + |
|---|
| 417 | + ubifs_init_node(c, node, len, pad); |
|---|
| 418 | + |
|---|
| 419 | + if (hmac_offs > 0) { |
|---|
| 420 | + err = ubifs_node_insert_hmac(c, node, len, hmac_offs); |
|---|
| 421 | + if (err) |
|---|
| 422 | + return err; |
|---|
| 423 | + } |
|---|
| 424 | + |
|---|
| 425 | + ubifs_crc_node(c, node, len); |
|---|
| 426 | + |
|---|
| 427 | + return 0; |
|---|
| 428 | +} |
|---|
| 429 | + |
|---|
| 380 | 430 | /** |
|---|
| 381 | 431 | * ubifs_prepare_node - prepare node to be written to flash. |
|---|
| 382 | 432 | * @c: UBIFS file-system description object |
|---|
| .. | .. |
|---|
| 390 | 440 | */ |
|---|
| 391 | 441 | void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad) |
|---|
| 392 | 442 | { |
|---|
| 393 | | - uint32_t crc; |
|---|
| 394 | | - struct ubifs_ch *ch = node; |
|---|
| 395 | | - unsigned long long sqnum = next_sqnum(c); |
|---|
| 396 | | - |
|---|
| 397 | | - ubifs_assert(c, len >= UBIFS_CH_SZ); |
|---|
| 398 | | - |
|---|
| 399 | | - ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC); |
|---|
| 400 | | - ch->len = cpu_to_le32(len); |
|---|
| 401 | | - ch->group_type = UBIFS_NO_NODE_GROUP; |
|---|
| 402 | | - ch->sqnum = cpu_to_le64(sqnum); |
|---|
| 403 | | - ch->padding[0] = ch->padding[1] = 0; |
|---|
| 404 | | - crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8); |
|---|
| 405 | | - ch->crc = cpu_to_le32(crc); |
|---|
| 406 | | - |
|---|
| 407 | | - if (pad) { |
|---|
| 408 | | - len = ALIGN(len, 8); |
|---|
| 409 | | - pad = ALIGN(len, c->min_io_size) - len; |
|---|
| 410 | | - ubifs_pad(c, node + len, pad); |
|---|
| 411 | | - } |
|---|
| 443 | + /* |
|---|
| 444 | + * Deliberately ignore return value since this function can only fail |
|---|
| 445 | + * when a hmac offset is given. |
|---|
| 446 | + */ |
|---|
| 447 | + ubifs_prepare_node_hmac(c, node, len, 0, pad); |
|---|
| 412 | 448 | } |
|---|
| 413 | 449 | |
|---|
| 414 | 450 | /** |
|---|
| .. | .. |
|---|
| 810 | 846 | */ |
|---|
| 811 | 847 | n = aligned_len >> c->max_write_shift; |
|---|
| 812 | 848 | if (n) { |
|---|
| 813 | | - n <<= c->max_write_shift; |
|---|
| 849 | + int m = n - 1; |
|---|
| 850 | + |
|---|
| 814 | 851 | dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, |
|---|
| 815 | 852 | wbuf->offs); |
|---|
| 816 | | - err = ubifs_leb_write(c, wbuf->lnum, buf + written, |
|---|
| 817 | | - wbuf->offs, n); |
|---|
| 853 | + |
|---|
| 854 | + if (m) { |
|---|
| 855 | + /* '(n-1)<<c->max_write_shift < len' is always true. */ |
|---|
| 856 | + m <<= c->max_write_shift; |
|---|
| 857 | + err = ubifs_leb_write(c, wbuf->lnum, buf + written, |
|---|
| 858 | + wbuf->offs, m); |
|---|
| 859 | + if (err) |
|---|
| 860 | + goto out; |
|---|
| 861 | + wbuf->offs += m; |
|---|
| 862 | + aligned_len -= m; |
|---|
| 863 | + len -= m; |
|---|
| 864 | + written += m; |
|---|
| 865 | + } |
|---|
| 866 | + |
|---|
| 867 | + /* |
|---|
| 868 | + * The non-written len of buf may be less than 'n' because |
|---|
| 869 | + * parameter 'len' is not 8 bytes aligned, so here we read |
|---|
| 870 | + * min(len, n) bytes from buf. |
|---|
| 871 | + */ |
|---|
| 872 | + n = 1 << c->max_write_shift; |
|---|
| 873 | + memcpy(wbuf->buf, buf + written, min(len, n)); |
|---|
| 874 | + if (n > len) { |
|---|
| 875 | + ubifs_assert(c, n - len < 8); |
|---|
| 876 | + ubifs_pad(c, wbuf->buf + len, n - len); |
|---|
| 877 | + } |
|---|
| 878 | + |
|---|
| 879 | + err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, n); |
|---|
| 818 | 880 | if (err) |
|---|
| 819 | 881 | goto out; |
|---|
| 820 | 882 | wbuf->offs += n; |
|---|
| 821 | 883 | aligned_len -= n; |
|---|
| 822 | | - len -= n; |
|---|
| 884 | + len -= min(len, n); |
|---|
| 823 | 885 | written += n; |
|---|
| 824 | 886 | } |
|---|
| 825 | 887 | |
|---|
| .. | .. |
|---|
| 870 | 932 | } |
|---|
| 871 | 933 | |
|---|
| 872 | 934 | /** |
|---|
| 935 | + * ubifs_write_node_hmac - write node to the media. |
|---|
| 936 | + * @c: UBIFS file-system description object |
|---|
| 937 | + * @buf: the node to write |
|---|
| 938 | + * @len: node length |
|---|
| 939 | + * @lnum: logical eraseblock number |
|---|
| 940 | + * @offs: offset within the logical eraseblock |
|---|
| 941 | + * @hmac_offs: offset of the HMAC within the node |
|---|
| 942 | + * |
|---|
| 943 | + * This function automatically fills node magic number, assigns sequence |
|---|
| 944 | + * number, and calculates node CRC checksum. The length of the @buf buffer has |
|---|
| 945 | + * to be aligned to the minimal I/O unit size. This function automatically |
|---|
| 946 | + * appends padding node and padding bytes if needed. Returns zero in case of |
|---|
| 947 | + * success and a negative error code in case of failure. |
|---|
| 948 | + */ |
|---|
| 949 | +int ubifs_write_node_hmac(struct ubifs_info *c, void *buf, int len, int lnum, |
|---|
| 950 | + int offs, int hmac_offs) |
|---|
| 951 | +{ |
|---|
| 952 | + int err, buf_len = ALIGN(len, c->min_io_size); |
|---|
| 953 | + |
|---|
| 954 | + dbg_io("LEB %d:%d, %s, length %d (aligned %d)", |
|---|
| 955 | + lnum, offs, dbg_ntype(((struct ubifs_ch *)buf)->node_type), len, |
|---|
| 956 | + buf_len); |
|---|
| 957 | + ubifs_assert(c, lnum >= 0 && lnum < c->leb_cnt && offs >= 0); |
|---|
| 958 | + ubifs_assert(c, offs % c->min_io_size == 0 && offs < c->leb_size); |
|---|
| 959 | + ubifs_assert(c, !c->ro_media && !c->ro_mount); |
|---|
| 960 | + ubifs_assert(c, !c->space_fixup); |
|---|
| 961 | + |
|---|
| 962 | + if (c->ro_error) |
|---|
| 963 | + return -EROFS; |
|---|
| 964 | + |
|---|
| 965 | + err = ubifs_prepare_node_hmac(c, buf, len, hmac_offs, 1); |
|---|
| 966 | + if (err) |
|---|
| 967 | + return err; |
|---|
| 968 | + |
|---|
| 969 | + err = ubifs_leb_write(c, lnum, buf, offs, buf_len); |
|---|
| 970 | + if (err) |
|---|
| 971 | + ubifs_dump_node(c, buf); |
|---|
| 972 | + |
|---|
| 973 | + return err; |
|---|
| 974 | +} |
|---|
| 975 | + |
|---|
| 976 | +/** |
|---|
| 873 | 977 | * ubifs_write_node - write node to the media. |
|---|
| 874 | 978 | * @c: UBIFS file-system description object |
|---|
| 875 | 979 | * @buf: the node to write |
|---|
| .. | .. |
|---|
| 886 | 990 | int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum, |
|---|
| 887 | 991 | int offs) |
|---|
| 888 | 992 | { |
|---|
| 889 | | - int err, buf_len = ALIGN(len, c->min_io_size); |
|---|
| 890 | | - |
|---|
| 891 | | - dbg_io("LEB %d:%d, %s, length %d (aligned %d)", |
|---|
| 892 | | - lnum, offs, dbg_ntype(((struct ubifs_ch *)buf)->node_type), len, |
|---|
| 893 | | - buf_len); |
|---|
| 894 | | - ubifs_assert(c, lnum >= 0 && lnum < c->leb_cnt && offs >= 0); |
|---|
| 895 | | - ubifs_assert(c, offs % c->min_io_size == 0 && offs < c->leb_size); |
|---|
| 896 | | - ubifs_assert(c, !c->ro_media && !c->ro_mount); |
|---|
| 897 | | - ubifs_assert(c, !c->space_fixup); |
|---|
| 898 | | - |
|---|
| 899 | | - if (c->ro_error) |
|---|
| 900 | | - return -EROFS; |
|---|
| 901 | | - |
|---|
| 902 | | - ubifs_prepare_node(c, buf, len, 1); |
|---|
| 903 | | - err = ubifs_leb_write(c, lnum, buf, offs, buf_len); |
|---|
| 904 | | - if (err) |
|---|
| 905 | | - ubifs_dump_node(c, buf); |
|---|
| 906 | | - |
|---|
| 907 | | - return err; |
|---|
| 993 | + return ubifs_write_node_hmac(c, buf, len, lnum, offs, -1); |
|---|
| 908 | 994 | } |
|---|
| 909 | 995 | |
|---|
| 910 | 996 | /** |
|---|