diff --git a/Makefile.am b/Makefile.am index ad5966e..5fa6c5f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = libudffs mkudffs cdrwtool pktsetup udffsck udfinfo udflabel wrudf doc +SUBDIRS = libudffs mkudffs cdrwtool pktsetup udffsck udfinfo udflabel udftune wrudf doc dist_doc_DATA = AUTHORS COPYING NEWS README EXTRA_DIST = autogen.sh Doxyfile diff --git a/configure.ac b/configure.ac index 30aa656..eb59393 100644 --- a/configure.ac +++ b/configure.ac @@ -41,6 +41,6 @@ AC_SUBST(LTLIBOBJS) AM_CONDITIONAL(USE_READLINE, test "$readline_found" = "yes") -AC_CONFIG_FILES(Makefile libudffs/Makefile mkudffs/Makefile cdrwtool/Makefile pktsetup/Makefile udffsck/Makefile udfinfo/Makefile udflabel/Makefile wrudf/Makefile doc/Makefile) +AC_CONFIG_FILES(Makefile libudffs/Makefile mkudffs/Makefile cdrwtool/Makefile pktsetup/Makefile udffsck/Makefile udfinfo/Makefile udflabel/Makefile udftune/Makefile wrudf/Makefile doc/Makefile) AC_OUTPUT diff --git a/doc/udftune.8 b/doc/udftune.8 new file mode 100644 index 0000000..05545db --- /dev/null +++ b/doc/udftune.8 @@ -0,0 +1,87 @@ +'\" t -*- coding: UTF-8 -*- +.\" Copyright (C) 2017-2021 Pali Rohár +.\" Copyright (C) 2023 Johannes Truschnigg +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License along +.\" with this program; if not, write to the Free Software Foundation, Inc., +.\" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +.\" +.TH UDFTUNE 8 "udftools" "Commands" + +.SH NAME +udftune \(em modify UDF filesystem characteristics + +.SH SYNOPSIS +.BI "udftune [block\-options] [filesystem\-options] " device + +.SH DESCRIPTION +\fBudftune\fP is a UDF-specific utility to modify various aspects of filesystem +metadata, in the spirit of \fBtune2fs\fP(8) and similar tools for other +filesystems. Its current implementation can mark an existing UDF device/image +read-only, or to reverse that and mark it read-write. + +.SH OPTIONS + +.SS "GENERAL OPTIONS" +.TP +.B \-h,\-\-help +Display the usage and the list of options. + +.SS "BLOCK OPTIONS" +.TP +.BI \-b,\-\-blocksize= " block\-size " + +.TP +.BI \-\-startblock= " start\-block " + +.TP +.BI \-\-lastblock= " last\-block " + +.TP +.BI \-\-vatblock= " vat\-block " + +.TP +.B \-\-force + +.TP +.B \-n,\-\-no\-write + +For a comprehensive overview of the block-related options listed above, please +refer to \fBudflabel\fP(8). + +.SS "FILESYSTEM OPTIONS" +.TP +.BI \-\-mark-ro +Mark the UDF filesystem on \fIdevice\fP ro (read-only) in its FSD and LVD. + +.TP +.BI \-\-mark-rw +Mark the UDF filesystem on \fIdevice\fP rw (read+write) in its FSD and LVD. + +.SH "EXIT STATUS" +\fBudftune\fP returns 0 if successful, non-zero if there are problems like +if the block device does not contain a UDF filesystem, or updating failed. + +.SH AUTHOR +.nf +Johannes Truschnigg +Pali Rohár +.fi + +.SH AVAILABILITY +\fBudftune\fP is part of the udftools package since after version 2.3 and is +available from https://github.com/pali/udftools/. + +.SH "SEE ALSO" +\fBmkudffs\fP(8), \fBpktsetup\fP(8), \fBcdrwtool\fP(1), \fBudfinfo\fP(1), +\fBwrudf\fP(1) diff --git a/udfinfo/main.c b/udfinfo/main.c index 03a7041..cb05831 100644 --- a/udfinfo/main.c +++ b/udfinfo/main.c @@ -38,52 +38,6 @@ #include "options.h" #include "readdisc.h" -static uint64_t get_size(int fd) -{ - struct stat st; - uint64_t size; - off_t offset; - - if (fstat(fd, &st) == 0) - { - if (S_ISBLK(st.st_mode) && ioctl(fd, BLKGETSIZE64, &size) == 0) - return size; - else if (S_ISREG(st.st_mode)) - return st.st_size; - } - - offset = lseek(fd, 0, SEEK_END); - if (offset == (off_t)-1) - { - fprintf(stderr, "%s: Error: Cannot detect size of disk: %s\n", appname, strerror(errno)); - exit(1); - } - - if (lseek(fd, 0, SEEK_SET) != 0) - { - fprintf(stderr, "%s: Error: Cannot seek to start of disk: %s\n", appname, strerror(errno)); - exit(1); - } - - return offset; -} - -static int get_sector_size(int fd) -{ - int size; - - if (ioctl(fd, BLKSSZGET, &size) != 0) - return 0; - - if (size < 512 || size > 32768 || (size & (size - 1))) - { - fprintf(stderr, "%s: Warning: Disk logical sector size (%d) is not suitable for UDF\n", appname, size); - return 0; - } - - return size; -} - static uint32_t compute_windows_serial_num(struct udf_disc *disc) { uint8_t *buffer = (uint8_t *)disc->udf_fsd; diff --git a/udfinfo/readdisc.c b/udfinfo/readdisc.c index 7b4e2f5..82ca1bf 100644 --- a/udfinfo/readdisc.c +++ b/udfinfo/readdisc.c @@ -2398,3 +2398,49 @@ int read_disc(int fd, struct udf_disc *disc) return 0; } + +uint64_t get_size(int fd) +{ + struct stat st; + uint64_t size; + off_t offset; + + if (fstat(fd, &st) == 0) + { + if (S_ISBLK(st.st_mode) && ioctl(fd, BLKGETSIZE64, &size) == 0) + return size; + else if (S_ISREG(st.st_mode)) + return st.st_size; + } + + offset = lseek(fd, 0, SEEK_END); + if (offset == (off_t)-1) + { + fprintf(stderr, "%s: Error: Cannot detect size of disk: %s\n", appname, strerror(errno)); + exit(1); + } + + if (lseek(fd, 0, SEEK_SET) != 0) + { + fprintf(stderr, "%s: Error: Cannot seek to start of disk: %s\n", appname, strerror(errno)); + exit(1); + } + + return offset; +} + +int get_sector_size(int fd) +{ + int size; + + if (ioctl(fd, BLKSSZGET, &size) != 0) + return 0; + + if (size < 512 || size > 32768 || (size & (size - 1))) + { + fprintf(stderr, "%s: Warning: Disk logical sector size (%d) is not suitable for UDF\n", appname, size); + return 0; + } + + return size; +} diff --git a/udfinfo/readdisc.h b/udfinfo/readdisc.h index b64832b..636345f 100644 --- a/udfinfo/readdisc.h +++ b/udfinfo/readdisc.h @@ -19,8 +19,12 @@ #ifndef READDISC_H #define READDISC_H +#include + struct udf_disc; +uint64_t get_size(int); +int get_sector_size(int); int read_disc(int, struct udf_disc *); #endif /* READDISC_H */ diff --git a/udflabel/Makefile.am b/udflabel/Makefile.am index 99de9d7..d8d83c2 100644 --- a/udflabel/Makefile.am +++ b/udflabel/Makefile.am @@ -1,4 +1,4 @@ sbin_PROGRAMS = udflabel udflabel_LDADD = $(top_builddir)/libudffs/libudffs.la -udflabel_SOURCES = main.c options.c ../udfinfo/readdisc.c options.h ../udfinfo/readdisc.h ../include/ecma_167.h ../include/osta_udf.h ../include/libudffs.h ../include/bswap.h +udflabel_SOURCES = main.c options.c ../udfinfo/readdisc.c ../udftune/updatedisc.c options.h ../udftune/updatedisc.h ../udfinfo/readdisc.h ../include/ecma_167.h ../include/osta_udf.h ../include/libudffs.h ../include/bswap.h AM_CPPFLAGS = -I$(top_srcdir)/include diff --git a/udflabel/main.c b/udflabel/main.c index d2c9af4..7e7ac88 100644 --- a/udflabel/main.c +++ b/udflabel/main.c @@ -36,156 +36,16 @@ #include "libudffs.h" #include "options.h" +#include "../udftune/updatedisc.h" #include "../udfinfo/readdisc.h" -static uint64_t get_size(int fd) -{ - struct stat st; - uint64_t size; - off_t offset; - - if (fstat(fd, &st) == 0) - { - if (S_ISBLK(st.st_mode) && ioctl(fd, BLKGETSIZE64, &size) == 0) - return size; - else if (S_ISREG(st.st_mode)) - return st.st_size; - } - - offset = lseek(fd, 0, SEEK_END); - if (offset == (off_t)-1) - { - fprintf(stderr, "%s: Error: Cannot detect size of disk: %s\n", appname, strerror(errno)); - exit(1); - } - - if (lseek(fd, 0, SEEK_SET) != 0) - { - fprintf(stderr, "%s: Error: Cannot seek to start of disk: %s\n", appname, strerror(errno)); - exit(1); - } - - return offset; -} - -static int get_sector_size(int fd) -{ - int size; - - if (ioctl(fd, BLKSSZGET, &size) != 0) - return 0; - - if (size < 512 || size > 32768 || (size & (size - 1))) - { - fprintf(stderr, "%s: Warning: Disk logical sector size (%d) is not suitable for UDF\n", appname, size); - return 0; - } - - return size; -} - -static uint16_t compute_crc(void *desc, size_t length) -{ - return udf_crc((uint8_t *)desc + sizeof(tag), length - sizeof(tag), 0); -} - -static uint8_t compute_checksum(tag *tag) -{ - uint8_t i, checksum = 0; - for (i = 0; i < 16; i++) - { - if (i == 4) - continue; - checksum += ((uint8_t *)tag)[i]; - } - return checksum; -} - -static int check_desc(void *desc, size_t length) -{ - tag *tag = desc; - uint16_t crc_length = le16_to_cpu(tag->descCRCLength); - if (crc_length > length - sizeof(*tag)) - return 0; - if (compute_checksum(tag) != tag->tagChecksum) - return 0; - if (compute_crc(desc, sizeof(*tag) + crc_length) != le16_to_cpu(tag->descCRC)) - return 0; - return 1; -} - -static void update_desc(void *desc, size_t length) -{ - tag *tag = desc; - if (length > le16_to_cpu(tag->descCRCLength) + sizeof(*tag)) - length = le16_to_cpu(tag->descCRCLength) + sizeof(*tag); - tag->descCRC = cpu_to_le16(compute_crc(desc, length)); - tag->tagChecksum = compute_checksum(tag); -} - -static void write_desc(int fd, struct udf_disc *disc, enum udf_space_type type, uint16_t ident, void *buffer) -{ - struct udf_extent *ext; - struct udf_desc *desc; - off_t off; - off_t offset; - ssize_t ret; - - ext = disc->head; - while ((ext = next_extent(ext, type))) - { - desc = ext->head; - while ((desc = next_desc(desc, ident))) - { - if (!desc->data || desc->data->buffer != buffer) - continue; - - printf(" ... at block %"PRIu32"\n", ext->start + desc->offset); - - offset = (off_t)disc->blocksize * (ext->start + desc->offset); - off = lseek(fd, offset, SEEK_SET); - if (off != (off_t)-1 && off != offset) - { - errno = EIO; - off = (off_t)-1; - } - if (off == (off_t)-1) - { - fprintf(stderr, "%s: Error: lseek failed: %s\n", appname, strerror(errno)); - return; - } - - if (!(disc->flags & FLAG_NO_WRITE)) - { - ret = write_nointr(fd, desc->data->buffer, desc->data->length); - if (ret >= 0 && (size_t)ret != desc->data->length) - { - errno = EIO; - ret = -1; - } - if (ret < 0) - { - fprintf(stderr, "%s: Error: write failed: %s\n", appname, strerror(errno)); - return; - } - } - - return; - } - } - - fprintf(stderr, "%s: Error: Cannot find needed block for write\n", appname); - return; -} - int main(int argc, char *argv[]) { struct udf_disc disc; char *filename; struct partitionDesc *pd; - struct logicalVolDesc *lvd; struct impUseVolDescImpUse *iuvdiu; - struct domainIdentSuffix *dis; + struct logicalVolDesc *lvd; size_t len; int fd; int flags; @@ -208,6 +68,7 @@ int main(int argc, char *argv[]) int update_lvd = 0; int update_iuvd = 0; int update_fsd = 0; + int update_vid = 0; if (fcntl(0, F_GETFL) < 0 && open("/dev/null", O_RDONLY) < 0) _exit(1); @@ -260,9 +121,6 @@ int main(int argc, char *argv[]) parse_args(argc, argv, &disc, &filename, &force, new_lvid, new_vid, new_fsid, new_fullvsid, new_uuid, new_vsid, new_owner, new_org, new_contact, new_appid, new_impid); - if (disc.flags & FLAG_NO_WRITE) - printf("Note: Not writing to device, just simulating\n"); - if (new_lvid[0] != 0xFF) { update_lvd = 1; @@ -270,8 +128,11 @@ int main(int argc, char *argv[]) update_fsd = 1; } - if (new_vid[0] != 0xFF) + if (new_fullvsid[0] != 0xFF || new_vid[0] != 0xFF) + { + update_vid = 1; update_pvd = 1; + } if (new_fsid[0] != 0xFF) update_fsd = 1; @@ -279,10 +140,10 @@ int main(int argc, char *argv[]) if (new_owner[0] != 0xFF || new_org[0] != 0xFF || new_contact[0] != 0xFF) update_iuvd = 1; - if (new_uuid[0] || new_vsid[0] != 0xFF || new_fullvsid[0] != 0xFF || new_appid[0] != (char)-1 || new_impid[0] != (char)-1) + if (new_uuid[0] || new_vsid[0] != 0xFF || new_appid[0] != (char)-1 || new_impid[0] != (char)-1) update_pvd = 1; - if (update_pvd || update_lvd || update_iuvd || update_fsd) + if (update_pvd || update_lvd || update_iuvd || update_fsd || update_vid) update = 1; if (update && !(disc.flags & FLAG_NO_WRITE)) @@ -290,35 +151,12 @@ int main(int argc, char *argv[]) else flags = O_RDONLY | O_EXCL; - fd = open(filename, flags); - if (fd < 0 && errno == EBUSY) - { - if (update) - { - fprintf(stderr, "%s: Error: Cannot open device '%s': Device is busy, maybe mounted?\n", appname, filename); - exit(1); - } - flags &= ~O_EXCL; - fd = open(filename, flags); - } + fd = open_existing_disc(&disc, filename, flags, update, buf); if (fd < 0) - { - fprintf(stderr, "%s: Error: Cannot open device '%s': %s\n", appname, filename, (errno != EBUSY) ? strerror(errno) : "Device is busy, maybe mounted?"); exit(1); - } - - if (!(flags & O_EXCL)) - fprintf(stderr, "%s: Warning: Device '%s' is busy, %s may report bogus information\n", appname, filename, appname); - - disc.blksize = get_size(fd); - disc.blkssz = get_sector_size(fd); - - if (read_disc(fd, &disc) < 0) - { - fprintf(stderr, "%s: Error: Cannot process device '%s' as UDF disk\n", appname, filename); - exit(1); - } + /* mimick the behavior of e2label(8) et al. when no change is + * requested, i.e. print the current label to stdout, then exit. */ if (!update) { close(fd); @@ -348,21 +186,7 @@ int main(int argc, char *argv[]) fwrite(buf, len, 1, stdout); putchar('\n'); - return 0; - } - - printf("Updating device: %s\n", filename); - - if (!disc.udf_lvid || le32_to_cpu(disc.udf_lvid->integrityType) != LVID_INTEGRITY_TYPE_CLOSE) - { - fprintf(stderr, "%s: Error: Logical Volume is in inconsistent state\n", appname); - exit(1); - } - - if (disc.udf_write_rev > 0x0260) - { - fprintf(stderr, "%s: Error: Minimal UDF Write Revision is %"PRIx16".%02"PRIx16", but udflabel supports only 2.60\n", appname, disc.udf_write_rev >> 8, disc.udf_write_rev & 0xFF); - exit(1); + exit(0); } if (disc.udf_pd[0]) @@ -375,105 +199,17 @@ int main(int argc, char *argv[]) exit(1); } - switch (le32_to_cpu(pd->accessType)) - { - case PD_ACCESS_TYPE_OVERWRITABLE: - case PD_ACCESS_TYPE_REWRITABLE: - break; - - case PD_ACCESS_TYPE_NONE: /* Pseudo OverWrite */ - if (force) - fprintf(stderr, "%s: Warning: Trying to overwrite pseudo-overwrite partition\n", appname); - break; - - case PD_ACCESS_TYPE_WRITE_ONCE: - if (!force && (new_fullvsid[0] != 0xFF || new_vid[0] != 0xFF)) - { - fprintf(stderr, "%s: Error: Cannot update --vid, --vsid, --uuid or --fullvid on writeonce partition\n", appname); - exit(1); - } - else if (!force && !disc.vat_block) - { - fprintf(stderr, "%s: Error: Cannot update writeonce partition without Virtual Allocation Table\n", appname); - exit(1); - } - else if (force) - { - fprintf(stderr, "%s: Warning: Trying to overwrite writeonce partition\n", appname); - } - break; - - case PD_ACCESS_TYPE_READ_ONLY: - if (!force) - { - fprintf(stderr, "%s: Error: Cannot overwrite readonly partition\n", appname); - exit(1); - } - else - { - fprintf(stderr, "%s: Warning: Trying to overwrite readonly partition\n", appname); - } - break; - - default: - if (!force) - { - fprintf(stderr, "%s: Error: Partition Access Type is unknown\n", appname); - exit(1); - } - else - { - fprintf(stderr, "%s: Warning: Trying to overwrite partition with unknown access type\n", appname); - } - break; - } - - /* TODO: VAT mode */ - if ((le32_to_cpu(pd->accessType) == PD_ACCESS_TYPE_WRITE_ONCE && !force) || (disc.vat && (new_lvid[0] != 0xFF || new_fsid[0] != 0xFF))) - { - fprintf(stderr, "%s: Error: Updating Virtual Allocation Table is not supported yet\n", appname); - exit(1); - } - - /* TODO: Pseudo OverWrite mode */ - if (le32_to_cpu(pd->accessType) == PD_ACCESS_TYPE_NONE && !force) - { - fprintf(stderr, "%s: Error: Updating pseudo-overwrite partition is not supported yet\n", appname); + if (!check_access_type(&disc, pd, (char *)appname, force, update_vid)) exit(1); - } if (disc.udf_lvd[0] && update_lvd) { - dis = (struct domainIdentSuffix *)disc.udf_lvd[0]->domainIdent.identSuffix; - if (dis->domainFlags & (DOMAIN_FLAGS_SOFT_WRITE_PROTECT|DOMAIN_FLAGS_HARD_WRITE_PROTECT)) - { - if (!force) - { - fprintf(stderr, "%s: Error: Cannot overwrite write protected Logical Volume Descriptor\n", appname); - exit(1); - } - else - { - fprintf(stderr, "%s: Warning: Trying to overwrite write protected Logical Volume Descriptor\n", appname); - } - } + if (!check_wr_lvd(&disc, (char *)appname, force)) exit(1); } if (disc.udf_fsd && update_fsd) { - dis = (struct domainIdentSuffix *)disc.udf_fsd->domainIdent.identSuffix; - if (dis->domainFlags & (DOMAIN_FLAGS_SOFT_WRITE_PROTECT|DOMAIN_FLAGS_HARD_WRITE_PROTECT)) - { - if (!force) - { - fprintf(stderr, "%s: Error: Cannot overwrite write protected File Set Descriptor\n", appname); - exit(1); - } - else - { - fprintf(stderr, "%s: Warning: Trying to overwrite write protected File Set Descriptor\n", appname); - } - } + if (!check_wr_fsd(&disc, (char *)appname, force)) exit(1); } if (update_pvd) @@ -553,16 +289,8 @@ int main(int argc, char *argv[]) if (update_lvd) { - if (!disc.udf_lvd[0] || !check_desc(disc.udf_lvd[0], sizeof(*disc.udf_lvd[0]) + le32_to_cpu(disc.udf_lvd[0]->mapTableLength))) - { - fprintf(stderr, "%s: Error: Main Logical Volume Descriptor is damaged\n", appname); - exit(1); - } - if (!disc.udf_lvd[1] || !check_desc(disc.udf_lvd[1], sizeof(*disc.udf_lvd[1]) + le32_to_cpu(disc.udf_lvd[1]->mapTableLength))) - { - fprintf(stderr, "%s: Error: Reserve Logical Volume Descriptor is damaged\n", appname); + if (!verify_lvd(&disc, (char *)appname)) exit(1); - } } if (update_iuvd) @@ -581,11 +309,8 @@ int main(int argc, char *argv[]) if (update_fsd) { - if (!disc.udf_fsd || !check_desc(disc.udf_fsd, sizeof(*disc.udf_fsd))) - { - fprintf(stderr, "%s: Error: File Set Descriptor is damaged\n", appname); + if (!verify_fsd(&disc, (char *)appname)) exit(1); - } } if (new_lvid[0] != 0xFF) @@ -815,22 +540,7 @@ int main(int argc, char *argv[]) write_desc(fd, &disc, RVDS, TAG_IDENT_IUVD, disc.udf_iuvd[1]); } - printf("Synchronizing...\n"); - if (!(disc.flags & FLAG_NO_WRITE)) - { - if (fsync(fd) != 0) - { - fprintf(stderr, "%s: Error: Synchronization to device '%s' failed: %s\n", appname, filename, strerror(errno)); - exit(1); - } - } - - if (close(fd) != 0 && errno != EINTR) - { - fprintf(stderr, "%s: Error: Closing device '%s' failed: %s\n", appname, filename, strerror(errno)); - exit(1); - } - - printf("Done\n"); + if (!sync_dev_and_close(&disc, fd, (char *)appname, (char *)filename)) + return 1; return 0; } diff --git a/udftune/Makefile.am b/udftune/Makefile.am new file mode 100644 index 0000000..bbe6490 --- /dev/null +++ b/udftune/Makefile.am @@ -0,0 +1,4 @@ +sbin_PROGRAMS = udftune +udftune_LDADD = $(top_builddir)/libudffs/libudffs.la +udftune_SOURCES = main.c options.c updatedisc.c ../udfinfo/readdisc.c updatedisc.h options.h ../udfinfo/readdisc.h ../include/ecma_167.h ../include/osta_udf.h ../include/libudffs.h +AM_CPPFLAGS = -I$(top_srcdir)/include diff --git a/udftune/main.c b/udftune/main.c new file mode 100644 index 0000000..8195212 --- /dev/null +++ b/udftune/main.c @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2017-2021 Pali Rohár + * Copyright (C) 2023 Johannes Truschnigg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "libudffs.h" +#include "options.h" +#include "updatedisc.h" +#include "../udfinfo/readdisc.h" + +int main(int argc, char *argv[]) +{ + struct udf_disc disc; + char *filename; + struct partitionDesc *pd; + struct domainIdentSuffix *dis; + int fd; + int flags; + char buf[256]; + int mark_ro = 0; + int mark_rw = 0; + int force = 0; + int update = 0; + int update_lvd = 0; + int update_fsd = 0; + int update_vid = 0; + + if (fcntl(0, F_GETFL) < 0 && open("/dev/null", O_RDONLY) < 0) + _exit(1); + if (fcntl(1, F_GETFL) < 0 && open("/dev/null", O_WRONLY) < 0) + _exit(1); + if (fcntl(2, F_GETFL) < 0 && open("/dev/null", O_WRONLY) < 0) + _exit(1); + + appname = "udftune"; + + memset(&disc, 0, sizeof(disc)); + + disc.head = calloc(1, sizeof(struct udf_extent)); + if (!disc.head) + { + fprintf(stderr, "%s: Error: calloc failed: %s\n", appname, strerror(errno)); + exit(1); + } + + disc.start_block = (uint32_t)-1; + disc.flags = FLAG_LOCALE; + disc.tail = disc.head; + disc.head->space_type = USPACE; + + parse_args(argc, argv, &disc, &filename, &force, &mark_ro, &mark_rw); + + if (mark_ro != 0 || mark_rw != 0) + { + update_lvd = 1; + update_fsd = 1; + } + + if (update_lvd || update_fsd) + update = 1; + + if (update && !(disc.flags & FLAG_NO_WRITE)) + flags = O_RDWR | O_EXCL; + else + flags = O_RDONLY | O_EXCL; + + fd = open_existing_disc(&disc, filename, flags, update, buf); + if (fd < 0) + exit(1); + + if (disc.udf_pd[0]) + pd = disc.udf_pd[0]; + else if (disc.udf_pd[1]) + pd = disc.udf_pd[1]; + else + { + fprintf(stderr, "%s: Error: Both Main and Reserve Partition Descriptor are damaged\n", appname); + exit(1); + } + + if (!check_access_type(&disc, pd, (char *)appname, force, update_vid)) + exit(1); + + if (disc.udf_lvd[0] && update_lvd) + { + if (!check_wr_lvd(&disc, (char *)appname, force)) + exit(1); + } + + if (disc.udf_fsd && update_fsd) + { + if (!check_wr_fsd(&disc, (char *)appname, force)) + exit(1); + } + + if (update_lvd) + { + if (!verify_lvd(&disc, (char *)appname)) + exit(1); + } + + if (update_fsd) + { + if (!verify_fsd(&disc, (char *)appname)) + exit(1); + } + + if (mark_ro != 0) + { + printf("Setting FSD SOFT_WRITE_PROTECT Flag...\n"); + dis = (struct domainIdentSuffix *)disc.udf_fsd->domainIdent.identSuffix; + dis->domainFlags |= DOMAIN_FLAGS_SOFT_WRITE_PROTECT; + + printf("Setting LVD SOFT_WRITE_PROTECT Flag...\n"); + dis = (struct domainIdentSuffix *)disc.udf_lvd[0]->domainIdent.identSuffix; + dis->domainFlags |= DOMAIN_FLAGS_SOFT_WRITE_PROTECT; + dis = (struct domainIdentSuffix *)disc.udf_lvd[1]->domainIdent.identSuffix; + dis->domainFlags |= DOMAIN_FLAGS_SOFT_WRITE_PROTECT; + } + + if (mark_rw != 0) + { + printf("Removing FSD HARD_WRITE_PROTECT Flag...\n"); + dis = (struct domainIdentSuffix *)disc.udf_fsd->domainIdent.identSuffix; + dis->domainFlags &= DOMAIN_FLAGS_HARD_WRITE_PROTECT; + printf("Removing FSD SOFT_WRITE_PROTECT Flag...\n"); + dis = (struct domainIdentSuffix *)disc.udf_fsd->domainIdent.identSuffix; + dis->domainFlags &= DOMAIN_FLAGS_SOFT_WRITE_PROTECT; + + printf("Removing LVD HARD_WRITE_PROTECT Flag...\n"); + dis = (struct domainIdentSuffix *)disc.udf_lvd[0]->domainIdent.identSuffix; + dis->domainFlags &= DOMAIN_FLAGS_HARD_WRITE_PROTECT; + dis = (struct domainIdentSuffix *)disc.udf_lvd[1]->domainIdent.identSuffix; + dis->domainFlags &= DOMAIN_FLAGS_HARD_WRITE_PROTECT; + printf("Removing LVD SOFT_WRITE_PROTECT Flag...\n"); + dis = (struct domainIdentSuffix *)disc.udf_lvd[0]->domainIdent.identSuffix; + dis->domainFlags &= DOMAIN_FLAGS_SOFT_WRITE_PROTECT; + dis = (struct domainIdentSuffix *)disc.udf_lvd[1]->domainIdent.identSuffix; + dis->domainFlags &= DOMAIN_FLAGS_SOFT_WRITE_PROTECT; + } + + if (update_lvd) + { + printf("Updating Main Logical Volume Descriptor...\n"); + update_desc(disc.udf_lvd[0], sizeof(*disc.udf_lvd[0]) + le32_to_cpu(disc.udf_lvd[0]->mapTableLength)); + write_desc(fd, &disc, MVDS, TAG_IDENT_LVD, disc.udf_lvd[0]); + } + + if (update_fsd) + { + printf("Updating File Set Descriptor...\n"); + update_desc(disc.udf_fsd, sizeof(*disc.udf_fsd)); + write_desc(fd, &disc, PSPACE, TAG_IDENT_FSD, disc.udf_fsd); + } + + if (update_lvd && disc.udf_lvd[1] != disc.udf_lvd[0]) + { + printf("Updating Reserve Logical Volume Descriptor...\n"); + update_desc(disc.udf_lvd[1], sizeof(*disc.udf_lvd[1]) + le32_to_cpu(disc.udf_lvd[1]->mapTableLength)); + write_desc(fd, &disc, RVDS, TAG_IDENT_LVD, disc.udf_lvd[1]); + } + + if (!sync_dev_and_close(&disc, fd, (char *)appname, (char *)filename)) + return 1; + return 0; +} diff --git a/udftune/options.c b/udftune/options.c new file mode 100644 index 0000000..9949135 --- /dev/null +++ b/udftune/options.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2017-2021 Pali Rohár + * Copyright (C) 2023 Johannes Truschnigg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "libudffs.h" +#include "options.h" + +static struct option long_options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { "blocksize", required_argument, NULL, OPT_BLK_SIZE }, + { "startblock", required_argument, NULL, OPT_START_BLOCK }, + { "lastblock", required_argument, NULL, OPT_LAST_BLOCK }, + { "vatblock", required_argument, NULL, OPT_VAT_BLOCK }, + { "force", no_argument, NULL, OPT_FORCE }, + { "no-write", no_argument, NULL, OPT_NO_WRITE }, + { "mark-ro", no_argument, NULL, OPT_MARK_RO }, + { "mark-rw", no_argument, NULL, OPT_MARK_RW }, + { 0, 0, NULL, 0 }, +}; + +static void usage(void) +{ + fprintf(stderr, "udftune from " PACKAGE_NAME " " PACKAGE_VERSION "\n" + "Usage:\n" + "\tudftune [block-options] device [filesystem-options]\n" + "\n" + "Options:\n" + "\t--help, -h Display this help\n" + "\n" + "Block Options:\n" + "\t--blocksize=, -b Size of blocks in bytes (512, 1024, 2048, 4096, 8192, 16384, 32768; default: detect)\n" + "\t--startblock= Block location where the UDF filesystem starts (default: last session from TOC or 0)\n" + "\t--lastblock= Block location where the UDF filesystem ends (default: VAT block or last device block)\n" + "\t--vatblock= Block location of the Virtual Allocation Table (default: detect)\n" + "\t--force Force updating UDF disks without write support (useful only for disk images)\n" + "\t--no-write, -n Not really, do not write to device, just simulate\n" + "\n" + "Filesystem Options:\n" + "\t--mark-ro Set target to read-only mode\n" + "\t--mark-rw Set target to read-write mode\n" + ); + exit(1); +} + +void parse_args(int argc, char *argv[], struct udf_disc *disc, char **filename, int *force, int *mark_ro, int *mark_rw) +{ + int failed; + int ret; + + while ((ret = getopt_long(argc, argv, "nh", long_options, NULL)) != EOF) // XXX + { + switch (ret) + { + case OPT_HELP: + case 'h': + usage(); + break; + case OPT_BLK_SIZE: + case 'b': + disc->blocksize = strtou32(optarg, 0, &failed); + if (failed || disc->blocksize < 512 || disc->blocksize > 32768 || (disc->blocksize & (disc->blocksize - 1))) + { + fprintf(stderr, "%s: Error: Invalid value for option --blocksize\n", appname); + exit(1); + } + break; + case OPT_START_BLOCK: + disc->start_block = strtou32(optarg, 0, &failed); + if (failed) + { + fprintf(stderr, "%s: Error: Invalid value for option --startblock\n", appname); + exit(1); + } + break; + case OPT_LAST_BLOCK: + disc->last_block = strtou32(optarg, 0, &failed); + if (failed) + { + fprintf(stderr, "%s: Error: Invalid value for option --lastblock\n", appname); + exit(1); + } + break; + case OPT_VAT_BLOCK: + disc->vat_block = strtou32(optarg, 0, &failed); + if (failed) + { + fprintf(stderr, "%s: Error: Invalid value for option --vatblock\n", appname); + exit(1); + } + break; + case OPT_FORCE: + *force = 1; + break; + case OPT_NO_WRITE: + case 'n': + disc->flags |= FLAG_NO_WRITE; + break; + case OPT_MARK_RO: + if (*mark_rw == 1) + { + fprintf(stderr, "%s: Cannot mark a filesystem read-only and re-write at the same time\n", appname); + exit(1); + } + *mark_ro = 1; + break; + case OPT_MARK_RW: + if (*mark_ro == 1) + { + fprintf(stderr, "%s: Cannot mark a filesystem read-only and re-write at the same time\n", appname); + exit(1); + } + *mark_rw = 1; + break; + default: + usage(); + break; + } + } + + if (optind+1 != argc && optind+2 != argc) + usage(); + + *filename = argv[optind]; + +} diff --git a/udftune/options.h b/udftune/options.h new file mode 100644 index 0000000..682bff9 --- /dev/null +++ b/udftune/options.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2017-2021 Pali Rohár + * Copyright (C) 2023 Johannes Truschnigg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef OPTIONS_H +#define OPTIONS_H + +struct udf_disc; + +void parse_args(int, char *[], struct udf_disc *, char **, int *, int *, int *); + +/* + * Command line option token values. + * 0x0000-0x00ff Single characters + * 0x1000-0x1fff Long switches (no arg) + * 0x2000-0x2fff Long settings (arg required) + */ + +#define OPT_HELP 0x1000 +#define OPT_FORCE 0x1001 +#define OPT_NO_WRITE 0x1002 +#define OPT_MARK_RO 0x1003 +#define OPT_MARK_RW 0x1004 +#define OPT_BLK_SIZE 0x2000 +#define OPT_VAT_BLOCK 0x2001 +#define OPT_START_BLOCK 0x2008 +#define OPT_LAST_BLOCK 0x2009 + + +#endif /* OPTIONS_H */ diff --git a/udftune/updatedisc.c b/udftune/updatedisc.c new file mode 100644 index 0000000..d1dcb40 --- /dev/null +++ b/udftune/updatedisc.c @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2017-2021 Pali Rohár + * Copyright (C) 2023 Johannes Truschnigg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "libudffs.h" +#include "updatedisc.h" +#include "../udfinfo/readdisc.h" + +uint16_t compute_crc(void *desc, size_t length) +{ + return udf_crc((uint8_t *)desc + sizeof(tag), length - sizeof(tag), 0); +} + +uint8_t compute_checksum(tag *tag) +{ + uint8_t i, checksum = 0; + for (i = 0; i < 16; i++) + { + if (i == 4) + continue; + checksum += ((uint8_t *)tag)[i]; + } + return checksum; +} + +int check_desc(void *desc, size_t length) +{ + tag *tag = desc; + uint16_t crc_length = le16_to_cpu(tag->descCRCLength); + if (crc_length > length - sizeof(*tag)) + return 0; + if (compute_checksum(tag) != tag->tagChecksum) + return 0; + if (compute_crc(desc, sizeof(*tag) + crc_length) != le16_to_cpu(tag->descCRC)) + return 0; + return 1; +} + +void update_desc(void *desc, size_t length) +{ + tag *tag = desc; + if (length > le16_to_cpu(tag->descCRCLength) + sizeof(*tag)) + length = le16_to_cpu(tag->descCRCLength) + sizeof(*tag); + tag->descCRC = cpu_to_le16(compute_crc(desc, length)); + tag->tagChecksum = compute_checksum(tag); +} + +void write_desc(int fd, struct udf_disc *disc, enum udf_space_type type, uint16_t ident, void *buffer) +{ + struct udf_extent *ext; + struct udf_desc *desc; + off_t off; + off_t offset; + ssize_t ret; + + ext = disc->head; + while ((ext = next_extent(ext, type))) + { + desc = ext->head; + while ((desc = next_desc(desc, ident))) + { + if (!desc->data || desc->data->buffer != buffer) + continue; + + printf(" ... at block %"PRIu32"\n", ext->start + desc->offset); + + offset = (off_t)disc->blocksize * (ext->start + desc->offset); + off = lseek(fd, offset, SEEK_SET); + if (off != (off_t)-1 && off != offset) + { + errno = EIO; + off = (off_t)-1; + } + if (off == (off_t)-1) + { + fprintf(stderr, "%s: Error: lseek failed: %s\n", appname, strerror(errno)); + return; + } + + if (!(disc->flags & FLAG_NO_WRITE)) + { + ret = write_nointr(fd, desc->data->buffer, desc->data->length); + if (ret >= 0 && (size_t)ret != desc->data->length) + { + errno = EIO; + ret = -1; + } + if (ret < 0) + { + fprintf(stderr, "%s: Error: write failed: %s\n", appname, strerror(errno)); + return; + } + } + + return; + } + } + + fprintf(stderr, "%s: Error: Cannot find needed block for write\n", appname); + return; +} + +int open_existing_disc(struct udf_disc *disc, char *filename, int flags, int update, char *buf) +{ + int fd; + + fd = open(filename, flags); + if (fd < 0 && errno == EBUSY) + { + if (update) + { + fprintf(stderr, "%s: Error: Cannot open device '%s': Device is busy, maybe mounted?\n", appname, filename); + return -1; + } + flags &= ~O_EXCL; + fd = open(filename, flags); + } + if (fd < 0) + { + fprintf(stderr, "%s: Error: Cannot open device '%s': %s\n", appname, filename, (errno != EBUSY) ? strerror(errno) : "Device is busy, maybe mounted?"); + return -1; + } + + if (!(flags & O_EXCL)) + fprintf(stderr, "%s: Warning: Device '%s' is busy, %s may report bogus information\n", appname, filename, appname); + + disc->blksize = get_size(fd); + disc->blkssz = get_sector_size(fd); + + if (read_disc(fd, disc) < 0) + { + fprintf(stderr, "%s: Error: Cannot process device '%s' as UDF disk\n", appname, filename); + close(fd); + return -1; + } + + if (disc->udf_write_rev > 0x0260) + { + fprintf(stderr, "%s: Error: Minimal UDF Write Revision is %"PRIx16".%02"PRIx16", but %s supports only 2.60\n", appname, disc->udf_write_rev >> 8, disc->udf_write_rev & 0xFF, appname); + close(fd); + return -1; + } + + if (!disc->udf_lvid || le32_to_cpu(disc->udf_lvid->integrityType) != LVID_INTEGRITY_TYPE_CLOSE) + { + fprintf(stderr, "%s: Error: Logical Volume is in inconsistent state\n", appname); + close(fd); + return -1; + } + + if (update && disc->flags & FLAG_NO_WRITE) + printf("Note: Not writing to device, just simulating\n"); + + if (update) + printf("Updating device: %s\n", filename); + return fd; +} + +int verify_lvd(struct udf_disc *disc, char *appname) +{ + int result = 1; + if (!disc->udf_lvd[0] || !check_desc(disc->udf_lvd[0], sizeof(*disc->udf_lvd[0]) + le32_to_cpu(disc->udf_lvd[0]->mapTableLength))) + { + fprintf(stderr, "%s: Error: Main Logical Volume Descriptor is damaged\n", appname); + result = 0; + } + if (!disc->udf_lvd[1] || !check_desc(disc->udf_lvd[1], sizeof(*disc->udf_lvd[1]) + le32_to_cpu(disc->udf_lvd[1]->mapTableLength))) + { + fprintf(stderr, "%s: Error: Reserve Logical Volume Descriptor is damaged\n", appname); + result = 0; + } + return result; +} + +int verify_fsd(struct udf_disc *disc, char *appname) +{ + int result = 1; + if (!disc->udf_fsd || !check_desc(disc->udf_fsd, sizeof(*disc->udf_fsd))) + { + fprintf(stderr, "%s: Error: File Set Descriptor is damaged\n", appname); + result = 0; + } + return result; +} + +int check_wr_lvd(struct udf_disc *disc, char *appname, int force) +{ + int result = 1; + struct domainIdentSuffix *dis; + + dis = (struct domainIdentSuffix *)disc->udf_lvd[0]->domainIdent.identSuffix; + if (dis->domainFlags & (DOMAIN_FLAGS_SOFT_WRITE_PROTECT|DOMAIN_FLAGS_HARD_WRITE_PROTECT)) + { + if (!force) + { + fprintf(stderr, "%s: Error: Cannot overwrite write protected Logical Volume Descriptor\n", appname); + result = 0; + } + else + { + fprintf(stderr, "%s: Warning: Trying to overwrite write protected Logical Volume Descriptor\n", appname); + } + } + return result; +} + +int check_wr_fsd(struct udf_disc *disc, char *appname, int force) +{ + int result = 1; + struct domainIdentSuffix *dis; + + dis = (struct domainIdentSuffix *)disc->udf_fsd->domainIdent.identSuffix; + if (dis->domainFlags & (DOMAIN_FLAGS_SOFT_WRITE_PROTECT|DOMAIN_FLAGS_HARD_WRITE_PROTECT)) + { + if (!force) + { + fprintf(stderr, "%s: Error: Cannot overwrite write protected File Set Descriptor\n", appname); + result = 0; + } + else + { + fprintf(stderr, "%s: Warning: Trying to overwrite write protected File Set Descriptor\n", appname); + } + } + return result; +} + +int sync_dev_and_close(struct udf_disc *disc, int fd, char *appname, char *filename) +{ + int result = 1; + + printf("Synchronizing...\n"); + if (!(disc->flags & FLAG_NO_WRITE)) + { + if (fsync(fd) != 0) + { + fprintf(stderr, "%s: Error: Synchronization to device '%s' failed: %s\n", appname, filename, strerror(errno)); + result = 0; + } + } + + if (close(fd) != 0 && errno != EINTR) + { + fprintf(stderr, "%s: Error: Closing device '%s' failed: %s\n", appname, filename, strerror(errno)); + result = 0; + } + + printf("Done\n"); + return result; +} + +int check_access_type(struct udf_disc *disc, struct partitionDesc *pd, char *appname, int force, int update_vid) +{ + int result = 1; + + /* TODO: VAT mode */ + if (disc->vat) + { + fprintf(stderr, "%s: Error: Updating Virtual Allocation Table is not supported yet\n", appname); + result = 0; + } + + switch (le32_to_cpu(pd->accessType)) + { + case PD_ACCESS_TYPE_OVERWRITABLE: + case PD_ACCESS_TYPE_REWRITABLE: + break; + + /* TODO: Pseudo OverWrite mode */ + case PD_ACCESS_TYPE_NONE: + if (force) + { + fprintf(stderr, "%s: Warning: Trying to overwrite pseudo-overwrite partition\n", appname); + } + else + { + fprintf(stderr, "%s: Error: Updating pseudo-overwrite partition is not supported yet\n", appname); + result = 0; + } + break; + + case PD_ACCESS_TYPE_WRITE_ONCE: + if (!force && update_vid) + { + fprintf(stderr, "%s: Error: Cannot update --vid, --vsid, --uuid or --fullvid on writeonce partition\n", appname); + result = 0; + } + else if (!force && !disc->vat_block) + { + fprintf(stderr, "%s: Error: Cannot update writeonce partition without Virtual Allocation Table\n", appname); + result = 0; + } + else if (force) + { + fprintf(stderr, "%s: Warning: Trying to overwrite writeonce partition\n", appname); + } + break; + + case PD_ACCESS_TYPE_READ_ONLY: + if (!force) + { + fprintf(stderr, "%s: Error: Cannot overwrite readonly partition\n", appname); + result = 0; + } + else + { + fprintf(stderr, "%s: Warning: Trying to overwrite readonly partition\n", appname); + } + break; + + default: + if (!force) + { + fprintf(stderr, "%s: Error: Partition Access Type is unknown\n", appname); + result = 0; + } + else + { + fprintf(stderr, "%s: Warning: Trying to overwrite partition with unknown access type\n", appname); + } + break; + } + return result; +} diff --git a/udftune/updatedisc.h b/udftune/updatedisc.h new file mode 100644 index 0000000..1bb2c1d --- /dev/null +++ b/udftune/updatedisc.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 Pali Rohár + * Copyright (C) 2023 Johannes Truschnigg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef UPDATEDISC_H +#define UPDATEDISC_H + +uint16_t compute_crc(void *, size_t); +uint8_t compute_checksum(tag *); +int check_desc(void *, size_t); +void update_desc(void *, size_t); +void write_desc(int, struct udf_disc *, enum udf_space_type, uint16_t, void *); +int open_existing_disc(struct udf_disc *, char *, int, int, char *); +int verify_lvd(struct udf_disc *, char *); +int verify_fsd(struct udf_disc *, char *); +int check_wr_lvd(struct udf_disc *, char *, int); +int check_wr_fsd(struct udf_disc *, char *, int); +int sync_dev_and_close(struct udf_disc *, int, char *, char *); +int check_access_type(struct udf_disc *, struct partitionDesc *, char *, int, int); + +#endif /* UPDATEDISC_H */ diff --git a/wrudf/ide-pc.c b/wrudf/ide-pc.c index 6d3202b..42bbfe8 100644 --- a/wrudf/ide-pc.c +++ b/wrudf/ide-pc.c @@ -483,7 +483,8 @@ get_configuration(int fd, u_char* buffer, int size, u_char feature) tmp_be16 = cpu_to_be16(8); memcpy(&pc.cmd[7], &tmp_be16, sizeof(tmp_be16)); // only to see how much will be returned pc.buffer=(void*)buffer; - if( size < 8 ) return -EINVAL; + if( size < 8 ) + return -EINVAL; pc.buflen = 8; rv = ioctl(fd, CDROM_SEND_PACKET, &pc); diff --git a/wrudf/wrudf-cdrw.c b/wrudf/wrudf-cdrw.c index 569c578..444091d 100644 --- a/wrudf/wrudf-cdrw.c +++ b/wrudf/wrudf-cdrw.c @@ -600,7 +600,8 @@ freeBlock(uint32_t lbn, uint16_t part) struct packetbuf *b; uint32_t blkno; - if( medium == CDR ) return; + if( medium == CDR ) + return; blkno = lbn + ( part == 0xFFFF ? 0 : pd->partitionStartingLocation ); b = findBuf(blkno);