aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archive/sg_err.h4
-rw-r--r--examples/sg_iovec_tst.c194
-rw-r--r--examples/sg_simple_aio.c219
-rw-r--r--utils/Makefile58
-rw-r--r--utils/hxascdmp.c171
5 files changed, 644 insertions, 2 deletions
diff --git a/archive/sg_err.h b/archive/sg_err.h
index 317767b6..ef57b5ce 100644
--- a/archive/sg_err.h
+++ b/archive/sg_err.h
@@ -3,7 +3,7 @@
/* Feel free to copy and modify this GPL-ed code into your applications. */
-/* Version 0.89 (20030313)
+/* Version 0.90 (20030519)
*/
@@ -157,6 +157,6 @@ extern int sg_err_category3(struct sg_io_hdr * hp);
extern int sg_get_command_size(unsigned char opcode);
extern void sg_get_command_name(unsigned char opcode, int buff_len,
- char * buff);
+ char * buff);
#endif
diff --git a/examples/sg_iovec_tst.c b/examples/sg_iovec_tst.c
new file mode 100644
index 00000000..16e7a4d7
--- /dev/null
+++ b/examples/sg_iovec_tst.c
@@ -0,0 +1,194 @@
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "sg_include.h"
+#include "sg_err.h"
+
+/* Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg")
+ device driver.
+* Copyright (C) 2003 D. Gilbert
+* 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 2, or (at your option)
+* any later version.
+
+ This program will read a certain number of blocks of a given block size
+ from a given sg device node and write what is retrieved out to a
+ normal file. The purpose is to test the sg_iovec mechanism within the
+ sg_io_hdr structure.
+
+ Version 0.10 (20030529)
+*/
+
+
+#define ME "sg_iovec_tst: "
+
+#define A_PRIME 509
+#define IOVEC_ELEMS 2048
+
+#define SENSE_BUFF_LEN 32
+#define DEF_TIMEOUT 40000 /* 40,000 milliseconds */
+
+struct sg_iovec iovec[IOVEC_ELEMS];
+
+/* Returns 0 if everything ok */
+int sg_read(int sg_fd, unsigned char * buff, int num_blocks, int from_block,
+ int bs)
+{
+ unsigned char rdCmd[10] = {READ_10, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char senseBuff[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+ int dxfer_len = bs * num_blocks;
+ int k, pos, rem;
+
+ rdCmd[2] = (unsigned char)((from_block >> 24) & 0xff);
+ rdCmd[3] = (unsigned char)((from_block >> 16) & 0xff);
+ rdCmd[4] = (unsigned char)((from_block >> 8) & 0xff);
+ rdCmd[5] = (unsigned char)(from_block & 0xff);
+ rdCmd[7] = (unsigned char)((num_blocks >> 8) & 0xff);
+ rdCmd[8] = (unsigned char)(num_blocks & 0xff);
+
+ for (k = 0, pos = 0, rem = dxfer_len; k < IOVEC_ELEMS; ++k) {
+ iovec[k].iov_base = buff + pos;
+ iovec[k].iov_len = (rem > A_PRIME) ? A_PRIME : rem;
+ if (rem <= A_PRIME)
+ break;
+ pos += A_PRIME;
+ rem -= A_PRIME;
+ }
+ if (k >= IOVEC_ELEMS) {
+ fprintf(stderr, "Can't fit dxfer_len=%d bytes in iovec\n", dxfer_len);
+ return -1;
+ }
+ memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof(rdCmd);
+ io_hdr.cmdp = rdCmd;
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = dxfer_len;
+ io_hdr.iovec_count = k + 1;
+ io_hdr.dxferp = iovec;
+ io_hdr.mx_sb_len = SENSE_BUFF_LEN;
+ io_hdr.sbp = senseBuff;
+ io_hdr.timeout = DEF_TIMEOUT;
+ io_hdr.pack_id = from_block;
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr)) {
+ perror("reading (SG_IO) on sg device, error");
+ return -1;
+ }
+ switch (sg_err_category3(&io_hdr)) {
+ case SG_ERR_CAT_CLEAN:
+ break;
+ case SG_ERR_CAT_RECOVERED:
+ fprintf(stderr, "Recovered error while reading block=%d, num=%d\n",
+ from_block, num_blocks);
+ break;
+ case SG_ERR_CAT_MEDIA_CHANGED:
+ fprintf(stderr, "Media changed\n");
+ return -1;
+ default:
+ sg_chk_n_print3("reading", &io_hdr);
+ return -1;
+ }
+ return 0;
+}
+
+
+int main(int argc, char * argv[])
+{
+ int sg_fd, fd, res, j, m, dxfer_len;
+ unsigned int k, num;
+ int do_help = 0;
+ int blk_size = 512;
+ int count = 0;
+ char * sg_file_name = 0;
+ char * out_file_name = 0;
+ unsigned char * buffp;
+
+ for (j = 1; j < argc; ++j) {
+ if (0 == strncmp("-b=", argv[j], 3)) {
+ m = 3;
+ num = sscanf(argv[j] + m, "%d", &blk_size);
+ if ((1 != num) || (blk_size <= 0)) {
+ printf("Couldn't decode number after '-b' switch\n");
+ sg_file_name = 0;
+ break;
+ }
+ }
+ else if (0 == strncmp("-c=", argv[j], 3)) {
+ m = 3;
+ num = sscanf(argv[j] + m, "%d", &count);
+ if (1 != num) {
+ printf("Couldn't decode number after '-c' switch\n");
+ sg_file_name = 0;
+ break;
+ }
+ }
+ else if (0 == strcmp("-h", argv[j]))
+ do_help = 1;
+ else if (*argv[j] == '-') {
+ printf("Unrecognized switch: %s\n", argv[j]);
+ sg_file_name = 0;
+ break;
+ }
+ else if (NULL == sg_file_name)
+ sg_file_name = argv[j];
+ else
+ out_file_name = argv[j];
+ }
+ if ((NULL == sg_file_name) || (NULL == out_file_name) || (0 == count)) {
+ printf("Usage: sg_iovec_tst [-h] [-b=num] -c=num <generic_device> "
+ "<output_filename>\n");
+ printf(" where: -h this usage message\n");
+ printf(" -b=num block size (default 512 Bytes)\n");
+ printf(" -c=num count of blocks to transfer\n");
+ printf(" reads from <generic_device> and sends to <output_filename>\n");
+ return 1;
+ }
+
+ sg_fd = open(sg_file_name, O_RDONLY);
+ if (sg_fd < 0) {
+ perror(ME "sg device node open error");
+ return 1;
+ }
+ /* Don't worry, being very careful not to write to a none-sg file ... */
+ res = ioctl(sg_fd, SG_GET_VERSION_NUM, &k);
+ if ((res < 0) || (k < 30000)) {
+ printf(ME "not a sg device, or driver prior to 3.x\n");
+ return 1;
+ }
+ fd = open(out_file_name, O_WRONLY | O_CREAT, 0666);
+ if (fd < 0) {
+ perror(ME "output file open error");
+ return 1;
+ }
+ dxfer_len = count * blk_size;
+ buffp = malloc(dxfer_len);
+ if (buffp) {
+ if (0 == sg_read(sg_fd, buffp, count, 0, blk_size)) {
+ if (write(fd, buffp, dxfer_len) < 0)
+ perror(ME "output write failed");
+ }
+ free(buffp);
+ }
+ res = close(fd);
+ if (res < 0) {
+ perror(ME "output file close error");
+ close(sg_fd);
+ return 1;
+ }
+ res = close(sg_fd);
+ if (res < 0) {
+ perror(ME "sg device close error");
+ return 1;
+ }
+ return 0;
+}
diff --git a/examples/sg_simple_aio.c b/examples/sg_simple_aio.c
new file mode 100644
index 00000000..127629aa
--- /dev/null
+++ b/examples/sg_simple_aio.c
@@ -0,0 +1,219 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libaio.h>
+#include "sg_include.h"
+#include "sg_err.h"
+
+/* This is a simple program executing a SCSI INQUIRY command and a
+ TEST UNIT READY command using the SCSI generic (sg) driver
+ This variant to test async I/O.
+
+* Copyright (C) 2003 D. Gilbert
+* 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 2, or (at your option)
+* any later version.
+
+ Invocation: sg_simple_aio [-x] <sg_device>
+
+ Version 0.91 (20031109)
+
+6 byte INQUIRY command:
+[0x12][ |lu][pg cde][res ][al len][cntrl ]
+
+6 byte TEST UNIT READY command:
+[0x00][ |lu][res ][res ][res ][res ]
+
+*/
+
+#define INQ_REPLY_LEN 96
+#define INQ_CMD_LEN 6
+#define TUR_CMD_LEN 6
+
+#define EBUFF_SZ 256
+
+void my_io_callback(io_context_t ctx, struct iocb *iocb, long res, long res2)
+{
+ printf("my_io_callback: res=%ld, res2=%ld\n", res, res2);
+}
+
+int main(int argc, char * argv[])
+{
+ int sg_fd, k, ok;
+ unsigned char inqCmdBlk [INQ_CMD_LEN] =
+ {0x12, 0, 0, 0, INQ_REPLY_LEN, 0};
+ unsigned char turCmdBlk [TUR_CMD_LEN] =
+ {0x00, 0, 0, 0, 0, 0};
+ unsigned char inqBuff[INQ_REPLY_LEN];
+ sg_io_hdr_t io_hdr;
+ char * file_name = 0;
+ char ebuff[EBUFF_SZ];
+ unsigned char sense_buffer[32];
+ int do_extra = 0;
+
+ for (k = 1; k < argc; ++k) {
+ if (0 == memcmp("-x", argv[k], 2))
+ do_extra = 1;
+ else if (*argv[k] == '-') {
+ printf("Unrecognized switch: %s\n", argv[k]);
+ file_name = 0;
+ break;
+ }
+ else if (0 == file_name)
+ file_name = argv[k];
+ else {
+ printf("too many arguments\n");
+ file_name = 0;
+ break;
+ }
+ }
+ if (0 == file_name) {
+ printf("Usage: 'sg_simple_aio [-x] <sg_device>'\n");
+ return 1;
+ }
+
+ /* An access mode of O_RDWR is required for write()/read() interface */
+ if ((sg_fd = open(file_name, O_RDWR)) < 0) {
+ snprintf(ebuff, EBUFF_SZ,
+ "sg_simple_aio: error opening file: %s", file_name);
+ perror(ebuff);
+ return 1;
+ }
+ /* Just to be safe, check we have a new sg device by trying an ioctl */
+ if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
+ printf("sg_simple_aio: %s doesn't seem to be an new sg device\n",
+ file_name);
+ close(sg_fd);
+ return 1;
+ }
+
+ /* Prepare INQUIRY command */
+ memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof(inqCmdBlk);
+ /* io_hdr.iovec_count = 0; */ /* memset takes care of this */
+ io_hdr.mx_sb_len = sizeof(sense_buffer);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = INQ_REPLY_LEN;
+ io_hdr.dxferp = inqBuff;
+ io_hdr.cmdp = inqCmdBlk;
+ io_hdr.sbp = sense_buffer;
+ io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */
+ /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */
+ /* io_hdr.pack_id = 0; */
+ /* io_hdr.usr_ptr = NULL; */
+
+#if 1
+ {
+ struct iocb a_iocb;
+ struct iocb * iocb_arr[1];
+ io_context_t io_ctx;
+ int res;
+
+ if (0 != (res = io_queue_init(1, &io_ctx))) {
+ printf("io_queue_init: failed %s\n", strerror(-res));
+ close(sg_fd);
+ return 1;
+ }
+ iocb_arr[0] = &a_iocb;
+ io_prep_pwrite(iocb_arr[0], sg_fd, &io_hdr, sizeof(io_hdr), 0);
+ io_set_callback(iocb_arr[0], my_io_callback);
+ res = io_submit(io_ctx, 1, iocb_arr);
+ if (1 != res) {
+ printf("io_submit: returned %d\n", res);
+ close(sg_fd);
+ return 1;
+ }
+ }
+#else
+ if (write(sg_fd, &io_hdr, sizeof(io_hdr)) < 0) {
+ perror("sg_simple_aio: Inquiry write error");
+ close(sg_fd);
+ return 1;
+ }
+#endif
+ /* sleep(3); */
+ if (read(sg_fd, &io_hdr, sizeof(io_hdr)) < 0) {
+ perror("sg_simple_aio: Inquiry read error");
+ close(sg_fd);
+ return 1;
+ }
+
+ /* now for the error processing */
+ ok = 0;
+ switch (sg_err_category3(&io_hdr)) {
+ case SG_ERR_CAT_CLEAN:
+ ok = 1;
+ break;
+ case SG_ERR_CAT_RECOVERED:
+ printf("Recovered error on INQUIRY, continuing\n");
+ ok = 1;
+ break;
+ default: /* won't bother decoding other categories */
+ sg_chk_n_print3("INQUIRY command error", &io_hdr);
+ break;
+ }
+
+ if (ok) { /* output result if it is available */
+ char * p = (char *)inqBuff;
+ int f = (int)*(p + 7);
+ printf("Some of the INQUIRY command's results:\n");
+ printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32);
+ printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n",
+ !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1));
+ /* Extra info, not necessary to look at */
+ if (do_extra)
+ printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n",
+ io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status);
+ }
+
+ /* Prepare TEST UNIT READY command */
+ memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof(turCmdBlk);
+ io_hdr.mx_sb_len = sizeof(sense_buffer);
+ io_hdr.dxfer_direction = SG_DXFER_NONE;
+ io_hdr.cmdp = turCmdBlk;
+ io_hdr.sbp = sense_buffer;
+ io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
+ perror("sg_simple_aio: Test Unit Ready SG_IO ioctl error");
+ close(sg_fd);
+ return 1;
+ }
+
+ /* now for the error processing */
+ ok = 0;
+ switch (sg_err_category3(&io_hdr)) {
+ case SG_ERR_CAT_CLEAN:
+ ok = 1;
+ break;
+ case SG_ERR_CAT_RECOVERED:
+ printf("Recovered error on Test Unit Ready, continuing\n");
+ ok = 1;
+ break;
+ default: /* won't bother decoding other categories */
+ sg_chk_n_print3("Test Unit Ready command error", &io_hdr);
+ break;
+ }
+
+ if (ok)
+ printf("Test Unit Ready successful so unit is ready!\n");
+ else
+ printf("Test Unit Ready failed so unit may _not_ be ready!\n");
+
+ if (do_extra)
+ printf("TEST UNIT READY duration=%u millisecs, resid=%d, msg_status=%d\n",
+ io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status);
+
+ close(sg_fd);
+ return 0;
+}
diff --git a/utils/Makefile b/utils/Makefile
new file mode 100644
index 00000000..35060548
--- /dev/null
+++ b/utils/Makefile
@@ -0,0 +1,58 @@
+SHELL = /bin/sh
+
+PREFIX=/usr/local
+INSTDIR=$(DESTDIR)/$(PREFIX)/bin
+MANDIR=$(DESTDIR)/$(PREFIX)/man
+
+CC = gcc
+LD = gcc
+
+EXECS = hxascdmp
+
+MAN_PGS =
+MAN_PREF = man8
+
+LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+
+CFLAGS = -g -O2 -Wall -D_REENTRANT $(LARGE_FILE_FLAGS)
+# CFLAGS = -g -O2 -Wall -D_REENTRANT -DSG_KERNEL_INCLUDES $(LARGE_FILE_FLAGS)
+# CFLAGS = -g -O2 -Wall -pedantic -D_REENTRANT $(LARGE_FILE_FLAGS)
+
+LDFLAGS =
+
+all: $(EXECS)
+
+depend dep:
+ for i in *.c; do $(CC) $(INCLUDES) $(CFLAGS) -M $$i; \
+ done > .depend
+
+clean:
+ /bin/rm -f *.o $(EXECS) core .depend
+
+hxascdmp: hxascdmp.o
+ $(LD) -o $@ $(LDFLAGS) $^
+
+
+install: $(EXECS)
+ install -d $(INSTDIR)
+ for name in $^; \
+ do install -s -o root -g root -m 755 $$name $(INSTDIR); \
+ done
+ install -d $(MANDIR)/$(MAN_PREF)
+ for mp in $(MAN_PGS); \
+ do install -o root -g root -m 644 $$mp $(MANDIR)/$(MAN_PREF); \
+ gzip -9f $(MANDIR)/$(MAN_PREF)/$$mp; \
+ done
+
+uninstall:
+ dists="$(EXECS)"; \
+ for name in $$dists; do \
+ rm -f $(INSTDIR)/$$name; \
+ done
+ for mp in $(MAN_PGS); do \
+ rm -f $(MANDIR)/$(MAN_PREF)/$$mp.gz; \
+ done
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/utils/hxascdmp.c b/utils/hxascdmp.c
new file mode 100644
index 00000000..467e3a7c
--- /dev/null
+++ b/utils/hxascdmp.c
@@ -0,0 +1,171 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+#define DEF_BYTES_PER_LINE 16
+
+static int bytes_per_line = DEF_BYTES_PER_LINE;
+
+#define CHARS_PER_HEX_BYTE 3
+#define BINARY_START_COL 6
+#define MAX_LINE_LENGTH 257
+
+
+static void dStrHex(const char* str, int len, long start)
+{
+ const char* p = str;
+ unsigned char c;
+ char buff[MAX_LINE_LENGTH];
+ long a = start;
+ const int bpstart = BINARY_START_COL;
+ const int cpstart = BINARY_START_COL +
+ ((CHARS_PER_HEX_BYTE * bytes_per_line) + 1) + 5;
+ int cpos = cpstart;
+ int bpos = bpstart;
+ int midline_space = (bytes_per_line / 2) + 1;
+ int i, k, line_length;
+
+ if (len <= 0)
+ return;
+ line_length = BINARY_START_COL +
+ (bytes_per_line * (1 + CHARS_PER_HEX_BYTE)) + 7;
+ if (line_length >= MAX_LINE_LENGTH)
+ {
+ fprintf(stderr, "bytes_per_line causes maximum line length of %d "
+ "to be exceeded\n", MAX_LINE_LENGTH);
+ return;
+ }
+ memset(buff, ' ', line_length);
+ buff[line_length] = '\0';
+ k = sprintf(buff + 1, "%.2lx", a);
+ buff[k + 1] = ' ';
+ if (bpos >= ((bpstart + (midline_space * CHARS_PER_HEX_BYTE))))
+ bpos++;
+
+ for(i = 0; i < len; i++)
+ {
+ c = *p++;
+ bpos += CHARS_PER_HEX_BYTE;
+ if (bpos == (bpstart + (midline_space * CHARS_PER_HEX_BYTE)))
+ bpos++;
+ sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c);
+ buff[bpos + 2] = ' ';
+ if ((c < ' ') || (c >= 0x7f))
+ c='.';
+ buff[cpos++] = c;
+ if (cpos >= (cpstart + bytes_per_line))
+ {
+ printf("%s\n", buff);
+ bpos = bpstart;
+ cpos = cpstart;
+ a += bytes_per_line;
+ memset(buff,' ', line_length);
+ k = sprintf(buff + 1, "%.2lx", a);
+ buff[k + 1] = ' ';
+ }
+ }
+ if (cpos > cpstart)
+ printf("%s\n", buff);
+}
+
+
+static void usage()
+{
+ fprintf(stderr, "Usage: hxascdmp [-b=<n>] [-h] [-?] [file+] \n");
+ fprintf(stderr, " Sends hex ASCII dump of stdin/file to stdout\n");
+ fprintf(stderr, " where:\n");
+ fprintf(stderr, " -b=<n> bytes per line to display "
+ "(def: 16)\n");
+ fprintf(stderr, " -h print this usage message\n");
+ fprintf(stderr, " -? print this usage message\n");
+ fprintf(stderr, " file reads file(s) and outputs it "
+ "as hex ASCII\n");
+ fprintf(stderr, " if no files reads stdin\n");
+}
+
+int main(int argc, const char ** argv)
+{
+ char buff[8192];
+ int num = 8192;
+ long start = 0;
+ int res, k, u;
+ int inFile = 0; /* stdin */
+ int doHelp = 0;
+ int hasFilename = 0;
+
+ for (k = 1; k < argc; k++)
+ {
+ if (0 == strncmp("-b=", argv[k], 3))
+ {
+ res = sscanf(argv[k] + 3, "%d", &u);
+ if ((1 != res) || (u < 1))
+ {
+ printf("Bad value after '-b' switch\n");
+ usage();
+ return 1;
+ }
+ bytes_per_line = u;
+ }
+ else if (0 == strcmp("-h", argv[k]))
+ doHelp = 1;
+ else if (0 == strcmp("-?", argv[k]))
+ doHelp = 1;
+ else if (*argv[k] == '-')
+ {
+ fprintf(stderr, "unknown switch: %s\n", argv[k]);
+ usage();
+ return 1;
+ }
+ else
+ {
+ hasFilename = 1;
+ break;
+ }
+ }
+ if (doHelp)
+ {
+ usage();
+ return 0;
+ }
+
+ /* Make sure num to fetch is integral multiple of bytes_per_line */
+ if (0 != (num % bytes_per_line))
+ num = (num / bytes_per_line) * bytes_per_line;
+
+ if (hasFilename)
+ {
+ for ( ; k < argc; k++)
+ {
+ inFile = open(argv[k], O_RDONLY);
+ if (inFile < 0)
+ {
+ fprintf(stderr, "Couldn't open file: %s\n", argv[k]);
+ }
+ else
+ {
+ start = 0;
+ printf("ASCII hex dump of file: %s\n", argv[k]);
+ while ((res = read(inFile, buff, num)) > 0)
+ {
+ dStrHex(buff, res, start);
+ start += (long)res;
+ }
+ }
+ close(inFile);
+ printf("\n");
+ }
+ }
+ else
+ {
+ while ((res = read(inFile, buff, num)) > 0)
+ {
+ dStrHex(buff, res, start);
+ start += (long)res;
+ }
+ }
+ return 0;
+}