...
 
Commits (5)
????-??-??: Version ?.?.?
- Add functions to open directories/files from already open directory.
- Fix possible memory corruption with inline files.
- Improve error resilience and stability.
- Add support for Volume Descriptor Pointer.
......
......@@ -27,51 +27,56 @@
#include "udfread.h"
static int _lsdir(udfread *udf, const char *path)
static int _lsdir_at(UDFDIR *dir, const char *path, int depth)
{
struct udfread_dirent dirent;
UDFDIR *dir = udfread_opendir(udf, path);
if (!dir) {
fprintf(stderr, "udfread_opendir(%s) failed\n", path);
return -1;
}
while (udfread_readdir(dir, &dirent)) {
if (!strcmp(dirent.d_name, ".") || !strcmp(dirent.d_name, "..")) continue;
if (dirent.d_type == UDF_DT_DIR) {
UDFDIR *child;
char *next_dir;
printf("\t\t %s%s\n", path, dirent.d_name);
next_dir = (char*)malloc(strlen(path) + strlen(dirent.d_name) + 2);
if (!next_dir) {
fprintf(stderr, "out of memory\n");
continue;
}
sprintf(next_dir, "%s%s/", path, dirent.d_name);
_lsdir(udf, next_dir);
child = udfread_opendir_at(dir, dirent.d_name);
if (!child) {
fprintf(stderr, "error opening directory %s\n", dirent.d_name);
continue;
}
_lsdir_at(child, next_dir, depth + 1);
udfread_closedir(child);
free(next_dir);
} else {
char *file;
UDFFILE *fp;
file = (char*)malloc(strlen(path) + strlen(dirent.d_name) + 1);
sprintf(file, "%s%s", path, dirent.d_name);
fp = udfread_file_open(udf, file);
fp = udfread_file_openat(dir, dirent.d_name);
if (!fp) {
fprintf(stderr, "error opening file '%s%s'\n", path, dirent.d_name);
continue;
}
printf("%16" PRId64 " %s%s\n", udfread_file_size(fp), path, dirent.d_name);
udfread_file_close(fp);
free(file);
}
}
udfread_closedir(dir);
return 0;
}
int main(int argc, const char *argv[])
{
udfread *udf;
UDFDIR *root;
if (argc < 2) {
fprintf(stderr, "usage: udfls <path>\n"
......@@ -92,7 +97,13 @@ int main(int argc, const char *argv[])
printf("Volume ID: %s\n", udfread_get_volume_id(udf));
_lsdir(udf, "/");
root = udfread_opendir(udf, "/");
if (!root) {
fprintf(stderr, "error opening root directory\n");
} else {
_lsdir_at(root, "/", 0);
udfread_closedir(root);
}
udfread_close(udf);
......
......@@ -174,7 +174,7 @@ size_t decode_file_identifier(const uint8_t *p, size_t size, struct file_identif
size_t l_iu; /* length of implementation use field */
if (size < 38) {
ecma_error("not enough data\n");
ecma_error("decode_file_identifier: not enough data\n");
return 0;
}
......@@ -185,7 +185,7 @@ size_t decode_file_identifier(const uint8_t *p, size_t size, struct file_identif
l_iu = _get_u16(p + 36);
if (size < 38 + l_iu + fi->filename_len) {
ecma_error("not enough data\n");
ecma_error("decode_file_identifier: not enough data\n");
return 0;
}
......@@ -285,14 +285,15 @@ static struct file_entry *_decode_file_entry(const uint8_t *p, size_t size,
int content_inline = 0;
if (p_ad + l_ad > size) {
ecma_error("not enough data in file entry\n");
ecma_error("decode_file_entry: not enough data\n");
return NULL;
}
_decode_icb_tag(p + 16, &tag);
if (tag.strategy_type != 4) {
/* UDF (2.): only ICB strategy types 4 and 4096 shall be recorded */
ecma_error("unsupported icb strategy type %d\n", tag.strategy_type);
ecma_error("decode_file_entry: unsupported icb strategy type %d\n",
tag.strategy_type);
return NULL;
}
......@@ -305,7 +306,7 @@ static struct file_entry *_decode_file_entry(const uint8_t *p, size_t size,
content_inline = 1;
break;
default:
ecma_error("unsupported icb flags: 0x%x\n", tag.flags);
ecma_error("decode_file_entry: unsupported icb flags: 0x%x\n", tag.flags);
return NULL;
}
......@@ -401,7 +402,7 @@ struct file_entry *decode_ext_file_entry(const uint8_t *p, size_t size, uint16_t
/* check for integer overflow */
if ((uint64_t)l_ea + (uint64_t)l_ad + (uint64_t)216 >= (uint64_t)1<<32) {
ecma_error("invalid file entry\n");
ecma_error("invalid extended file entry\n");
return NULL;
}
......
......@@ -1128,7 +1128,7 @@ static int _scan_dir(const struct udf_dir *dir, const char *filename, uint32_t *
}
static int _find_file(udfread *udf, const char *path,
const struct udf_dir **p_dir,
struct udf_dir **p_dir,
const struct udf_file_identifier **p_fid)
{
const struct udf_file_identifier *fid = NULL;
......@@ -1307,15 +1307,32 @@ size_t udfread_get_volume_set_id (udfread *udf, void *buffer, size_t size)
*/
struct udfread_dir {
const struct udf_dir *dir;
udfread *udf;
struct udf_dir *dir;
uint32_t current_file;
};
UDFDIR *udfread_opendir(udfread *udf, const char *path)
static UDFDIR *_new_udfdir(udfread *udf, struct udf_dir *dir)
{
const struct udf_dir *dir = NULL;
UDFDIR *result;
if (!dir) {
return NULL;
}
result = (UDFDIR *)calloc(1, sizeof(UDFDIR));
if (result) {
result->dir = dir;
result->udf = udf;
}
return result;
}
UDFDIR *udfread_opendir(udfread *udf, const char *path)
{
struct udf_dir *dir = NULL;
if (!udf || !udf->input || !path) {
return NULL;
}
......@@ -1324,16 +1341,26 @@ UDFDIR *udfread_opendir(udfread *udf, const char *path)
return NULL;
}
if (!dir) {
return _new_udfdir(udf, dir);
}
UDFDIR *udfread_opendir_at(UDFDIR *p, const char *name)
{
struct udf_dir *dir = NULL;
uint32_t index;
if (!p || !name) {
return NULL;
}
result = (UDFDIR *)calloc(1, sizeof(UDFDIR));
if (result) {
result->dir = dir;
if (_scan_dir(p->dir, name, &index) < 0) {
udf_log("udfread_opendir_at: entry %s not found\n", name);
return NULL;
}
return result;
dir = _read_subdir(p->udf, p->dir, index);
return _new_udfdir(p->udf, dir);
}
struct udfread_dirent *udfread_readdir(UDFDIR *p, struct udfread_dirent *entry)
......@@ -1395,20 +1422,11 @@ struct udfread_file {
void *block_mem;
};
UDFFILE *udfread_file_open(udfread *udf, const char *path)
static UDFFILE *_file_open(udfread *udf, const char *path, const struct udf_file_identifier *fi)
{
const struct udf_file_identifier *fi = NULL;
struct file_entry *fe;
UDFFILE *result;
if (!udf || !udf->input || !path) {
return NULL;
}
if (_find_file(udf, path, NULL, &fi) < 0) {
return NULL;
}
if (fi->characteristic & CHAR_FLAG_DIR) {
udf_log("error opening file %s (is directory)\n", path);
return NULL;
......@@ -1432,6 +1450,37 @@ UDFFILE *udfread_file_open(udfread *udf, const char *path)
return result;
}
UDFFILE *udfread_file_open(udfread *udf, const char *path)
{
const struct udf_file_identifier *fi = NULL;
if (!udf || !udf->input || !path) {
return NULL;
}
if (_find_file(udf, path, NULL, &fi) < 0) {
return NULL;
}
return _file_open(udf, path, fi);
}
UDFFILE *udfread_file_openat(UDFDIR *dir, const char *name)
{
uint32_t index;
if (!dir || !name) {
return NULL;
}
if (_scan_dir(dir->dir, name, &index) < 0) {
udf_log("udfread_file_openat: entry %s not found\n", name);
return NULL;
}
return _file_open(dir->udf, name, &dir->dir->files[index]);
}
int64_t udfread_file_size(UDFFILE *p)
{
if (p) {
......
......@@ -124,6 +124,17 @@ typedef struct udfread_dir UDFDIR;
*/
UDFDIR *udfread_opendir (udfread *, const char *path);
/**
* Open directory stream
*
* Directory name may contain special chars (/, \, ...).
*
* @param dir parent directory handle (NULL for root directory)
* @param name name of the directory to open from dir
* @return directory stream on the directory, or NULL if it could not be opened.
*/
UDFDIR *udfread_opendir_at(UDFDIR *dir, const char *name);
/**
* Read directory stream
*
......@@ -182,6 +193,17 @@ typedef struct udfread_file UDFFILE;
*/
UDFFILE *udfread_file_open (udfread *, const char *path);
/**
* Open a file from directory
*
* File name may contain special chars (/, \, ...).
*
* @param dir parent directory handle
* @param name name of the file
* @return file object, or NULL if it could not be opened.
*/
UDFFILE *udfread_file_openat (UDFDIR *dir, const char *name);
/**
* Close file object
*
......