Click here to Skip to main content
11,714,719 members (85,178 online)
Click here to Skip to main content

Magnetic Tape Data Storage. Part 1: Tape Drive - IO Commands

, 12 Sep 2006 CPOL 64.5K 666 29
Rate this:
Please Sign up or sign in to vote.
This article describes the simple way to implement Read/Write operation on tape device

Introduction

This article describes the simple way to implement Read/Write operation on tape device. Attached zip file contains TapeOperator class that exposes Load, Read, Write and Close methods and BlockSize property. All these can be used as part of backup utility.

Step 1 - Configuration

Congratulations, you've bought a tape device and connected it to your PC. Now you can implement simple backup utility in C#. Actually there are three ways to work with your tape:

  1. You can operate it via driver
  2. You can work with it via some management software (if it's provided by the device manufacturer)
  3. And the last, simplest way to do it is to operate it via OS handle. This is our case; I'll show to you how you can operate it via OS handle

It is well known that each external device is interpreted by OS as a file, it's true for tape devices as well. The only thing that you have to find out before we start is the appropriate device file name. Open the device manager Window of your PC and you'll see your tape device under the Tape drives node (see picture 1 below).

Sample screenshot

Picture 1

Perform mouse right click on your tape device node and choose Tape Symbolic Name tab. In this tab you can see tape symbolic name, Tape0 in our example (see Picture 2). This name can be used to create a handle for your device.

Sample screenshot

Picture 2

So the appropriate file name for your device is @file://./Tape0.

Step 2 - Implementation

TapeOperator methods description:

  1. Load: gets as parameter name of your tape device ( "\\.\Tape0"). It creates a handle to the device by CreateFile and performs PrepareTape which executes certain procedures to prepare the given tape for I/O, both methods are part of Win32 API and therefore INTEROP is used to invoke it. Now you have the OS handle for your tape device, and it can be interpreted like a regular file handle, I mean you can open System.IO.FileStream. The only difference is that you can't seek opened FileStream, instead use SetTapePosition Win32 API (see read and write operations).
    /// <summary>
    /// Loads tape with given name. 
    /// </summary>
    
    public void Load( string tapeName )
    {
        // Try to open the file.
        
        m_handleValue = CreateFile(
            tapeName,
            GENERIC_READ | GENERIC_WRITE,
            0,
            IntPtr.Zero,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_ARCHIVE | FILE_FLAG_BACKUP_SEMANTICS,
            IntPtr.Zero
            );
        if ( m_handleValue.IsInvalid )
        {
            throw new TapeOperatorWin32Exception(
                "CreateFile", Marshal.GetLastWin32Error() );
        }
        // Load the tape
        
        int result = PrepareTape(
            m_handleValue,
            TAPE_LOAD,
            TRUE
            );
        if ( result != NO_ERROR )
        {
            throw new TapeOperatorWin32Exception(
                 "PrepareTape", Marshal.GetLastWin32Error() );
        }
        m_stream = new FileStream(
            m_handleValue,
            FileAccess.ReadWrite,
            65536,
            false
            );
    }
  2. Write: gets the start position and byte array to write. As it was shown, now you can access your tape device via the opened FileStream. Just invoke FileStrem.Write and FileSream.Flush methods. One thing you have to remember, all I/O operations on tape must be done in multiplies of block size. Each device has min, default and max block sizes (in my example I've used default block size - 65536), these values can be fetched by GetTapeParameters method (Win32 API), for more information, see BlockSize property implementation.
    /// <summary>
    /// Writes to the tape given stream starting from given position
    /// </summary>
    /// <param name="startPos"></param>
    /// <param name="stream"></param>
    
    public void Write( long startPos, byte[] stream )
    {
        // Get number of blocks that will be needed to perform write
        
        uint numberOfBlocks = GetBlocksNumber( stream.Length );
        // Updates tape's current position
        
        SetTapePosition( startPos );
        
        byte[] arrayToWrite = new byte[ numberOfBlocks * BlockSize ];
        Array.Copy( stream, arrayToWrite, stream.Length );
        // Write data to the device
        
        m_stream.Write( stream, 0, stream.Length );
        m_stream.Flush();
    }
  3. Read: gets the start positions and number of bytes to read.

    *By the way, pay attention on SetTapePosition (Win32 API) last parameter, it's type is BOOL in WIN32 definition. Don't pass .NET Boolean type for BOOL and BOOLEAN of WIN32. The size of .NET Boolean is 2 bytes, the size of BOOL is 4 bytes and size of BOOLEAN is 1 byte, therefore each Win32 API method with BOOL or BO<code>OLEAN parameter will return error for .NET Boolean pass attempt.

    /// <summary>
    /// Read one logical block from tape 
    /// starting on the given position
    /// </summary>
    /// <returns></returns>
    
    public byte[] Read( long startPosition )
    {
        byte[] buffer = new byte[ BlockSize ];
        SetTapePosition( startPosition );
        
        m_stream.Read( buffer, 0, buffer.Length );
        m_stream.Flush();
        return buffer;
    }
  4. Close: closes the stream and releases unmanaged resources. You can add to this code call to LoadTape with TAPE_UNLOAD parameter to eject tape from drive.
    /// <summary>
    /// Closes handler of the current tape
    /// </summary>
    
    public void Close()
    {
        if ( m_handleValue != null &&
            !m_handleValue.IsInvalid &&
            !m_handleValue.IsClosed )
        {
            m_handleValue.Close();
        }
    }
  5. BlockSize: This property returns the tape's default block size by invocation of GetTapeParameters method. One of the GetTapeParameters is a reference to the structure that is filled by Win32 method. So Marshal class is used to allocate unmanaged memory and copy between managed and unmanaged structures. See the source code below:
    /// <summary>
    /// Returns default block size for current
    /// device
    /// </summary>
    public uint BlockSize
    {
        get
        {
            IntPtr ptr = IntPtr.Zero;
            try
            {
                if ( !m_driveInfo.HasValue )
                {
                    m_driveInfo = new DriveInfo();
                    // Allocate unmanaged memory
                    
                    int size = Marshal.SizeOf( m_driveInfo );
                    ptr = Marshal.AllocHGlobal( size );
                    Marshal.StructureToPtr(
                        m_driveInfo,
                        ptr,
                        false
                    );
                    
                    int result = 0;
                    if ( ( result = GetTapeParameters(
                        m_handleValue,
                        DRIVE_PARAMS,
                        ref size,
                        ptr ) ) != NO_ERROR )
                    {
                        throw new TapeOperatorWin32Exception(
                            "GetTapeParameters", 
                            Marshal.GetLastWin32Error() );    
                    }
                    // Get managed media Info
                    
                    m_driveInfo = ( DriveInfo )
                        Marshal.PtrToStructure
                ( ptr, typeof( DriveInfo ) );
                }
                
                return m_driveInfo.Value.DefaultBlockSize;
            }
            finally
            {
                if ( ptr != IntPtr.Zero )
                {
                    Marshal.FreeHGlobal( ptr );
                }
            }
        }
  6. See attached files for more information about defined constants, private variables, private methods and PINVOKE declarations.
  7. Good luck!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Dima Statz
Retired
Israel Israel
Name: Statz Dima
Fields of interest: software

You may also be interested in...

Comments and Discussions

 
QuestionFix for Handle does not support synchronous operations Pin
Member 1165305520-Aug-15 14:19
memberMember 1165305520-Aug-15 14:19 
QuestionTape Designated position read and write? Pin
lsyfg14-Jan-13 2:09
memberlsyfg14-Jan-13 2:09 
QuestionTape Designated position read and write? Pin
lsyfg7-Jan-13 19:48
memberlsyfg7-Jan-13 19:48 
QuestionRead data error(Have more data can be read) Pin
lsyfg19-Nov-12 13:59
memberlsyfg19-Nov-12 13:59 
Questionresult GetTapeMediaParameters and read/ write problem Pin
seyed ali ehbali20-May-12 2:18
memberseyed ali ehbali20-May-12 2:18 
QuestionHelp in read, write and exchange method Pin
seyed ali ehbali19-May-12 22:59
memberseyed ali ehbali19-May-12 22:59 
QuestionSynchronous read exceptions Pin
jo3162-Aug-11 8:24
memberjo3162-Aug-11 8:24 
AnswerRe: Synchronous read exceptions Pin
billl papan20-Jan-12 12:47
memberbilll papan20-Jan-12 12:47 
GeneralMicrosoft Tape Format Pin
rafaelverisys26-Apr-11 8:26
memberrafaelverisys26-Apr-11 8:26 
QuestionWrite to blank tape Pin
kk wan15-Dec-10 16:25
memberkk wan15-Dec-10 16:25 
AnswerRe: Write to blank tape Pin
Dima Statsenko16-Dec-10 1:23
memberDima Statsenko16-Dec-10 1:23 
GeneralRe: Write to blank tape Pin
kk wan16-Dec-10 17:50
memberkk wan16-Dec-10 17:50 
GeneralRe: Write to blank tape Pin
Dima Statsenko19-Dec-10 0:09
memberDima Statsenko19-Dec-10 0:09 
GeneralSlow with large file Pin
kk wan12-Dec-10 14:55
memberkk wan12-Dec-10 14:55 
GeneralRe: Slow with large file Pin
Dima Statsenko15-Dec-10 2:52
memberDima Statsenko15-Dec-10 2:52 
QuestionIO operation will not work. Most likely the file will become too long or the handle was not opened to support synchronous IO operations. Pin
Blakey66627-Aug-10 1:44
memberBlakey66627-Aug-10 1:44 
AnswerRe: IO operation will not work. Most likely the file will become too long or the handle was not opened to support synchronous IO operations. Pin
Dima_sta26-Sep-10 3:01
memberDima_sta26-Sep-10 3:01 
GeneralQuestion About Write Operation in Code Pin
ozbear17-Jan-10 19:59
memberozbear17-Jan-10 19:59 
GeneralRe: Question About Write Operation in Code Pin
Dima_sta26-Sep-10 3:02
memberDima_sta26-Sep-10 3:02 
GeneralRegarding tapedrive read/write operation Pin
prabhakarsangisetty5-Jul-09 23:56
memberprabhakarsangisetty5-Jul-09 23:56 
GeneralTape Barcode Pin
Venu Tam12-Jun-09 3:31
memberVenu Tam12-Jun-09 3:31 
GeneralRe: Tape Barcode Pin
Dima_sta26-Sep-10 3:13
memberDima_sta26-Sep-10 3:13 
QuestionAny news on the synchronous / asynchronous front? Pin
hausschuh21-Feb-09 2:50
memberhausschuh21-Feb-09 2:50 
AnswerRe: Any news on the synchronous / asynchronous front? Pin
Dima_sta26-Sep-10 3:14
memberDima_sta26-Sep-10 3:14 
General"When accessing a new tape of a multivolume partition, the current block size is incorrect" Pin
jmbillings20-Oct-08 22:50
memberjmbillings20-Oct-08 22:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150819.1 | Last Updated 12 Sep 2006
Article Copyright 2006 by Dima Statz
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid