On Wednesday 22 August 2018 09:19:29 Pali Rohár wrote:
> On Tuesday 21 August 2018 14:30:16 Phillip Susi wrote:
> > On 8/19/2018 4:26 PM, Pali Rohár wrote:
> > > UDF detection is not simple when you want to do it correctly. But later
> > > I can implement it. What probe function needs to return? Just true/false
> > > if device is a UDF filesystem? Or it needs to return also some metadata?
> > 
> > It doesn't just have some magic number at some offset you can look for
> > to say yep, that looks like UDF?
> 
> Yes and no. Offset is according to anchor block descriptor and location
> of this block of course depends on UDF fs block size. Plus there are 4
> possible locations of anchor. But there is just a finite number of
> possible locations and finite number of possible file system block
> sizes. So it is not a problem, just "correct" implementation needs to
> check all possible combinations -- and I hope you want "correct"
> implementation :-)

Hi! I tried to implement it correctly. In attachment is a simple program
which check if input file is UDF filesystem or not.

But I do not know to easily re-write it to parted API as for reading
buffer there is just ped_geometry_read() function. Which does not take
offset in bytes, but in number of sectors. Anyway, if you have some idea
how to do it easily let me know...

-- 
Pali Rohár
[email protected]
/*
    isudf - Program to check if input file is UDF filesystem
    Copyright (C) 2018 Pali Rohár <[email protected]>

    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 3 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, see <http://www.gnu.org/licenses/>.
*/

#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

/* Scan VSR and check for UDF VSD */
static int detect_vrs(int fd, unsigned int vsdsize)
{
	unsigned int block;
	off_t offset;
	unsigned char ident[5];

	/* Check only first 64 blocks, but theoretically standards does not define upper limit */
	for (block = 0; block < 64; block++)
	{
		/* VRS starts at fixed offset 32kB, it is independent of block size or vsd size */
		offset = 32768 + (off_t)block * vsdsize + 1;
		if (lseek(fd, offset, SEEK_SET) != offset)
			return 0;

		/* Read VSD identifier, it is at offset 1 */
		if (read(fd, ident, 5) != 5)
			return 0;

		/* Check for UDF identifier */
		if (memcmp(ident, "NSR02", 5) == 0 ||
		    memcmp(ident, "NSR03", 5) == 0)
			return 1;

		/* Unknown VSD identifier means end of VRS */
		if (memcmp(ident, "BEA01", 5) != 0 &&
		         memcmp(ident, "TEA01", 5) != 0 &&
		         memcmp(ident, "BOOT2", 5) != 0 &&
		         memcmp(ident, "CD001", 5) != 0 &&
		         memcmp(ident, "CDW02", 5) != 0)
			break;
	}

	return 0;
}

/* Check for UDF AVDP */
static int detect_anchor(int fd, unsigned int blocksize, int rel_block, off_t size)
{
	unsigned long block;
	off_t offset;
	unsigned char tag[16];

	/* Negative block means relative to the end of device */
	if (rel_block < 0)
	{
		if (size / blocksize <= (unsigned long)(-rel_block))
			return 0;
		block = size / blocksize - (unsigned long)(-rel_block);
		if (block < 257)
			return 0;
	}
	else
	{
		block = rel_block;
	}

	offset = (off_t)block * blocksize;
	if (lseek(fd, offset, SEEK_SET) != offset)
		return 0;

	/* Read 16 bytes long tag of AVDP */
	if (read(fd, tag, 16) != 16)
		return 0;

	/* Check for AVDP type (0x0002) */
	if (((unsigned short)tag[0] | ((unsigned short)tag[1] << 8)) != 0x0002)
		return 0;

	/* Check that location stored in AVDP matches */
	if (((unsigned long)tag[12] | ((unsigned long)tag[13] << 8) | ((unsigned long)tag[14] << 16) | ((unsigned long)tag[15] << 24)) != block)
		return 0;

	return 1;
}

/* Detect UDF filesystem, it must have VRS and AVDP, returns UDF block size */
static unsigned int detect_udf(int fd, off_t size)
{
	/* All possible combinations of UDF block size and location of AVDP block */
	static int anchors[] = { 256, -257, -1, 512 };
	static unsigned int blocksizes[] = { 512, 1024, 2048, 4096, 8192, 16384, 32768 };

	int detected_vrs[sizeof(blocksizes)/sizeof(*blocksizes)];
	size_t i, j;

	/* VSD size is min(2048, UDF block size) */
	detected_vrs[0] = detected_vrs[1] = detected_vrs[2] = detect_vrs(fd, 2048);
	if (detected_vrs[0])
	{
		for (i = 0; i < 3; i++)
		{
			if (detect_anchor(fd, blocksizes[i], anchors[0], size))
				return blocksizes[i];
		}
	}

	/* Check for block sizes larger then 2048 */
	for (i = 3; i < sizeof(blocksizes)/sizeof(*blocksizes); i++)
	{
		detected_vrs[i] = detect_vrs(fd, blocksizes[i]);
		if (!detected_vrs[i])
			continue;
		if (detect_anchor(fd, blocksizes[i], anchors[0], size))
			return blocksizes[i];
	}

	/* Check remaining possible AVDP locations and all block sizes */
	for (i = 1; i < sizeof(anchors)/sizeof(*anchors); i++)
	{
		for (j = 0; j < sizeof(blocksizes)/sizeof(*blocksizes); j++)
		{
			if (!detected_vrs[j])
				continue;
			if (detect_anchor(fd, blocksizes[j], anchors[i], size))
				return blocksizes[j];
		}
	}

	return 0;
}

int main(int argc, char *argv[])
{
	int fd;
	off_t size;
	unsigned int blocksize;

	if (argc != 2)
	{
		fprintf(stderr, "Usage: %s file\n", argv[0]);
		return 1;
	}

	fd = open(argv[1], O_RDONLY);
	if (fd < 0)
	{
		fprintf(stderr, "Cannot open file '%s': %s\n", argv[1], strerror(errno));
		return 1;
	}

	size = lseek(fd, 0, SEEK_END);
	if (size == (off_t)-1)
	{
		fprintf(stderr, "Cannot seek in file '%s': %s\n", argv[1], strerror(errno));
		return 1;
	}

	blocksize = detect_udf(fd, size);
	if (!blocksize)
		printf("File '%s' is not UDF filesystem\n", argv[1]);
	else
		printf("File '%s' is UDF filesystem with block size %u\n", argv[1], blocksize);

	return 0;
}

Attachment: signature.asc
Description: PGP signature

Reply via email to