4 * Written by Eryk Vershen
8 * Copyright 1997,1998 by Apple Computer, Inc.
11 * Permission to use, copy, modify, and distribute this software and
12 * its documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appears in all copies and
14 * that both the copyright notice and this permission notice appear in
15 * supporting documentation.
17 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE.
21 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
22 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
23 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
24 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
25 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 // for malloc() & free()
32 // for lseek(), read(), write(), close()
42 #include <sys/ioctl.h>
44 #include <linux/hdreg.h>
48 #include <sys/ioctl.h>
53 #include "file_media.h"
61 #define LOFF_MAX 9223372036854775807LL
62 extern __loff_t llseek
__P ((int __fd
, __loff_t __offset
, int __whence
));
63 #elif defined(__NetBSD__) || defined(__APPLE__)
66 #define LOFF_MAX LLONG_MAX
70 #define LOFF_MAX LONG_MAX
77 typedef struct file_media
*FILE_MEDIA
;
85 struct file_media_globals
{
90 typedef struct file_media_iterator
*FILE_MEDIA_ITERATOR
;
92 struct file_media_iterator
{
93 struct media_iterator m
;
102 int potential_block_sizes
[] = {
118 static long file_inited
= 0;
119 static struct file_media_globals file_info
;
122 * Forward declarations
124 int compute_block_size(int fd
);
125 void file_init(void);
126 FILE_MEDIA
new_file_media(void);
127 long read_file_media(MEDIA m
, long long offset
, unsigned long count
, void *address
);
128 long write_file_media(MEDIA m
, long long offset
, unsigned long count
, void *address
);
129 long close_file_media(MEDIA m
);
130 long os_reload_file_media(MEDIA m
);
131 FILE_MEDIA_ITERATOR
new_file_iterator(void);
132 void reset_file_iterator(MEDIA_ITERATOR m
);
133 char *step_file_iterator(MEDIA_ITERATOR m
);
134 void delete_file_iterator(MEDIA_ITERATOR m
);
143 if (file_inited
!= 0) {
148 file_info
.kind
= allocate_media_kind();
155 return (FILE_MEDIA
) new_media(sizeof(struct file_media
));
160 compute_block_size(int fd
)
171 size
= potential_block_sizes
[i
];
175 if (max_size
< size
) {
180 buffer
= malloc(max_size
);
183 size
= potential_block_sizes
[i
];
187 if ((x
= llseek(fd
, (loff_t
)0, 0)) < 0) {
188 error(errno
, "Can't seek on file");
191 if ((t
= read(fd
, buffer
, size
)) == size
) {
202 open_file_as_media(char *file
, int oflag
)
207 #if defined(__linux__) || defined(__unix__)
211 if (file_inited
== 0) {
216 fd
= open(file
, oflag
);
218 a
= new_file_media();
220 a
->m
.kind
= file_info
.kind
;
221 a
->m
.grain
= compute_block_size(fd
);
222 off
= llseek(fd
, (loff_t
)0, 2); /* seek to end of media */
223 #if !defined(__linux__) && !defined(__unix__)
225 off
= 1; /* XXX not right? */
228 //printf("file size = %Ld\n", off);
229 a
->m
.size_in_bytes
= (long long) off
;
230 a
->m
.do_read
= read_file_media
;
231 a
->m
.do_write
= write_file_media
;
232 a
->m
.do_close
= close_file_media
;
233 a
->m
.do_os_reload
= os_reload_file_media
;
236 #if defined(__linux__) || defined(__unix__)
237 if (fstat(fd
, &info
) < 0) {
238 error(errno
, "can't stat file '%s'", file
);
240 a
->regular_file
= S_ISREG(info
.st_mode
);
252 read_file_media(MEDIA m
, long long offset
, unsigned long count
, void *address
)
263 fprintf(stderr
,"no media\n");
264 } else if (a
->m
.kind
!= file_info
.kind
) {
265 /* wrong kind - XXX need to error here - this is an internal problem */
266 fprintf(stderr
,"wrong kind\n");
267 } else if (count
<= 0 || count
% a
->m
.grain
!= 0) {
268 /* can't handle size */
269 fprintf(stderr
,"bad size\n");
270 } else if (offset
< 0 || offset
% a
->m
.grain
!= 0) {
271 /* can't handle offset */
272 fprintf(stderr
,"bad offset\n");
273 } else if (offset
+ count
> a
->m
.size_in_bytes
&& a
->m
.size_in_bytes
!= (long long) 0) {
274 /* check for offset (and offset+count) too large */
275 fprintf(stderr
,"offset+count too large\n");
276 } else if (offset
+ count
> (long long) LOFF_MAX
) {
277 /* check for offset (and offset+count) too large */
278 fprintf(stderr
,"offset+count too large 2\n");
282 if ((off
= llseek(a
->fd
, off
, 0)) >= 0) {
283 if ((t
= read(a
->fd
, address
, count
)) == (ssize_t
)count
) {
286 fprintf(stderr
,"read failed\n");
289 fprintf(stderr
,"lseek failed\n");
297 write_file_media(MEDIA m
, long long offset
, unsigned long count
, void *address
)
308 } else if (a
->m
.kind
!= file_info
.kind
) {
309 /* wrong kind - XXX need to error here - this is an internal problem */
310 } else if (count
<= 0 || count
% a
->m
.grain
!= 0) {
311 /* can't handle size */
312 } else if (offset
< 0 || offset
% a
->m
.grain
!= 0) {
313 /* can't handle offset */
314 } else if (offset
+ count
> (long long) LOFF_MAX
) {
315 /* check for offset (and offset+count) too large */
319 if ((off
= llseek(a
->fd
, off
, 0)) >= 0) {
320 if ((t
= write(a
->fd
, address
, count
)) == (ssize_t
)count
) {
321 if (off
+ count
> a
->m
.size_in_bytes
) {
322 a
->m
.size_in_bytes
= off
+ count
;
333 close_file_media(MEDIA m
)
340 } else if (a
->m
.kind
!= file_info
.kind
) {
341 /* XXX need to error here - this is an internal problem */
351 os_reload_file_media(MEDIA m
)
355 #if defined(__linux__)
364 } else if (a
->m
.kind
!= file_info
.kind
) {
365 /* wrong kind - XXX need to error here - this is an internal problem */
366 } else if (a
->regular_file
) {
367 /* okay - nothing to do */
373 if ((i
= ioctl(a
->fd
, BLKRRPART
)) != 0) {
376 // some kernel versions (1.2.x) seem to have trouble
377 // rereading the partition table, but if asked to do it
378 // twice, the second time works. - biro@yggdrasil.com */
381 if ((i
= ioctl(a
->fd
, BLKRRPART
)) != 0) {
386 // printf("Syncing disks.\n");
388 sleep(4); /* for sync() */
391 error(saved_errno
, "Re-read of partition table failed");
392 printf("Reboot your system to ensure the "
393 "partition table is updated.\n");
402 #if !defined(__linux__) && !defined(__unix__)
408 new_file_iterator(void)
410 return (FILE_MEDIA_ITERATOR
) new_media_iterator(sizeof(struct file_media_iterator
));
415 create_file_iterator(void)
417 FILE_MEDIA_ITERATOR a
;
419 if (file_inited
== 0) {
423 a
= new_file_iterator();
425 a
->m
.kind
= file_info
.kind
;
427 a
->m
.do_reset
= reset_file_iterator
;
428 a
->m
.do_step
= step_file_iterator
;
429 a
->m
.do_delete
= delete_file_iterator
;
434 return (MEDIA_ITERATOR
) a
;
439 reset_file_iterator(MEDIA_ITERATOR m
)
441 FILE_MEDIA_ITERATOR a
;
443 a
= (FILE_MEDIA_ITERATOR
) m
;
446 } else if (a
->m
.kind
!= file_info
.kind
) {
447 /* wrong kind - XXX need to error here - this is an internal problem */
448 } else if (a
->m
.state
!= kInit
) {
455 step_file_iterator(MEDIA_ITERATOR m
)
457 FILE_MEDIA_ITERATOR a
;
464 a
= (FILE_MEDIA_ITERATOR
) m
;
467 } else if (a
->m
.kind
!= file_info
.kind
) {
468 /* wrong kind - XXX need to error here - this is an internal problem */
470 switch (a
->m
.state
) {
473 /* fall through to reset */
475 a
->style
= 0 /* first style */;
476 a
->index
= 0 /* first index */;
477 a
->m
.state
= kIterating
;
478 /* fall through to iterate */
481 if (a
->style
> kMaxStyle
) {
485 /* if old version of mklinux then skip CD drive */
486 if (a
->style
== kSCSI_Disks
&& a
->index
== 3) {
490 /* generate result */
491 result
= (char *) malloc(20);
492 if (result
!= NULL
) {
494 * for DR3 we should actually iterate through:
496 * /dev/sd[a...] # first missing is end of list
497 * /dev/hd[a...] # may be holes in sequence
498 * /dev/scd[0...] # first missing is end of list
500 * and stop in each group when either a stat of
501 * the name fails or if an open fails for
502 * particular reasons.
505 value
= (int) a
->index
;
509 snprintf(result
, 20, "/dev/sd%c", 'a'+value
);
510 } else if (value
< 676) {
511 snprintf(result
, 20, "/dev/sd%c%c",
520 snprintf(result
, 20, "/dev/hd%c", 'a'+value
);
527 snprintf(result
, 20, "/dev/scd%c", '0'+value
);
534 // already set don't even check
535 } else if (stat(result
, &info
) < 0) {
537 } else if ((fd
= open(result
, O_RDONLY
)) >= 0) {
539 #if defined(__linux__) || defined(__unix__)
540 } else if (errno
== ENXIO
|| errno
== ENODEV
) {
541 if (a
->style
== kATA_Devices
) {
550 a
->style
+= 1; /* next style */
551 a
->index
= 0; /* first index again */
553 a
->index
+= 1; /* next index */
560 a
->index
+= 1; /* next index */
564 /* fall through to end */
570 return 0 /* no entry */;
575 delete_file_iterator(MEDIA_ITERATOR m
)