📄 devices.c
字号:
/* * Copyright (c) International Business Machines Corp., 2000-2003 * * 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 of the License, 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; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <fcntl.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include "jfs_types.h"#include "jfs_filsys.h"#include <string.h>#include <stdio.h>#include <stdlib.h>#include "devices.h"#include "debug.h"#include <sys/ioctl.h>#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE64)#define BLKGETSIZE64 _IOR(0x12, 114, size_t)#endif#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)#define BLKGETSIZE _IO(0x12,96) /* return device size (sectors) */#endif/* * NAME: ujfs_get_dev_size * * FUNCTION: Uses the device driver interface to determine the raw capacity of * the specified device. * * PRE CONDITIONS: * * POST CONDITIONS: * * PARAMETERS: * device - device * size - filled in with size of device; not modified if failure occurs * * NOTES: * * DATA STRUCTURES: * * RETURNS: 0 if successful; anything else indicates failures */int ujfs_get_dev_size(HFILE device, int64_t *size){ off_t Starting_Position; /* position within file/device upon * entry to this function. */ off_t Current_Position = 16777215; /* position we are attempting * to read from. */ off_t Last_Valid_Position = 0; /* Last position we could successfully * read from. */ off_t First_Invalid_Position; /* first invalid position we attempted * to read from/seek to. */ off_t Seek_Result; /* value returned by lseek. */ size_t Read_Result = 0; /* value returned by read. */ char Test_Byte; /* used to validate a position that we * successfully lseek'ed to. */ int rc; struct stat stat_data; rc = fstat(device, &stat_data); if (!rc && S_ISREG(stat_data.st_mode)) { /* This is a regular file. */ *size = (int64_t) ((stat_data.st_size / 1024) * 1024); return NO_ERROR; }#ifdef BLKGETSIZE64 { uint64_t sz; if (ioctl(device, BLKGETSIZE64, &sz) >= 0) { *size = sz; return 0; } }#endif#ifdef BLKGETSIZE { unsigned long num_sectors = 0; if (ioctl(device, BLKGETSIZE, &num_sectors) >= 0) { /* for now, keep size as multiple of 1024, * * not 512, so eliminate any odd sector. */ *size = PBSIZE * (int64_t) ((num_sectors / 2) * 2); return NO_ERROR; } }#endif /* * If the ioctl above fails or is undefined, use a binary search to * find the last byte in the partition. This works because an lseek to * a position within the partition does not return an error while an * lseek to a position beyond the end of the partition does. Note that * some SCSI drivers may log an 'access beyond end of device' error * message. */ /* Save the starting position so that we can restore it when we are * done! */ Starting_Position = lseek(device, 0, SEEK_CUR); if (Starting_Position < 0) return ERROR_SEEK; /* * Find a position beyond the end of the partition. We will start by * attempting to seek to and read the 16777216th byte in the partition. * We start here because a JFS partition must be at least this big. If * it is not, then we can not format it as JFS. */ do { /* Seek to the location we wish to test. */ Seek_Result = lseek(device, Current_Position, SEEK_SET); if (Seek_Result == Current_Position) { /* Can we read from this location? */ Read_Result = read(device, &Test_Byte, 1); if (Read_Result == 1) { /* The current test position is valid. Save it * for future reference. */ Last_Valid_Position = Current_Position; /* Lets calculate the next location to test. */ Current_Position = ((Current_Position + 1) * 2) - 1; } } } while ((Seek_Result == Last_Valid_Position) && (Read_Result == 1)); /* * We have exited the while loop, which means that Current Position is * beyond the end of the partition or is unreadable due to a hardware * problem (bad block). Since the odds of hitting a bad block are very * low, we will ignore that condition for now. If time becomes * available, then this issue can be revisited. */ /* Is the drive greater than 16MB? */ if (Last_Valid_Position == 0) { /* * Determine if drive is readable at all. If it is, the drive * is too small. If not, it could be a newly created partion, * so we need to issue a different error message */ *size = 0; /* Indicates not readable at all */ Seek_Result = lseek(device, Last_Valid_Position, SEEK_SET); if (Seek_Result == Last_Valid_Position) { /* Can we read from this location? */ Read_Result = read(device, &Test_Byte, 1); if (Read_Result == 1) /* non-zero indicates readable, but too small */ *size = 1; } goto restore; } /* * The drive is larger than 16MB. Now we must find out exactly how * large. * * We now have a point within the partition and one beyond it. The end * of the partition must lie between the two. We will use a binary * search to find it. */ /* Setup for the binary search. */ First_Invalid_Position = Current_Position; Current_Position = Last_Valid_Position + ((Current_Position - Last_Valid_Position) / 2); /* * Iterate until the difference between the last valid position and the * first invalid position is 2 or less. */ while ((First_Invalid_Position - Last_Valid_Position) > 2) { /* Seek to the location we wish to test. */ Seek_Result = lseek(device, Current_Position, SEEK_SET); if (Seek_Result == Current_Position) { /* Can we read from this location? */ Read_Result = read(device, &Test_Byte, 1); if (Read_Result == 1) { /* The current test position is valid. * Save it for future reference. */ Last_Valid_Position = Current_Position; /* * Lets calculate the next location to test. It * should be half way between the current test * position and the first invalid position that * we know of. */ Current_Position = Current_Position + ((First_Invalid_Position - Last_Valid_Position) / 2); } } else Read_Result = 0; if (Read_Result != 1) { /* Out test position is beyond the end of the partition. * It becomes our first known invalid position. */ First_Invalid_Position = Current_Position; /* Our new test position should be half way between our * last known valid position and our current test * position. */ Current_Position = Last_Valid_Position + ((Current_Position - Last_Valid_Position) / 2); } } /* * The size of the drive should be Last_Valid_Position + 1 as * Last_Valid_Position is an offset from the beginning of the partition. */ *size = Last_Valid_Position + 1;restore: /* Restore the original position. */ if (Starting_Position != lseek(device, Starting_Position, SEEK_SET)) return ERROR_SEEK; return NO_ERROR;}/* * NAME: ujfs_rw_diskblocks * * FUNCTION: Read/Write specific number of bytes for an opened device. * * PRE CONDITIONS: * * POST CONDITIONS: * * PARAMETERS: * dev_ptr - file handle of an opened device to read/write * disk_offset - byte offset from beginning of device for start of disk * block read/write * disk_count - number of bytes to read/write * data_buffer - On read this will be filled in with data read from * disk; on write this contains data to be written * mode - GET: read; PUT: write; VRFY: verify * * NOTES: A disk address is formed by {#cylinder, #head, #sector} * * Also the DSK_READTRACK and DSK_WRITETRACK is a track based * function. If it needs to read/write crossing track boundary, * additional calls are used. * * DATA STRUCTURES: * * RETURNS: */int ujfs_rw_diskblocks(HFILE dev_ptr, int64_t disk_offset, int32_t disk_count, void *data_buffer, int32_t mode){ off_t Actual_Location; size_t Bytes_Transferred; Actual_Location = lseek(dev_ptr, disk_offset, SEEK_SET); if ((Actual_Location < 0) || (Actual_Location != disk_offset)) return ERROR_SEEK; switch (mode) { case GET: Bytes_Transferred = read(dev_ptr, data_buffer, disk_count); break; case PUT: Bytes_Transferred = write(dev_ptr, data_buffer, disk_count); break; default: DBG_ERROR(("Internal error: %s(%d): bad mode: %d\n", __FILE__, __LINE__, mode)) return ERROR_INVALID_HANDLE; break; /* Keep the compiler happy. */ } if (Bytes_Transferred != disk_count) { if (mode == GET) return ERROR_READ_FAULT; else return ERROR_WRITE_FAULT; } return NO_ERROR;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -