📄 ftape-eof.c
字号:
/* * Copyright (C) 1994-1995 Bas Laarhoven. 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 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. $Source: /usr/local/cvsroot/AplioTRIO/linux/drivers/char/ftape/ftape-eof.c,v $ $Author: vadim $ * $Revision: 1.1.1.1 $ $Date: 1999/11/15 13:41:57 $ $State: Exp $ * * This file contains the eof mark handling code * for the QIC-40/80 floppy-tape driver for Linux. */#include <linux/ftape.h>#include <linux/string.h>#include <linux/errno.h>#include "tracing.h"#include "ftape-eof.h"#include "ftape-write.h"#include "ftape-read.h"#include "ftape-rw.h"#include "ftape-ctl.h"#include "ftape-bsm.h"/* Global vars. */int failed_sector_log_changed = 0;int eof_mark = 0;/* Local vars. */static struct failed_sector_entry { unsigned short segment; unsigned short sector;} *eof_mark_ptr;typedef union { struct failed_sector_entry mark; unsigned long entry;} eof_mark_union;/* a copy of the failed sector log from the header segment. */static eof_mark_union eof_map[(2048 - 256) / 4];/* index into eof_map table pointing to last found eof mark. */static int eof_index;/* number of eof marks (entries in bad sector log) on tape. */static int nr_of_eof_marks = -1;static char linux_tape_label[] = "Linux raw format V";enum { min_fmt_version = 1, max_fmt_version = 2};static unsigned ftape_fmt_version = 0;/* Ftape (mis)uses the bad sector log to record end-of-file marks. * Initially (when the tape is erased) all entries in the bad sector * log are added to the tape's bad sector map. The bad sector log * then is cleared. * * The bad sector log normally contains entries of the form: * even 16-bit word: segment number of bad sector * odd 16-bit word: encoded date * There can be a total of 448 entries (1792 bytes). * * My guess is that no program is using this bad sector log (the * format seems useless as there is no indication of the bad sector * itself, only the segment) * However, if any program does use the bad sector log, the format * used by ftape will let the program think there are some bad sectors * and no harm is done. * * The eof mark entries that ftape stores in the bad sector log: * even 16-bit word: segment number of eof mark * odd 16-bit word: sector number of eof mark [1..32] * * The eof_map as maintained is a sorted list of eof mark entries. * * * The tape name field in the header segments is used to store a * linux tape identification string and a version number. * This way the tape can be recognized as a Linux raw format * tape when using tools under other OS's. * * 'Wide' QIC tapes (format code 4) don't have a failed sector list * anymore. That space is used for the (longer) bad sector map that * now is a variable length list too. * We now store our end-of-file marker list after the bad-sector-map * on tape. The list is delimited by a (long) 0 entry. */int ftape_validate_label(char *label){ TRACE_FUN(8, "ftape_validate_label"); int result = 0; TRACEx1(4, "tape label = `%s'", label); ftape_fmt_version = 0; if (memcmp(label, linux_tape_label, strlen(linux_tape_label)) == 0) { int pos = strlen(linux_tape_label); while (label[pos] >= '0' && label[pos] <= '9') { ftape_fmt_version *= 10; ftape_fmt_version = label[pos++] - '0'; } result = (ftape_fmt_version >= min_fmt_version && ftape_fmt_version <= max_fmt_version); } TRACEx1(4, "format version = %d", ftape_fmt_version); TRACE_EXIT; return result;}static byte * find_end_of_eof_list(byte * ptr, byte * limit){ while (ptr + 3 < limit) { if (*(unsigned long *) ptr) { ++(unsigned long *) ptr; } else { return ptr; } } return NULL;}void reset_eof_list(void){ TRACE_FUN(8, "reset_eof_list"); eof_mark_ptr = &eof_map[0].mark; eof_index = 0; eof_mark = 0; TRACE_EXIT;}/* Test if `segment' has an eof mark set (optimized for sequential access). * return 0 if not eof mark or sector number (> 0) if eof mark set. */int check_for_eof(unsigned segment){ TRACE_FUN(8, "check_for_eof"); static unsigned last_reference = INT_MAX; int result; if (segment < last_reference) { reset_eof_list(); } last_reference = segment; while (eof_index < nr_of_eof_marks && segment > eof_mark_ptr->segment) { ++eof_mark_ptr; ++eof_index; } if (eof_index < nr_of_eof_marks && segment == eof_mark_ptr->segment) { TRACEx3(5, "hit mark %d/%d at index %d", eof_map[eof_index].mark.segment, eof_map[eof_index].mark.sector, eof_index); if (eof_mark_ptr->sector >= SECTORS_PER_SEGMENT) { TRACEx2(-1, "Bad file mark detected: %d/%d", eof_mark_ptr->segment, eof_mark_ptr->sector); result = 0; /* return bogus (but valid) value */ } else { result = eof_mark_ptr->sector; } } else { result = 0; } TRACE_EXIT; return result;}void clear_eof_mark_if_set(unsigned segment, unsigned byte_count){ TRACE_FUN(5, "clear_eof_mark_if_set"); if (ftape_fmt_version != 0 && check_for_eof(segment) > 0 && byte_count >= eof_mark_ptr->sector * SECTOR_SIZE) { TRACEx3(5, "clearing mark %d/%d at index %d", eof_mark_ptr->segment, eof_mark_ptr->sector, eof_index); memmove(&eof_map[eof_index], &eof_map[eof_index + 1], (nr_of_eof_marks - eof_index) * sizeof(*eof_map)); --nr_of_eof_marks; failed_sector_log_changed = 1; } TRACE_EXIT;}void put_file_mark_in_map(unsigned segment, unsigned sector){ TRACE_FUN(8, "put_file_mark_in_map"); eof_mark_union new; int index; eof_mark_union *ptr; if (ftape_fmt_version != 0) { new.mark.segment = segment; new.mark.sector = sector; for (index = 0, ptr = &eof_map[0]; index < nr_of_eof_marks && ptr->mark.segment < segment; ++index, ++ptr) { } if (index < nr_of_eof_marks) { if (ptr->mark.segment == segment) { /* overwrite */ if (ptr->mark.sector == sector) { TRACEx2(5, "mark %d/%d already exists", new.mark.segment, new.mark.sector); } else { TRACEx5(5, "overwriting %d/%d at index %d with %d/%d", ptr->mark.segment, ptr->mark.sector, index, new.mark.segment, new.mark.sector); ptr->entry = new.entry; failed_sector_log_changed = 1; } } else { /* insert */ TRACEx5(5, "inserting %d/%d at index %d before %d/%d", new.mark.segment, new.mark.sector, index, ptr->mark.segment, ptr->mark.sector); memmove(ptr + 1, ptr, (nr_of_eof_marks - index) * sizeof(*eof_map)); ptr->entry = new.entry; ++nr_of_eof_marks; failed_sector_log_changed = 1; } } else { /* append */ TRACEx3(5, "appending %d/%d at index %d", new.mark.segment, new.mark.sector, index); ptr->entry = new.entry; ++nr_of_eof_marks; failed_sector_log_changed = 1; } } TRACE_EXIT;}/* Write count file marks to tape starting at first non-bad * sector following the given segment and sector. * sector = base 1 ! */int ftape_weof(unsigned count, unsigned segment, unsigned sector){ TRACE_FUN(5, "ftape_weof"); int result = 0; unsigned long mask = get_bad_sector_entry(segment); unsigned sector_nr = 0; if (ftape_fmt_version != 0) { if (sector < 1 || sector > 29 || segment + count >= ftape_last_segment.id) { TRACEx3(5, "parameter out of range: %d, %d, %d", count, segment, sector); result = -EIO; } else { while (count-- > 0) { do { /* count logical sectors */ do { /* skip until good sector */ while (mask & 1) { /* skip bad sectors */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -