On Tuesday 28 August 2018 13:50:53 Pali Rohár wrote: > On Monday 27 August 2018 12:31:25 Phillip Susi wrote: > > On 8/27/2018 12:05 PM, Pali Rohár wrote: > > > Sorry, but I do not understand you. I cannot remove special handling. As > > > I wrote for block sizes < 2048 it is needed, because VSD size != block > > > size. > > > > Your third loop exists only to go back and check the other 3 anchor > > offsets that the first two loops don't check. Just have the first two > > loops check all 4 anchor offsets, preferably by having detect_anchor > > drop it's rel_block argument and just put the 4 offsets in there. > > That would change detection of block size and may improperly detect it! > > But if we are not interested in block size, only in YES/NO answer, then > it should work.
In attachment is a new version, I tried to do what you suggested. -- 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 check_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 check_anchor(int fd, off_t size, unsigned int blocksize, int rel_block)
{
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 <= (off_t)(-rel_block))
return 0;
block = size / blocksize - (off_t)(-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;
}
static int detect_anchor(int fd, off_t size, unsigned int blocksize)
{
/* All possible AVDP locations in preferred order */
static int anchors[] = { 256, -257, -1, 512 };
size_t i;
for (i = 0; i < sizeof(anchors)/sizeof(*anchors); i++)
{
if (check_anchor(fd, size, blocksize, anchors[i]))
return 1;
}
return 0;
}
/* Detect UDF filesystem, it must have VRS and AVDP */
static int detect_udf(int fd, off_t size)
{
unsigned int blocksize;
/* VSD size is min(2048, UDF block size), check for block sizes <= 2048 */
if (check_vrs(fd, 2048))
{
for (blocksize = 512; blocksize <= 2048; blocksize *= 2)
{
if (detect_anchor(fd, size, blocksize))
return 1;
}
}
/* Check for block sizes larger then 2048, maximal theoretical block size is 32kB */
for (blocksize = 4096; blocksize <= 32768; blocksize *= 2)
{
if (!check_vrs(fd, blocksize))
continue;
if (detect_anchor(fd, size, blocksize))
return 1;
}
return 0;
}
int main(int argc, char *argv[])
{
int fd;
off_t size;
int is_udf;
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;
}
is_udf = detect_udf(fd, size);
printf("File '%s' is %sUDF filesystem\n", argv[1], is_udf ? "" : "not ");
return 0;
}
signature.asc
Description: PGP signature
