summaryrefslogtreecommitdiff
path: root/sbin/pdisk/file_media.c
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2001-03-24 00:14:39 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2001-03-24 00:14:39 +0000
commitffb72f990c9933280de104024acf91acee02c1a5 (patch)
tree8312fd465c763b17886e6e1795ab48bde45c2381 /sbin/pdisk/file_media.c
parentfa5275b22eb94a7d990e643d54768420845d618c (diff)
Import of pdisk from apple, BSD licensed code. Archive dated Feb 18 1998
This is a HFS partition editing tool.
Diffstat (limited to 'sbin/pdisk/file_media.c')
-rw-r--r--sbin/pdisk/file_media.c527
1 files changed, 527 insertions, 0 deletions
diff --git a/sbin/pdisk/file_media.c b/sbin/pdisk/file_media.c
new file mode 100644
index 00000000000..1b1e66f52fe
--- /dev/null
+++ b/sbin/pdisk/file_media.c
@@ -0,0 +1,527 @@
+/*
+ * file_media.c -
+ *
+ * Written by Eryk Vershen (eryk@apple.com)
+ */
+
+/*
+ * Copyright 1997,1998 by Apple Computer, Inc.
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+// for printf()
+#include <stdio.h>
+// for malloc() & free()
+#include <stdlib.h>
+// for lseek(), read(), write(), close()
+#include <unistd.h>
+// for open()
+#include <fcntl.h>
+// for LONG_MAX
+#include <limits.h>
+// for errno
+#include <errno.h>
+
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#include <sys/stat.h>
+#endif
+
+#include "file_media.h"
+#include "errors.h"
+
+
+/*
+ * Defines
+ */
+#ifdef __linux__
+#define LOFF_MAX 9223372036854775807LL
+extern __loff_t llseek __P ((int __fd, __loff_t __offset, int __whence));
+#else
+#define loff_t long
+#define llseek lseek
+#define LOFF_MAX LONG_MAX
+#endif
+
+
+/*
+ * Types
+ */
+typedef struct file_media *FILE_MEDIA;
+
+struct file_media {
+ struct media m;
+ int fd;
+ int regular_file;
+};
+
+struct file_media_globals {
+ long exists;
+ long kind;
+};
+
+typedef struct file_media_iterator *FILE_MEDIA_ITERATOR;
+
+struct file_media_iterator {
+ struct media_iterator m;
+ long style;
+ long index;
+};
+
+
+/*
+ * Global Constants
+ */
+int potential_block_sizes[] = {
+ 1, 512, 1024, 2048,
+ 0
+};
+
+enum {
+ kSCSI_Disks = 0,
+ kATA_Devices = 1,
+ kSCSI_CDs = 2,
+ kMaxStyle = 2
+};
+
+
+/*
+ * Global Variables
+ */
+static long file_inited = 0;
+static struct file_media_globals file_info;
+
+/*
+ * Forward declarations
+ */
+int compute_block_size(int fd);
+void file_init(void);
+FILE_MEDIA new_file_media(void);
+long read_file_media(MEDIA m, long long offset, unsigned long count, void *address);
+long write_file_media(MEDIA m, long long offset, unsigned long count, void *address);
+long close_file_media(MEDIA m);
+long os_reload_file_media(MEDIA m);
+FILE_MEDIA_ITERATOR new_file_iterator(void);
+void reset_file_iterator(MEDIA_ITERATOR m);
+char *step_file_iterator(MEDIA_ITERATOR m);
+void delete_file_iterator(MEDIA_ITERATOR m);
+
+
+/*
+ * Routines
+ */
+void
+file_init(void)
+{
+ if (file_inited != 0) {
+ return;
+ }
+ file_inited = 1;
+
+ file_info.kind = allocate_media_kind();
+}
+
+
+FILE_MEDIA
+new_file_media(void)
+{
+ return (FILE_MEDIA) new_media(sizeof(struct file_media));
+}
+
+
+int
+compute_block_size(int fd)
+{
+ int size;
+ int max_size;
+ loff_t x;
+ long t;
+ int i;
+ char *buffer;
+
+ max_size = 0;
+ for (i = 0; ; i++) {
+ size = potential_block_sizes[i];
+ if (size == 0) {
+ break;
+ }
+ if (max_size < size) {
+ max_size = size;
+ }
+ }
+
+ buffer = malloc(max_size);
+ if (buffer != 0) {
+ for (i = 0; ; i++) {
+ size = potential_block_sizes[i];
+ if (size == 0) {
+ break;
+ }
+ if ((x = llseek(fd, (loff_t)0, 0)) < 0) {
+ error(errno, "Can't seek on file");
+ break;
+ }
+ if ((t = read(fd, buffer, size)) == size) {
+ free(buffer);
+ return size;
+ }
+ }
+ }
+ return 0;
+}
+
+
+MEDIA
+open_file_as_media(char *file, int oflag)
+{
+ FILE_MEDIA a;
+ int fd;
+ loff_t off;
+#ifdef __linux__
+ struct stat info;
+#endif
+
+ if (file_inited == 0) {
+ file_init();
+ }
+
+ a = 0;
+ fd = open(file, oflag);
+ if (fd >= 0) {
+ a = new_file_media();
+ if (a != 0) {
+ a->m.kind = file_info.kind;
+ a->m.grain = compute_block_size(fd);
+ off = llseek(fd, (loff_t)0, 2); /* seek to end of media */
+#if !defined(__linux__) && !defined(__unix__)
+ if (off <= 0) {
+ off = 1; /* XXX not right? */
+ }
+#endif
+ //printf("file size = %Ld\n", off);
+ a->m.size_in_bytes = (long long) off;
+ a->m.do_read = read_file_media;
+ a->m.do_write = write_file_media;
+ a->m.do_close = close_file_media;
+ a->m.do_os_reload = os_reload_file_media;
+ a->fd = fd;
+ a->regular_file = 0;
+#ifdef __linux__
+ if (fstat(fd, &info) < 0) {
+ error(errno, "can't stat file '%s'", file);
+ } else {
+ a->regular_file = S_ISREG(info.st_mode);
+ }
+#endif
+ } else {
+ close(fd);
+ }
+ }
+ return (MEDIA) a;
+}
+
+
+long
+read_file_media(MEDIA m, long long offset, unsigned long count, void *address)
+{
+ FILE_MEDIA a;
+ long rtn_value;
+ loff_t off;
+ int t;
+
+ a = (FILE_MEDIA) m;
+ rtn_value = 0;
+ if (a == 0) {
+ /* no media */
+ //printf("no media\n");
+ } else if (a->m.kind != file_info.kind) {
+ /* wrong kind - XXX need to error here - this is an internal problem */
+ //printf("wrong kind\n");
+ } else if (count <= 0 || count % a->m.grain != 0) {
+ /* can't handle size */
+ //printf("bad size\n");
+ } else if (offset < 0 || offset % a->m.grain != 0) {
+ /* can't handle offset */
+ //printf("bad offset\n");
+ } else if (offset + count > a->m.size_in_bytes && a->m.size_in_bytes != (long long) 0) {
+ /* check for offset (and offset+count) too large */
+ //printf("offset+count too large\n");
+ } else if (offset + count > (long long) LOFF_MAX) {
+ /* check for offset (and offset+count) too large */
+ //printf("offset+count too large 2\n");
+ } else {
+ /* do the read */
+ off = offset;
+ if ((off = llseek(a->fd, off, 0)) >= 0) {
+ if ((t = read(a->fd, address, count)) == count) {
+ rtn_value = 1;
+ } else {
+ //printf("read failed\n");
+ }
+ } else {
+ //printf("lseek failed\n");
+ }
+ }
+ return rtn_value;
+}
+
+
+long
+write_file_media(MEDIA m, long long offset, unsigned long count, void *address)
+{
+ FILE_MEDIA a;
+ long rtn_value;
+ loff_t off;
+ int t;
+
+ a = (FILE_MEDIA) m;
+ rtn_value = 0;
+ if (a == 0) {
+ /* no media */
+ } else if (a->m.kind != file_info.kind) {
+ /* wrong kind - XXX need to error here - this is an internal problem */
+ } else if (count <= 0 || count % a->m.grain != 0) {
+ /* can't handle size */
+ } else if (offset < 0 || offset % a->m.grain != 0) {
+ /* can't handle offset */
+ } else if (offset + count > (long long) LOFF_MAX) {
+ /* check for offset (and offset+count) too large */
+ } else {
+ /* do the write */
+ off = offset;
+ if ((off = llseek(a->fd, off, 0)) >= 0) {
+ if ((t = write(a->fd, address, count)) == count) {
+ if (off + count > a->m.size_in_bytes) {
+ a->m.size_in_bytes = off + count;
+ }
+ rtn_value = 1;
+ }
+ }
+ }
+ return rtn_value;
+}
+
+
+long
+close_file_media(MEDIA m)
+{
+ FILE_MEDIA a;
+
+ a = (FILE_MEDIA) m;
+ if (a == 0) {
+ return 0;
+ } else if (a->m.kind != file_info.kind) {
+ /* XXX need to error here - this is an internal problem */
+ return 0;
+ }
+
+ close(a->fd);
+ return 1;
+}
+
+
+long
+os_reload_file_media(MEDIA m)
+{
+ FILE_MEDIA a;
+ long rtn_value;
+#ifdef __linux__
+ int i;
+ int saved_errno;
+#endif
+
+ a = (FILE_MEDIA) m;
+ rtn_value = 0;
+ if (a == 0) {
+ /* no media */
+ } else if (a->m.kind != file_info.kind) {
+ /* wrong kind - XXX need to error here - this is an internal problem */
+ } else if (a->regular_file) {
+ /* okay - nothing to do */
+ rtn_value = 1;
+ } else {
+#ifdef __linux__
+ sync();
+ sleep(2);
+ if ((i = ioctl(a->fd, BLKRRPART)) != 0) {
+ saved_errno = errno;
+ } else {
+ // some kernel versions (1.2.x) seem to have trouble
+ // rereading the partition table, but if asked to do it
+ // twice, the second time works. - biro@yggdrasil.com */
+ sync();
+ sleep(2);
+ if ((i = ioctl(a->fd, BLKRRPART)) != 0) {
+ saved_errno = errno;
+ }
+ }
+
+ // printf("Syncing disks.\n");
+ sync();
+ sleep(4); /* for sync() */
+
+ if (i < 0) {
+ error(saved_errno, "Re-read of partition table failed");
+ printf("Reboot your system to ensure the "
+ "partition table is updated.\n");
+ }
+#endif
+ rtn_value = 1;
+ }
+ return rtn_value;
+}
+
+
+#pragma mark -
+
+
+FILE_MEDIA_ITERATOR
+new_file_iterator(void)
+{
+ return (FILE_MEDIA_ITERATOR) new_media_iterator(sizeof(struct file_media_iterator));
+}
+
+
+MEDIA_ITERATOR
+create_file_iterator(void)
+{
+ FILE_MEDIA_ITERATOR a;
+
+ if (file_inited == 0) {
+ file_init();
+ }
+
+ a = new_file_iterator();
+ if (a != 0) {
+ a->m.kind = file_info.kind;
+ a->m.state = kInit;
+ a->m.do_reset = reset_file_iterator;
+ a->m.do_step = step_file_iterator;
+ a->m.do_delete = delete_file_iterator;
+ a->style = 0;
+ a->index = 0;
+ }
+
+ return (MEDIA_ITERATOR) a;
+}
+
+
+void
+reset_file_iterator(MEDIA_ITERATOR m)
+{
+ FILE_MEDIA_ITERATOR a;
+
+ a = (FILE_MEDIA_ITERATOR) m;
+ if (a == 0) {
+ /* no media */
+ } else if (a->m.kind != file_info.kind) {
+ /* wrong kind - XXX need to error here - this is an internal problem */
+ } else if (a->m.state != kInit) {
+ a->m.state = kReset;
+ }
+}
+
+
+char *
+step_file_iterator(MEDIA_ITERATOR m)
+{
+ FILE_MEDIA_ITERATOR a;
+ char *result;
+ struct stat info;
+
+ a = (FILE_MEDIA_ITERATOR) m;
+ if (a == 0) {
+ /* no media */
+ } else if (a->m.kind != file_info.kind) {
+ /* wrong kind - XXX need to error here - this is an internal problem */
+ } else {
+ switch (a->m.state) {
+ case kInit:
+ a->m.state = kReset;
+ /* fall through to reset */
+ case kReset:
+ a->style = 0 /* first style */;
+ a->index = 0 /* first index */;
+ a->m.state = kIterating;
+ /* fall through to iterate */
+ case kIterating:
+ while (1) {
+ if (a->style > kMaxStyle) {
+ break;
+ }
+#ifndef notdef
+ /* if old version of mklinux then skip CD drive */
+ if (a->style == kSCSI_Disks && a->index == 3) {
+ a->index += 1;
+ }
+#endif
+ /* generate result */
+ result = (char *) malloc(20);
+ if (result != NULL) {
+ /*
+ * for DR3 we should actually iterate through:
+ *
+ * /dev/sd[a...] # first missing is end of list
+ * /dev/hd[a...] # may be holes in sequence
+ * /dev/scd[0...] # first missing is end of list
+ *
+ * and stop in each group when either a stat of
+ * the name fails or if an open fails (except opens
+ * will fail if you run not as root)
+ */
+ switch (a->style) {
+ case kSCSI_Disks:
+ sprintf(result, "/dev/sd%c", 'a'+(int)a->index);
+ break;
+ case kATA_Devices:
+ sprintf(result, "/dev/hd%c", 'a'+(int)a->index);
+ break;
+ case kSCSI_CDs:
+ sprintf(result, "/dev/scd%c", '0'+(int)a->index);
+ break;
+ }
+ if (stat(result, &info) < 0) {
+ a->style += 1; /* next style */
+ a->index = 0; /* first index again */
+ free(result);
+ continue;
+ }
+ }
+
+ a->index += 1; /* next index */
+ return result;
+ }
+ a->m.state = kEnd;
+ /* fall through to end */
+ case kEnd:
+ default:
+ break;
+ }
+ }
+ return 0 /* no entry */;
+}
+
+
+void
+delete_file_iterator(MEDIA_ITERATOR m)
+{
+ return;
+}