diff --git a/libisofs/fsource.c b/libisofs/fsource.c index 05f698d..5d95ee0 100644 --- a/libisofs/fsource.c +++ b/libisofs/fsource.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso + * Copyright (c) 2022 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -133,3 +134,59 @@ int iso_file_source_get_aa_string(IsoFileSource *src, return src->class->get_aa_string(src, aa_string, flag); } + +/* Determine whether src is random-access readable and return its capacity. + @flag bit0= Open and close src + @return <0 iso_file_source_lseek failed , >= 0 readable capacity +*/ +off_t iso_file_source_lseek_capacity(IsoFileSource *src, int flag) +{ + int ret, opened = 0; + off_t end, old, reset; + struct stat info; + + ret = iso_file_source_stat(src, &info); + if (ret < 0) { + end = -1; + goto ex; + } + if (S_ISDIR(info.st_mode) || S_ISLNK(info.st_mode) || + S_ISFIFO(info.st_mode) || S_ISSOCK(info.st_mode)) { + /* open(2) on fifo can block and have side effects. + Active Unix sockets have not been tested but they make as few sense + as directories or symbolic links. + */ + end = -1; + goto ex; + } + + if (flag & 1) { + ret = iso_file_source_open(src); + if (ret < 0) { + end = -1; + goto ex; + } + opened = 1; + } + old = iso_file_source_lseek(src, 0, 1); + if (old < 0) { + end = -1; + goto ex; + } + end = iso_file_source_lseek(src, 0, 2); + if (end < 0) { + end = -1; + goto ex; + } + reset = iso_file_source_lseek(src, old, 0); + if (reset != old) { + end = -1; + goto ex; + } +ex:; + if (opened) { + iso_file_source_close(src); + } + return end; +} + diff --git a/libisofs/fsource.h b/libisofs/fsource.h index 3ec897c..56781f5 100644 --- a/libisofs/fsource.h +++ b/libisofs/fsource.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 - 2016 Thomas Schmitt + * Copyright (c) 2009 - 2022 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -49,4 +49,10 @@ int iso_ifs_source_clone(IsoFileSource *old_source, IsoFileSource **new_source, int flag); +/* Determine whether src is random-access readable and return its capacity. + @return -1 iso_file_source_lseek failed , >= 0 readable capacity +*/ +off_t iso_file_source_lseek_capacity(IsoFileSource *src, int flag); + + #endif /*LIBISO_FSOURCE_H_*/ diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 11ad70d..13af024 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -4,7 +4,7 @@ /* * Copyright (c) 2007-2008 Vreixo Formoso, Mario Danic - * Copyright (c) 2009-2021 Thomas Schmitt + * Copyright (c) 2009-2022 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -6349,8 +6349,9 @@ int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, * according to iso_image_set_truncate_mode(). * Its directory path depends on the parent node. * @param path - * The absolute path of the file in the local filesystem. For now - * only regular files and symlinks to regular files are supported. + * The absolute path of the random-access capable file in the local + * filesystem. Only regular files and device files are supported. + * On Linux, only regular files and block device offer random-access. * @param offset * Byte number in the given file from where to start reading data. * @param size @@ -6368,8 +6369,11 @@ int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists * ISO_OUT_OF_MEM * ISO_RR_NAME_TOO_LONG + * ISO_WRONG_ARG_VALUE, if path is not suitable for random access * * @since 0.6.4 + * + * Device files as path: @since 1.5.6 */ int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent, const char *name, const char *path, diff --git a/libisofs/stream.c b/libisofs/stream.c index 44da78f..ae3a9a2 100644 --- a/libisofs/stream.c +++ b/libisofs/stream.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 - 2015 Thomas Schmitt + * Copyright (c) 2009 - 2022 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -330,6 +330,7 @@ int cut_out_open(IsoStream *stream) { int ret; struct stat info; + off_t src_size, pos; IsoFileSource *src; struct cut_out_stream *data; @@ -348,20 +349,25 @@ int cut_out_open(IsoStream *stream) return ret; } - { - off_t ret; - if (data->offset > info.st_size) { - /* file is smaller than expected */ - ret = iso_file_source_lseek(src, info.st_size, 0); - } else { - ret = iso_file_source_lseek(src, data->offset, 0); - } - if (ret < 0) { - return (int) ret; - } + if (S_ISREG(info.st_mode)) { + src_size= info.st_size; + } else { + /* Determine src_size and lseekability of device */ + src_size = iso_file_source_lseek_capacity(src, 0); + if (src_size <= 0) + return ISO_WRONG_ARG_VALUE; + } + if (data->offset > src_size) { + /* file is smaller than expected */ + pos = iso_file_source_lseek(src, src_size, 0); + } else { + pos = iso_file_source_lseek(src, data->offset, 0); + } + if (pos < 0) { + return (int) pos; } data->pos = 0; - if (data->offset + data->size > info.st_size) { + if (data->offset + data->size > src_size) { return 3; /* file smaller than expected */ } else { return ISO_SUCCESS; @@ -508,6 +514,7 @@ int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, IsoStream **stream) { int r; + off_t src_size; struct stat info; IsoStream *str; struct cut_out_stream *data; @@ -523,10 +530,16 @@ int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, if (r < 0) { return r; } - if (!S_ISREG(info.st_mode)) { - return ISO_WRONG_ARG_VALUE; + + if (S_ISREG(info.st_mode)) { + src_size = info.st_size; + } else { + /* Open src, do iso_source_lseek(SEEK_END), close src */ + src_size = iso_file_source_lseek_capacity(src, 1); + if (src_size <= 0) + return ISO_WRONG_ARG_VALUE; } - if (offset > info.st_size) { + if (offset > src_size) { return ISO_FILE_OFFSET_TOO_BIG; } @@ -551,7 +564,7 @@ int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size, iso_file_source_ref(src); data->offset = offset; - data->size = MIN(info.st_size - offset, size); + data->size = MIN(src_size - offset, size); /* get the id numbers */ data->dev_id = (dev_t) 0; diff --git a/libisofs/tree.c b/libisofs/tree.c index 9b801ba..91953b2 100644 --- a/libisofs/tree.c +++ b/libisofs/tree.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2011 - 2015 Thomas Schmitt + * Copyright (c) 2011 - 2022 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -677,6 +677,7 @@ int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent, IsoNode **node) { int result; + off_t src_size; struct stat info; IsoFilesystem *fs; IsoFileSource *src; @@ -715,17 +716,23 @@ int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent, iso_file_source_unref(src); return result; } - if (!S_ISREG(info.st_mode)) { - return ISO_WRONG_ARG_VALUE; + + if (S_ISREG(info.st_mode)) { + src_size = info.st_size; + } else { + /* Open src, do iso_source_lseek(SEEK_END), close src */ + src_size = iso_file_source_lseek_capacity(src, 1); + if (src_size <= 0) + return ISO_WRONG_ARG_VALUE; } - if (offset >= info.st_size) { + if (offset >= src_size) { return ISO_WRONG_ARG_VALUE; } /* force regular file */ result = image->builder->create_file(image->builder, image, src, &new); - /* free the file */ + /* Give up the newly acquired surplus reference to src */ iso_file_source_unref(src); if (result < 0) {