📄 zftape-vtbl.c
字号:
/* * Copyright (c) 1995-1997 Claus-Justus Heine 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: /homes/cvs/ftape-stacked/ftape/zftape/zftape-vtbl.c,v $ * $Revision: 1.7.6.1 $ * $Date: 1997/11/24 13:48:31 $ * * This file defines a volume table as defined in various QIC * standards. * * This is a minimal implementation, just allowing ordinary DOS * :( prgrams to identify the cartridge as used. */#include <linux/errno.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/zftape.h>#include "../zftape/zftape-init.h"#include "../zftape/zftape-eof.h"#include "../zftape/zftape-ctl.h"#include "../zftape/zftape-write.h"#include "../zftape/zftape-read.h"#include "../zftape/zftape-rw.h"#include "../zftape/zftape-vtbl.h"#define ZFT_CMAP_HACK /* leave this defined to hide the compression map *//* * global variables */int zft_qic_mode = 1; /* use the vtbl */int zft_old_ftape; /* prevents old ftaped tapes to be overwritten */int zft_volume_table_changed; /* for write_header_segments() *//* * private variables (only exported for inline functions) */LIST_HEAD(zft_vtbl);/* We could also allocate these dynamically when extracting the volume table * sizeof(zft_volinfo) is about 32 or something close to that */static zft_volinfo tape_vtbl;static zft_volinfo eot_vtbl;static zft_volinfo *cur_vtbl;static inline void zft_new_vtbl_entry(void){ struct list_head *tmp = &zft_last_vtbl->node; zft_volinfo *new = zft_kmalloc(sizeof(zft_volinfo)); list_add(&new->node, tmp); new->count = zft_eom_vtbl->count ++;}void zft_free_vtbl(void){ for (;;) { struct list_head *tmp = zft_vtbl.prev; zft_volinfo *vtbl; if (tmp == &zft_vtbl) break; list_del(tmp); vtbl = list_entry(tmp, zft_volinfo, node); zft_kfree(vtbl, sizeof(zft_volinfo)); } INIT_LIST_HEAD(&zft_vtbl); cur_vtbl = NULL;}/* initialize vtbl, called by ftape_new_cartridge() */void zft_init_vtbl(void){ zft_volinfo *new; zft_free_vtbl(); /* Create the two dummy vtbl entries */ new = zft_kmalloc(sizeof(zft_volinfo)); list_add(&new->node, &zft_vtbl); new = zft_kmalloc(sizeof(zft_volinfo)); list_add(&new->node, &zft_vtbl); zft_head_vtbl->end_seg = ft_first_data_segment; zft_head_vtbl->blk_sz = zft_blk_sz; zft_head_vtbl->count = -1; zft_eom_vtbl->start_seg = ft_first_data_segment + 1; zft_eom_vtbl->end_seg = ft_last_data_segment + 1; zft_eom_vtbl->blk_sz = zft_blk_sz; zft_eom_vtbl->count = 0; /* Reset the pointer for zft_find_volume() */ cur_vtbl = zft_eom_vtbl; /* initialize the dummy vtbl entries for zft_qic_mode == 0 */ eot_vtbl.start_seg = ft_last_data_segment + 1; eot_vtbl.end_seg = ft_last_data_segment + 1; eot_vtbl.blk_sz = zft_blk_sz; eot_vtbl.count = -1; tape_vtbl.start_seg = ft_first_data_segment; tape_vtbl.end_seg = ft_last_data_segment; tape_vtbl.blk_sz = zft_blk_sz; tape_vtbl.size = zft_capacity; tape_vtbl.count = 0;}/* check for a valid VTBL signature. */static int vtbl_signature_valid(__u8 signature[4]){ const char *vtbl_ids[] = VTBL_IDS; /* valid signatures */ int j; for (j = 0; (j < NR_ITEMS(vtbl_ids)) && (memcmp(signature, vtbl_ids[j], 4) != 0); j++); return j < NR_ITEMS(vtbl_ids);}/* We used to store the block-size of the volume in the volume-label, * using the keyword "blocksize". The blocksize written to the * volume-label is in bytes. * * We use this now only for compatibility with old zftape version. We * store the blocksize directly as binary number in the vendor * extension part of the volume entry. */static int check_volume_label(const char *label, int *blk_sz){ int valid_format; char *blocksize; TRACE_FUN(ft_t_flow); TRACE(ft_t_noise, "called with \"%s\" / \"%s\"", label, ZFT_VOL_NAME); if (strncmp(label, ZFT_VOL_NAME, strlen(ZFT_VOL_NAME)) != 0) { *blk_sz = 1; /* smallest block size that we allow */ valid_format = 0; } else { TRACE(ft_t_noise, "got old style zftape vtbl entry"); /* get the default blocksize */ /* use the kernel strstr() */ blocksize= strstr(label, " blocksize "); if (blocksize) { blocksize += strlen(" blocksize "); for(*blk_sz= 0; *blocksize >= '0' && *blocksize <= '9'; blocksize++) { *blk_sz *= 10; *blk_sz += *blocksize - '0'; } if (*blk_sz > ZFT_MAX_BLK_SZ) { *blk_sz= 1; valid_format= 0; } else { valid_format = 1; } } else { *blk_sz= 1; valid_format= 0; } } TRACE_EXIT valid_format;}/* check for a zftape volume */static int check_volume(__u8 *entry, zft_volinfo *volume){ TRACE_FUN(ft_t_flow); if(strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, strlen(ZFTAPE_SIG)) == 0) { TRACE(ft_t_noise, "got new style zftape vtbl entry"); volume->blk_sz = GET2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ); volume->qic113 = entry[VTBL_EXT+EXT_ZFTAPE_QIC113]; TRACE_EXIT 1; } else { TRACE_EXIT check_volume_label(&entry[VTBL_DESC], &volume->blk_sz); }}/* create zftape specific vtbl entry, the volume bounds are inserted * in the calling function, zft_create_volume_headers() */static void create_zft_volume(__u8 *entry, zft_volinfo *vtbl){ TRACE_FUN(ft_t_flow); memset(entry, 0, VTBL_SIZE); memcpy(&entry[VTBL_SIG], VTBL_ID, 4); sprintf(&entry[VTBL_DESC], ZFT_VOL_NAME" %03d", vtbl->count); entry[VTBL_FLAGS] = (VTBL_FL_NOT_VERIFIED | VTBL_FL_SEG_SPANNING); entry[VTBL_M_NO] = 1; /* multi_cartridge_count */ strcpy(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG); PUT2(entry, VTBL_EXT+EXT_ZFTAPE_BLKSZ, vtbl->blk_sz); if (zft_qic113) { PUT8(entry, VTBL_DATA_SIZE, vtbl->size); entry[VTBL_CMPR] = VTBL_CMPR_UNREG; if (vtbl->use_compression) { /* use compression: */ entry[VTBL_CMPR] |= VTBL_CMPR_USED; } entry[VTBL_EXT+EXT_ZFTAPE_QIC113] = 1; } else { PUT4(entry, VTBL_DATA_SIZE, vtbl->size); entry[VTBL_K_CMPR] = VTBL_CMPR_UNREG; if (vtbl->use_compression) { /* use compression: */ entry[VTBL_K_CMPR] |= VTBL_CMPR_USED; } } if (ft_format_code == fmt_big) { /* SCSI like vtbl, store the number of used * segments as 4 byte value */ PUT4(entry, VTBL_SCSI_SEGS, vtbl->end_seg-vtbl->start_seg + 1); } else { /* normal, QIC-80MC like vtbl */ PUT2(entry, VTBL_START, vtbl->start_seg); PUT2(entry, VTBL_END, vtbl->end_seg); } TRACE_EXIT;}/* this one creates the volume headers for each volume. It is assumed * that buffer already contains the old volume-table, so that vtbl * entries without the zft_volume flag set can savely be ignored. */static void zft_create_volume_headers(__u8 *buffer){ __u8 *entry; struct list_head *tmp; zft_volinfo *vtbl; TRACE_FUN(ft_t_flow); #ifdef ZFT_CMAP_HACK if((strncmp(&buffer[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, strlen(ZFTAPE_SIG)) == 0) && buffer[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) { TRACE(ft_t_noise, "deleting cmap volume"); memmove(buffer, buffer + VTBL_SIZE, FT_SEGMENT_SIZE - VTBL_SIZE); }#endif entry = buffer; for (tmp = zft_head_vtbl->node.next; tmp != &zft_eom_vtbl->node; tmp = tmp->next) { vtbl = list_entry(tmp, zft_volinfo, node); /* we now fill in the values only for newly created volumes. */ if (vtbl->new_volume) { create_zft_volume(entry, vtbl); vtbl->new_volume = 0; /* clear the flag */ } DUMP_VOLINFO(ft_t_noise, &entry[VTBL_DESC], vtbl); entry += VTBL_SIZE; } memset(entry, 0, FT_SEGMENT_SIZE - zft_eom_vtbl->count * VTBL_SIZE); TRACE_EXIT;}/* write volume table to tape. Calls zft_create_volume_headers() */int zft_update_volume_table(unsigned int segment){ int result = 0; __u8 *verify_buf = NULL; TRACE_FUN(ft_t_flow); TRACE_CATCH(result = ftape_read_segment(ft_first_data_segment, zft_deblock_buf, FT_RD_SINGLE),); zft_create_volume_headers(zft_deblock_buf); TRACE(ft_t_noise, "writing volume table segment %d", segment); if (zft_vmalloc_once(&verify_buf, FT_SEGMENT_SIZE) == 0) { TRACE_CATCH(zft_verify_write_segments(segment, zft_deblock_buf, result, verify_buf), zft_vfree(&verify_buf, FT_SEGMENT_SIZE)); zft_vfree(&verify_buf, FT_SEGMENT_SIZE); } else { TRACE_CATCH(ftape_write_segment(segment, zft_deblock_buf, FT_WR_SINGLE),); } TRACE_EXIT 0;}/* non zftape volumes are handled in raw mode. Thus we need to * calculate the raw amount of data contained in those segments. */static void extract_alien_volume(__u8 *entry, zft_volinfo *vtbl){ TRACE_FUN(ft_t_flow); vtbl->size = (zft_calc_tape_pos(zft_last_vtbl->end_seg+1) - zft_calc_tape_pos(zft_last_vtbl->start_seg)); vtbl->use_compression = 0; vtbl->qic113 = zft_qic113; if (vtbl->qic113) { TRACE(ft_t_noise, "Fake alien volume's size from " LL_X " to " LL_X, LL(GET8(entry, VTBL_DATA_SIZE)), LL(vtbl->size)); } else { TRACE(ft_t_noise, "Fake alien volume's size from %d to " LL_X, (int)GET4(entry, VTBL_DATA_SIZE), LL(vtbl->size)); } TRACE_EXIT;}/* extract an zftape specific volume */static void extract_zft_volume(__u8 *entry, zft_volinfo *vtbl){ TRACE_FUN(ft_t_flow); if (vtbl->qic113) { vtbl->size = GET8(entry, VTBL_DATA_SIZE); vtbl->use_compression = (entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0; } else { vtbl->size = GET4(entry, VTBL_DATA_SIZE); if (entry[VTBL_K_CMPR] & VTBL_CMPR_UNREG) { vtbl->use_compression = (entry[VTBL_K_CMPR] & VTBL_CMPR_USED) != 0; } else if (entry[VTBL_CMPR] & VTBL_CMPR_UNREG) { vtbl->use_compression = (entry[VTBL_CMPR] & VTBL_CMPR_USED) != 0; } else { TRACE(ft_t_warn, "Geeh! There is something wrong:\n" KERN_INFO "QIC compression (Rev = K): %x\n" KERN_INFO "QIC compression (Rev > K): %x", entry[VTBL_K_CMPR], entry[VTBL_CMPR]); } } TRACE_EXIT;}/* extract the volume table from buffer. "buffer" must already contain * the vtbl-segment */int zft_extract_volume_headers(__u8 *buffer){ __u8 *entry; TRACE_FUN(ft_t_flow); zft_init_vtbl(); entry = buffer;#ifdef ZFT_CMAP_HACK if ((strncmp(&entry[VTBL_EXT+EXT_ZFTAPE_SIG], ZFTAPE_SIG, strlen(ZFTAPE_SIG)) == 0) && entry[VTBL_EXT+EXT_ZFTAPE_CMAP] != 0) { TRACE(ft_t_noise, "ignoring cmap volume"); entry += VTBL_SIZE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -