On Wed, Jun 22, 2016 at 04:43:18PM +0200, Michal Privoznik wrote:
This function takes a FD and determines whether the current
position is in data section or in a hole. In addition to that,
it also determines how much bytes are there remaining till the
current section ends.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/libvirt_private.syms | 1 +
src/util/virfile.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
src/util/virfile.h | 4 +++
3 files changed, 75 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 501c23e..f476eae 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1513,6 +1513,7 @@ virFileGetHugepageSize;
virFileGetMountReverseSubtree;
virFileGetMountSubtree;
virFileHasSuffix;
+virFileInData;
virFileIsAbsPath;
virFileIsDir;
virFileIsExecutable;
diff --git a/src/util/virfile.c b/src/util/virfile.c
index f47bf39..05b709a 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -3443,3 +3443,73 @@ int virFileIsSharedFS(const char *path)
VIR_FILE_SHFS_SMB |
VIR_FILE_SHFS_CIFS);
}
+
+
+int virFileInData(int fd,
+ int *inData,
+ unsigned long long *length)
+{
+ int ret = -1;
+ off_t cur, data, hole;
+
+ /* Get current position */
+ cur = lseek(fd, 0, SEEK_CUR);
+ if (cur == (off_t) -1) {
+ virReportSystemError(errno, "%s",
+ _("Unable to get current position in file"));
+ goto cleanup;
+ }
+
+ /* Now try to get data and hole offsets */
+ data = lseek(fd, cur, SEEK_DATA);
+
+ /* There are four options:
+ * 1) data == cur; @cur is in data
+ * 2) data > cur; @cur is in a hole, next data at @data
+ * 3) data < 0, errno = ENXIO; either @cur is in trailing hole, or @cur is beyond
EOF.
+ * 4) data < 0, errno != ENXIO; we learned nothing
+ */
+
+ if (data == (off_t) -1) {
+ /* cases 3 and 4 */
+ if (errno != ENXIO) {
+ virReportSystemError(errno, "%s",
+ _("Unable to seek to data"));
+ goto cleanup;
+ }
+ *inData = 0;
+ *length = 0;
+ } else if (data > cur) {
+ /* case 2 */
+ *inData = 0;
+ *length = data - cur;
+ } else {
+ /* case 1 */
+ *inData = 1;
+
+ /* We don't know where does the next hole start. Let's
+ * find out. Here we get the same 4 possibilities as
+ * described above.*/
+ hole = lseek(fd, data, SEEK_HOLE);
+ if (hole == (off_t) -1 || hole == data) {
+ /* cases 1, 3 and 4 */
+ /* Wait a second. The reason why we are here is
+ * because we are in data. But at the same time we
+ * are in a trailing hole? Wut!? Do the best what we
+ * can do here. */
+ virReportSystemError(errno, "%s",
+ _("unable to seek to hole"));
+ goto cleanup;
+ } else {
+ /* case 2 */
+ *length = (hole - data);
+ }
+ }
+
+ ret = 0;
+ cleanup:
+ /* At any rate, reposition back to where we started. */
+ if (cur != (off_t) -1)
+ ignore_value(lseek(fd, cur, SEEK_SET));
Is it really safe to ignore the value here ? IIUC, callers of this
function would be justified in thinking it would *not* have a side
effect on file position. IOW, I think we'd probably want to treat
this error as fatal too.
I think it'd be desirable to have a unit test written explicitly
for this function, since there's a few fun edge cases to worry
about here.
Regards,
Daniel
--
|:
http://berrange.com -o-
http://www.flickr.com/photos/dberrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|:
http://entangle-photo.org -o-
http://live.gnome.org/gtk-vnc :|