Add FAT32 support. This allows the bootloader to find a BFS image file (currently named BEOS\IMAGE.BE) and start booting for it, until the kernel tries to mount the boot partition.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28156 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
François Revol 2008-10-15 23:54:04 +00:00
parent a04a170937
commit 2cf4975b4b
17 changed files with 1446 additions and 0 deletions

View File

@ -93,6 +93,8 @@ struct file_system_module_info {
};
extern file_system_module_info gBFSFileSystemModule;
extern file_system_module_info gFATFileSystemModule;
extern file_system_module_info gHFSPlusFileSystemModule;
extern file_system_module_info gAmigaFFSFileSystemModule;
extern file_system_module_info gTarFileSystemModule;

View File

@ -35,6 +35,7 @@ KernelLd boot_loader_$(TARGET_BOOT_PLATFORM) :
boot_bfs.a
boot_amiga_ffs.a
boot_tarfs.a
boot_fatfs.a
libz.a

View File

@ -20,6 +20,7 @@ UsePrivateHeaders shared storage ;
BOOT_SUPPORT_PARTITION_INTEL
BOOT_SUPPORT_FILE_SYSTEM_BFS
BOOT_SUPPORT_FILE_SYSTEM_FAT
BOOT_SUPPORT_FILE_SYSTEM_AMIGA_FFS
BOOT_SUPPORT_FILE_SYSTEM_TARFS

View File

@ -2,5 +2,6 @@ SubDir HAIKU_TOP src system boot loader file_systems ;
SubInclude HAIKU_TOP src system boot loader file_systems amiga_ffs ;
SubInclude HAIKU_TOP src system boot loader file_systems bfs ;
SubInclude HAIKU_TOP src system boot loader file_systems fat ;
SubInclude HAIKU_TOP src system boot loader file_systems hfs_plus ;
SubInclude HAIKU_TOP src system boot loader file_systems tarfs ;

View File

@ -0,0 +1,74 @@
/*
* Copyright 2008, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* François Revol <revol@free.fr>
*/
#include "CachedBlock.h"
#include "Stream.h"
#include "Directory.h"
#include "File.h"
#include <util/kernel_cpp.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
using namespace FATFS;
CachedBlock::CachedBlock(Volume &volume)
:
fVolume(volume),
fBlockNumber(-1LL),
fBlock(NULL)
{
}
CachedBlock::CachedBlock(Volume &volume, off_t block)
:
fVolume(volume),
fBlockNumber(-1LL),
fBlock(NULL)
{
SetTo(block);
}
CachedBlock::~CachedBlock()
{
free(fBlock);
}
inline void
CachedBlock::Unset()
{
fBlockNumber = -1;
}
inline uint8 *
CachedBlock::SetTo(off_t block)
{
if (block == fBlockNumber)
return fBlock;
if (fBlock == NULL) {
fBlock = (uint8 *)malloc(BlockSize());
if (fBlock == NULL)
return NULL;
}
fBlockNumber = block;
if (read_pos(fVolume.Device(), block << BlockShift(), fBlock, BlockSize()) < (ssize_t)BlockSize())
return NULL;
return fBlock;
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2008, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* François Revol <revol@free.fr>
*/
#ifndef CACHED_BLOCK_H
#define CACHED_BLOCK_H
#include <SupportDefs.h>
#include <sys/stat.h>
#include "Volume.h"
namespace FATFS {
class CachedBlock {
public:
CachedBlock(Volume &volume);
CachedBlock(Volume &volume, off_t block);
~CachedBlock();
uint8 *SetTo(off_t block);
void Unset();
uint8 *Block() const { return fBlock; }
off_t BlockNumber() const { return fBlockNumber; }
uint32 BlockSize() const { return fVolume.BlockSize(); }
uint32 BlockShift() const { return fVolume.BlockShift(); }
private:
Volume &fVolume;
off_t fBlockNumber;
uint8 *fBlock;
};
} // namespace FATFS
#endif /* CACHED_BLOCK_H */

View File

@ -0,0 +1,298 @@
/*
** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#include "Directory.h"
#include "Volume.h"
#include "File.h"
#include <StorageDefs.h>
#include <util/kernel_cpp.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#define TRACE(x) dprintf x
namespace FATFS {
struct dir_entry {
void *Buffer() const { return (void *)fName; };
const char *BaseName() const { return fName; };
const char *Extension() const { return fExt; };
uint8 Flags() const { return fFlags; };
uint32 Cluster(int32 fatBits) const;
uint32 Size() const { return B_LENDIAN_TO_HOST_INT32(fSize); };
bool IsFile() const;
bool IsDir() const;
char fName[8];
char fExt[3];
uint8 fFlags;
uint8 fReserved1;
uint8 fCreateTime10ms;
uint16 fCreateTime;
uint16 fCreateDate;
uint16 fAccessDate;
uint16 fClusterMSB;
uint16 fModifiedTime;
uint16 fModifiedDate;
uint16 fClusterLSB;
uint32 fSize;
} _PACKED;
uint32
dir_entry::Cluster(int32 fatBits) const
{
uint32 c = B_LENDIAN_TO_HOST_INT16(fClusterLSB);
if (fatBits == 32)
c += ((uint32)B_LENDIAN_TO_HOST_INT16(fClusterMSB) << 16);
return c;
}
bool
dir_entry::IsFile() const
{
return ((Flags() & (FAT_VOLUME|FAT_SUBDIR)) == 0);
}
bool
dir_entry::IsDir() const
{
return ((Flags() & (FAT_VOLUME|FAT_SUBDIR)) == FAT_SUBDIR);
}
struct dir_cookie {
int32 index;
struct dir_entry entry;
off_t Offset() const { return index * sizeof(struct dir_entry); }
};
Directory::Directory(Volume &volume, uint32 cluster, const char *name)
:
fVolume(volume),
fStream(volume, cluster, UINT32_MAX, name)
{
TRACE(("FASFS::Directory::(, %lu, %s)\n", cluster, name));
}
Directory::~Directory()
{
TRACE(("FASFS::Directory::~()\n"));
}
status_t
Directory::InitCheck()
{
status_t err;
err = fStream.InitCheck();
if (err < B_OK)
return err;
return B_OK;
}
status_t
Directory::Open(void **_cookie, int mode)
{
TRACE(("FASFS::Directory::%s(, %d)\n", __FUNCTION__, mode));
_inherited::Open(_cookie, mode);
struct dir_cookie *c = new struct dir_cookie;
if (c == NULL)
return B_NO_MEMORY;
c->index = -1;
*_cookie = (void *)c;
return B_OK;
}
status_t
Directory::Close(void *cookie)
{
TRACE(("FASFS::Directory::%s()\n", __FUNCTION__));
_inherited::Close(cookie);
delete (struct dir_cookie *)cookie;
return B_OK;
}
Node *
Directory::Lookup(const char *name, bool traverseLinks)
{
TRACE(("FASFS::Directory::%s('%s', %d)\n", __FUNCTION__, name, traverseLinks));
if (!strcmp(name, ".")) {
Acquire();
return this;
}
char *dot = strchr(name, '.');
int baselen = strlen(name);
if (baselen > FATFS_BASENAME_LENGTH) // !?
return NULL;
char *ext = NULL;
int extlen = 0;
if (dot) {
baselen = dot - name;
ext = dot + 1;
if (strlen(ext) > FATFS_EXTNAME_LENGTH) // !?
return NULL;
extlen = strlen(ext);
}
status_t err;
struct dir_cookie cookie;
struct dir_cookie *c = &cookie;
c->index = -1;
do {
err = GetNextEntry(c);
if (err < B_OK)
return NULL;
TRACE(("FASFS::Directory::%s: %s <> '%8.8s.%3.3s'\n", __FUNCTION__,
name, c->entry.BaseName(), c->entry.Extension()));
int i;
for (i = 0; i < FATFS_BASENAME_LENGTH; i++)
if (c->entry.BaseName()[i] == ' ')
break;
int nlen = MIN(i,FATFS_BASENAME_LENGTH);
for (i = 0; i < FATFS_EXTNAME_LENGTH; i++)
if (c->entry.Extension()[i] == ' ')
break;
int elen = MIN(i,FATFS_EXTNAME_LENGTH);
if (nlen != baselen)
continue;
if (elen != extlen)
continue;
if (strncasecmp(name, c->entry.BaseName(), nlen))
continue;
if (strncasecmp(ext, c->entry.Extension(), elen))
continue;
TRACE(("GOT IT!\n"));
break;
} while (true);
if (c->entry.IsFile()) {
TRACE(("IS FILE\n"));
return new File(fVolume, c->entry.Cluster(fVolume.FatBits()),
c->entry.Size(), name);
}
if (c->entry.IsDir()) {
TRACE(("IS DIR\n"));
return new Directory(fVolume, c->entry.Cluster(fVolume.FatBits()),
name);
}
return NULL;
}
status_t
Directory::GetNextEntry(void *cookie, char *name, size_t size)
{
TRACE(("FASFS::Directory::%s()\n", __FUNCTION__));
struct dir_cookie *c = (struct dir_cookie *)cookie;
status_t err;
err = GetNextEntry(cookie);
if (err < B_OK)
return err;
strlcpy(name, c->entry.fName, MIN(size, FATFS_BASENAME_LENGTH));
strlcpy(name, ".", size);
strlcpy(name, c->entry.fExt, MIN(size, FATFS_EXTNAME_LENGTH));
return B_OK;
}
status_t
Directory::GetNextNode(void *cookie, Node **_node)
{
return B_ERROR;
}
status_t
Directory::Rewind(void *cookie)
{
TRACE(("FASFS::Directory::%s()\n", __FUNCTION__));
struct dir_cookie *c = (struct dir_cookie *)cookie;
c->index = -1;
return B_OK;
}
bool
Directory::IsEmpty()
{
TRACE(("FASFS::Directory::%s()\n", __FUNCTION__));
struct dir_cookie cookie;
struct dir_cookie *c = &cookie;
c->index = -1;
if (GetNextEntry(c) == B_OK)
return false;
return true;
}
status_t
Directory::GetName(char *name, size_t size) const
{
TRACE(("FASFS::Directory::%s()\n", __FUNCTION__));
if (this == fVolume.Root())
return fVolume.GetName(name, size);
return fStream.GetName(name, size);
}
ino_t
Directory::Inode() const
{
TRACE(("FASFS::Directory::%s()\n", __FUNCTION__));
return fStream.FirstCluster() << 16;
}
status_t
Directory::GetNextEntry(void *cookie, uint8 mask, uint8 match = 0)
{
TRACE(("FASFS::Directory::%s(, %02x, %02x)\n", __FUNCTION__, mask, match));
struct dir_cookie *c = (struct dir_cookie *)cookie;
do {
c->index++;
size_t len = sizeof(c->entry);
if (fStream.ReadAt(c->Offset(), (uint8 *)&c->entry, &len) < B_OK)
return B_ENTRY_NOT_FOUND;
TRACE(("FASFS::Directory::%s: got one entry\n", __FUNCTION__));
if ((uint8)c->entry.fName[0] == 0x00) // last one
return B_ENTRY_NOT_FOUND;
if ((uint8)c->entry.fName[0] == 0xe5) // deleted
continue;
if (c->entry.Flags() == 0x0f) // LFN entry
continue;
if (c->entry.Flags() & (FAT_VOLUME|FAT_SUBDIR) == FAT_VOLUME) {
// TODO handle Volume name (set fVolume's name)
continue;
}
TRACE(("FASFS::Directory::%s: checking '%8.8s.%3.3s', %02x\n", __FUNCTION__,
c->entry.BaseName(), c->entry.Extension(), c->entry.Flags()));
if ((c->entry.Flags() & mask) == match)
break;
} while (true);
TRACE(("FATFS::Directory::%s: '%8.8s.%3.3s'\n", __FUNCTION__,
c->entry.BaseName(), c->entry.Extension()));
return B_OK;
}
} // namespace FATFS

View File

@ -0,0 +1,51 @@
/*
** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#ifndef DIRECTORY_H
#define DIRECTORY_H
#include "fatfs.h"
#include "Stream.h"
#include <boot/vfs.h>
namespace FATFS {
class Volume;
class Directory : public ::Directory {
public:
Directory();
Directory(Volume &volume, uint32 cluster, const char *name);
virtual ~Directory();
status_t InitCheck();
virtual status_t Open(void **_cookie, int mode);
virtual status_t Close(void *cookie);
virtual Node *Lookup(const char *name, bool traverseLinks);
virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize);
virtual status_t GetNextNode(void *cookie, Node **_node);
virtual status_t Rewind(void *cookie);
virtual bool IsEmpty();
virtual status_t GetName(char *name, size_t size) const;
virtual ino_t Inode() const;
private:
status_t GetNextEntry(void *cookie,
uint8 mask = FAT_VOLUME, uint8 match = 0);
Volume &fVolume;
Stream fStream;
typedef ::Directory _inherited;
};
} // namespace FATFS
#endif /* DIRECTORY_H */

View File

@ -0,0 +1,110 @@
/*
** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#include "File.h"
#include <util/kernel_cpp.h>
#include <sys/stat.h>
#include <unistd.h>
#define TRACE(x) dprintf x
namespace FATFS {
File::File(Volume &volume, uint32 cluster, off_t size, const char *name)
:
fVolume(volume),
fStream(volume, cluster, size, name)
{
TRACE(("FATFS::File::()\n"));
}
File::~File()
{
TRACE(("FATFS::File::~()\n"));
}
status_t
File::InitCheck()
{
if (!fStream.InitCheck() < B_OK)
return fStream.InitCheck();
return B_OK;
}
status_t
File::Open(void **_cookie, int mode)
{
TRACE(("FATFS::File::%s(, %d)\n", __FUNCTION__, mode));
if (fStream.InitCheck() < B_OK)
return fStream.InitCheck();
return B_OK;
}
status_t
File::Close(void *cookie)
{
return B_OK;
}
ssize_t
File::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
{
TRACE(("FATFS::File::%s(, %Ld,, %d)\n", __FUNCTION__, pos, bufferSize));
status_t err;
err = fStream.ReadAt(pos, (uint8 *)buffer, &bufferSize);
if (err < B_OK)
return err;
return bufferSize;
}
ssize_t
File::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
{
return EROFS;
}
status_t
File::GetName(char *nameBuffer, size_t bufferSize) const
{
return fStream.GetName(nameBuffer, bufferSize);
}
int32
File::Type() const
{
return S_IFREG;
}
off_t
File::Size() const
{
return fStream.Size();
}
ino_t
File::Inode() const
{
return fStream.FirstCluster() << 16;
}
} // namespace FATFS

View File

@ -0,0 +1,43 @@
/*
** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#ifndef FILE_H
#define FILE_H
#include <boot/vfs.h>
#include "Stream.h"
#include "Volume.h"
namespace FATFS {
class File : public Node {
public:
File(Volume &volume, uint32 cluster, off_t size, const char *name);
virtual ~File();
status_t InitCheck();
virtual status_t Open(void **_cookie, int mode);
virtual status_t Close(void *cookie);
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
virtual status_t GetName(char *nameBuffer, size_t bufferSize) const;
virtual int32 Type() const;
virtual off_t Size() const;
virtual ino_t Inode() const;
private:
Volume &fVolume;
//FileBlock fNode;
Stream fStream;
};
} // namespace FATFS
#endif /* FILE_H */

View File

@ -0,0 +1,24 @@
SubDir HAIKU_TOP src system boot loader file_systems fat ;
#UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ;
#UsePrivateHeaders [ FDirName kernel disk_device_manager ] ;
#UsePrivateHeaders [ FDirName storage ] ;
UsePrivateKernelHeaders ;
UsePrivateHeaders shared storage ;
#SubDirHdrs $(HAIKU_TOP) src add-ons kernel file_systems fat ;
local defines = [ FDefines _BOOT_MODE ] ;
SubDirCcFlags $(defines) ;
SubDirC++Flags -fno-rtti $(defines) ;
KernelStaticLibrary boot_fatfs :
fatfs.cpp
Volume.cpp
CachedBlock.cpp
Directory.cpp
File.cpp
Stream.cpp
: -fno-pic
;

View File

@ -0,0 +1,268 @@
/*
* Copyright 2008, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* François Revol <revol@free.fr>
*/
#include "Stream.h"
#include "CachedBlock.h"
#include "Directory.h"
#include "File.h"
#include <util/kernel_cpp.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define TRACE(x) dprintf x
using namespace FATFS;
Stream::Stream(Volume &volume, uint32 chain, off_t size, const char *name)
:
fVolume(volume),
fFirstCluster(chain),
//fClusters(NULL),
fClusterMapCacheLast(0),
fSize(size)
{
TRACE(("FATFS::Stream::(, %d, %Ld, %s)\n", chain, size, name));
fName[FATFS_NAME_LENGTH] = '\0';
strlcpy(fName, name, FATFS_NAME_LENGTH+1);
fClusterCount = (fSize + fVolume.ClusterSize() - 1) / fVolume.ClusterSize();
if (size == UINT32_MAX)
fClusterCount = 10; // ?
for (int i = 0; i < CLUSTER_MAP_CACHE_SIZE; i++) {
fClusterMapCache[i].block = -1;
fClusterMapCache[i].cluster = fVolume.InvalidClusterID();
}
}
Stream::~Stream()
{
TRACE(("FATFS::Stream::~()\n"));
}
status_t
Stream::InitCheck()
{
if (fSize && !fVolume.IsValidCluster(fFirstCluster))
return B_BAD_VALUE;
return B_OK;
}
status_t
Stream::GetName(char *nameBuffer, size_t bufferSize) const
{
return strlcpy(nameBuffer, fName, bufferSize);
}
status_t
Stream::FindBlock(off_t pos, off_t &block, off_t &offset)
{
//TRACE(("FATFS::Stream::%s(%Ld,,)\n", __FUNCTION__, pos));
uint32 index = (uint32)(pos / fVolume.ClusterSize());
uint32 cluster;
if (pos >= fSize)
return B_BAD_VALUE;
if (index >= fClusterCount)
return B_BAD_VALUE;
bool found = false;
int i;
for (i = 0; i < CLUSTER_MAP_CACHE_SIZE; i++) {
if (fClusterMapCache[i].block == index) {
cluster = fClusterMapCache[i].cluster;
found = true;
break;
}
}
if (!found) {
#if 1
uint32 count = (fSize + fVolume.ClusterSize() - 1) / fVolume.ClusterSize();
cluster = fFirstCluster;
if (fSize == UINT32_MAX) // it's a directory, try a large enough value
count = 10;
for (i = 0; i < index && fVolume.IsValidCluster(cluster); i++) {
if (fVolume.IsLastCluster(cluster))
break;
//TRACE(("FATFS::Stream::%s: [%d] = %d\n", __FUNCTION__, i, cluster));
cluster = fVolume.NextCluster(cluster);
//TRACE(("FATFS::Stream::%s: %04lx ?\n", __FUNCTION__, cluster));
}
#endif
#if 0
cluster = fVolume.NextCluster(cluster, index);
#endif
}
if (!fVolume.IsValidCluster(cluster))
return ENOENT;
fClusterMapCache[fClusterMapCacheLast].block = index;
fClusterMapCache[fClusterMapCacheLast].cluster = cluster;
fClusterMapCacheLast++;
fClusterMapCacheLast %= CLUSTER_MAP_CACHE_SIZE;
//cluster = fClusters[index];
// convert to position
offset = fVolume.ToOffset(cluster);
offset += (pos %= fVolume.ClusterSize());
// convert to block + offset
block = fVolume.ToBlock(offset);
offset %= fVolume.BlockSize();
//TRACE(("FATFS::Stream::FindBlock: %Ld:%Ld\n", block, offset));
return B_OK;
}
status_t
Stream::ReadAt(off_t pos, uint8 *buffer, size_t *_length)
{
TRACE(("FATFS::Stream::%s(%Ld, )\n", __FUNCTION__, pos));
status_t err;
// set/check boundaries for pos/length
if (pos < 0)
return B_BAD_VALUE;
if (pos >= fSize) {
*_length = 0;
return B_NO_ERROR;
}
#if 0
// lazily build the cluster list
if (!fClusters) {
err = BuildClusterList();
if (err < B_OK)
return err;
}
#endif
size_t length = *_length;
if (pos + length > fSize)
length = fSize - pos;
off_t num; // block number
off_t offset;
if (FindBlock(pos, num, offset) < B_OK) {
*_length = 0;
return B_BAD_VALUE;
}
uint32 bytesRead = 0;
uint32 blockSize = fVolume.BlockSize();
uint32 blockShift = fVolume.BlockShift();
uint8 *block;
// the first block_run we read could not be aligned to the block_size boundary
// (read partial block at the beginning)
// pos % block_size == (pos - offset) % block_size, offset % block_size == 0
if (pos % blockSize != 0) {
CachedBlock cached(fVolume, num);
if ((block = cached.Block()) == NULL) {
*_length = 0;
return B_BAD_VALUE;
}
bytesRead = blockSize - (pos % blockSize);
if (length < bytesRead)
bytesRead = length;
memcpy(buffer, block + (pos % blockSize), bytesRead);
pos += bytesRead;
length -= bytesRead;
if (length == 0) {
*_length = bytesRead;
return B_OK;
}
if (FindBlock(pos, num, offset) < B_OK) {
*_length = bytesRead;
return B_BAD_VALUE;
}
}
// the first block_run is already filled in at this point
// read the following complete blocks using cached_read(),
// the last partial block is read using the generic Cache class
bool partial = false;
while (length > 0) {
// offset is the offset to the current pos in the block_run
if (length < blockSize) {
CachedBlock cached(fVolume, num);
if ((block = cached.Block()) == NULL) {
*_length = bytesRead;
return B_BAD_VALUE;
}
memcpy(buffer + bytesRead, block, length);
bytesRead += length;
partial = true;
break;
}
if (read_pos(fVolume.Device(), fVolume.ToOffset(num),
buffer + bytesRead, fVolume.BlockSize()) < B_OK) {
*_length = bytesRead;
return B_BAD_VALUE;
}
int32 bytes = fVolume.BlockSize();
length -= bytes;
bytesRead += bytes;
if (length == 0)
break;
pos += bytes;
if (FindBlock(pos, num, offset) < B_OK) {
*_length = bytesRead;
return B_BAD_VALUE;
}
}
*_length = bytesRead;
return B_NO_ERROR;
}
status_t
Stream::BuildClusterList()
{
#if 0
TRACE(("FATFS::Stream::%s()\n", __FUNCTION__));
uint32 count = (fSize + fVolume.ClusterSize() - 1) / fVolume.ClusterSize();
uint32 c = fFirstCluster;
int i;
if (fSize == UINT32_MAX) // it's a directory, try a large enough value
count = 10;
//fClusters = (uint32 *)malloc(count * sizeof(uint32));
for (i = 0; i < count && fVolume.IsValidCluster(c); i++) {
if (fVolume.IsLastCluster(c))
break;
TRACE(("FATFS::Stream::%s: [%d] = %d\n", __FUNCTION__, i, c));
fClusters[i] = c;
c = fVolume.NextCluster(c);
TRACE(("FATFS::Stream::%s: %04lx ?\n", __FUNCTION__, c));
// XXX: try to realloc() for dirs maybe ?
}
fClusterCount = i;
TRACE(("FATFS::Stream::%s: %d clusters in chain\n", __FUNCTION__, i));
#endif
return B_OK;
}

View File

@ -0,0 +1,57 @@
/*
* Copyright 2008, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* François Revol <revol@free.fr>
*/
#ifndef STREAM_H
#define STREAM_H
#include "fatfs.h"
#include "Volume.h"
#include <sys/stat.h>
#define CLUSTER_MAP_CACHE_SIZE 50
class Node;
namespace FATFS {
class Stream {
public:
Stream(Volume &volume, uint32 chain, off_t size, const char *name);
~Stream();
status_t InitCheck();
Volume &GetVolume() const { return fVolume; }
status_t GetName(char *nameBuffer, size_t bufferSize) const;
off_t Size() const { return fSize; }
uint32 FirstCluster() const { return fFirstCluster; }
status_t ReadAt(off_t pos, uint8 *buffer, size_t *length);
private:
status_t BuildClusterList();
status_t FindBlock(off_t pos, off_t &block, off_t &offset);
Volume &fVolume;
uint32 fFirstCluster;
uint32 fClusterCount;
//uint32 *fClusters; // [fClusterCount]
struct {
off_t block;
uint32 cluster;
} fClusterMapCache[CLUSTER_MAP_CACHE_SIZE];
int fClusterMapCacheLast;
off_t fSize;
// we cache the name here, since FAT doesn't have inodes,
// let alone names inside.
char fName[FATFS_NAME_LENGTH+1];
};
} // namespace FATFS
#endif /* STREAM_H */

View File

@ -0,0 +1,299 @@
/*
** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#include "Volume.h"
#include "Directory.h"
#include "CachedBlock.h"
#include <boot/partitions.h>
#include <boot/platform.h>
#include <util/kernel_cpp.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#define TRACE(x) dprintf x
using namespace FATFS;
Volume::Volume(boot::Partition *partition)
:
fRoot(NULL)
{
TRACE(("%s()\n", __FUNCTION__));
if ((fDevice = open_node(partition, O_RDONLY)) < B_OK)
return;
fCachedBlock = new CachedBlock(*this);
if (fCachedBlock == NULL)
return;
uint8 *buf;
/* = (char *)malloc(4096);
if (buf == NULL)
return;*/
fBlockSize = partition->block_size;
switch (fBlockSize) {
case 0x200:
fBlockShift = 9;
break;
case 0x400:
fBlockShift = 10;
break;
case 0x800:
fBlockShift = 11;
break;
default:
goto err1;
}
TRACE(("%s: reading bootsector\n", __FUNCTION__));
// read boot sector
buf = fCachedBlock->SetTo(0);
if (buf == NULL)
goto err1;
TRACE(("%s: checking signature\n", __FUNCTION__));
// check the signature
if (((buf[0x1fe] != 0x55) || (buf[0x1ff] != 0xaa)) && (buf[0x15] == 0xf8))
goto err1;
if (!memcmp(buf+3, "NTFS ", 8) || !memcmp(buf+3, "HPFS ", 8))
goto err1;
TRACE(("%s: signature ok\n", __FUNCTION__));
fBytesPerSector = read16(buf,0xb);
switch (fBytesPerSector) {
case 0x200:
fSectorShift = 9;
break;
case 0x400:
fSectorShift = 10;
break;
case 0x800:
fSectorShift = 11;
break;
default:
goto err1;
}
TRACE(("%s: block shift %d\n", __FUNCTION__, fBlockShift));
fSectorsPerCluster = buf[0xd];
switch (fSectorsPerCluster) {
case 1: case 2: case 4: case 8:
case 0x10: case 0x20: case 0x40: case 0x80:
break;
default:
goto err1;
}
TRACE(("%s: sect/cluster %d\n", __FUNCTION__, fSectorsPerCluster));
fClusterShift = fSectorShift;
for (uint32 spc = fSectorsPerCluster; !(spc & 0x01); ) {
spc >>= 1;
fClusterShift += 1;
}
TRACE(("%s: cluster shift %d\n", __FUNCTION__, fClusterShift));
fReservedSectors = read16(buf,0xe);
fFatCount = buf[0x10];
if ((fFatCount == 0) || (fFatCount > 8))
goto err1;
fMediaDesc = buf[0x15];
if ((fMediaDesc != 0xf0) && (fMediaDesc < 0xf8))
goto err1;
fSectorsPerFat = read16(buf,0x16);
if (fSectorsPerFat == 0) {
// FAT32
fFatBits = 32;
fSectorsPerFat = read32(buf,0x24);
fTotalSectors = read32(buf,0x20);
bool lFatMirrored = !(buf[0x28] & 0x80);
fActiveFat = (lFatMirrored) ? (buf[0x28] & 0xf) : 0;
fDataStart = fReservedSectors + fFatCount * fSectorsPerFat;
fTotalClusters = (fTotalSectors - fDataStart) / fSectorsPerCluster;
fRootDirCluster = read32(buf,0x2c);
if (fRootDirCluster >= fTotalClusters)
goto err1;
} else {
// FAT12/16
// XXX:FIXME
fFatBits = 16;
goto err1;
}
TRACE(("%s: block size %d, sector size %d, sectors/cluster %d\n", __FUNCTION__,
fBlockSize, fBytesPerSector, fSectorsPerCluster));
TRACE(("%s: block shift %d, sector shift %d, cluster shift %d\n", __FUNCTION__,
fBlockShift, fSectorShift, fClusterShift));
TRACE(("%s: reserved %d, max root entries %d, media %02x, sectors/fat %d\n", __FUNCTION__,
fReservedSectors, fMaxRootEntries, fMediaDesc, fSectorsPerFat));
//if (fTotalSectors > partition->sectors_per_track * partition->cylinder_count * partition->head_count)
if ((off_t)fTotalSectors * fBytesPerSector > partition->size)
goto err1;
TRACE(("%s: found fat%d filesystem, root dir at cluster %d\n", __FUNCTION__,
fFatBits, fRootDirCluster));
fRoot = new Directory(*this, fRootDirCluster, "/");
return;
err1:
dprintf("fatfs: cannot mount (bad superblock ?)\n");
// XXX !? this triple-faults in QEMU ..
//delete fCachedBlock;
}
Volume::~Volume()
{
delete fRoot;
delete fCachedBlock;
close(fDevice);
}
status_t
Volume::InitCheck()
{
if (fCachedBlock == NULL)
return B_ERROR;
if (fRoot == NULL)
return B_ERROR;
return B_OK;
}
status_t
Volume::GetName(char *name, size_t size) const
{
//TODO: WRITEME
return strlcpy(name, "UNKNOWN", size);
}
off_t
Volume::ToOffset(uint32 cluster) const
{
return (fDataStart << SectorShift()) + ((cluster - 2) << ClusterShift());
}
uint32
Volume::NextCluster(uint32 cluster, uint32 skip)
{
//TRACE(("%s(%d, %d)\n", __FUNCTION__, cluster, skip));
// lookup the FAT for next cluster in chain
off_t offset;
uint8 *buf;
int32 next;
int fatBytes = (FatBits() + 7) / 8;
switch (fFatBits) {
case 32:
case 16:
break;
//XXX handle FAT12
default:
return InvalidClusterID();
}
again:
offset = fBytesPerSector * fReservedSectors;
//offset += fActiveFat * fTotalClusters * fFatBits / 8;
offset += cluster * fatBytes;
if (!IsValidCluster(cluster))
return InvalidClusterID();
buf = fCachedBlock->SetTo(ToBlock(offset));
if (!buf)
return InvalidClusterID();
offset %= BlockSize();
switch (fFatBits) {
case 32:
next = read32(buf, offset);
next &= 0x0fffffff;
break;
case 16:
next = read16(buf, offset);
break;
default:
return InvalidClusterID();
}
if (skip--) {
cluster = next;
goto again;
}
return next;
}
bool
Volume::IsValidCluster(uint32 cluster) const
{
if (cluster > 1 && cluster < fTotalClusters)
return true;
return false;
}
bool
Volume::IsLastCluster(uint32 cluster) const
{
if (cluster >= fTotalClusters && (cluster & 0xff8 == 0xff8))
return true;
return false;
}
// #pragma mark -
float
dosfs_identify_file_system(boot::Partition *partition)
{
TRACE(("%s()\n", __FUNCTION__));
Volume volume(partition);
return volume.InitCheck() < B_OK ? 0 : 0.8;
}
static status_t
dosfs_get_file_system(boot::Partition *partition, ::Directory **_root)
{
TRACE(("%s()\n", __FUNCTION__));
Volume *volume = new Volume(partition);
if (volume == NULL)
return B_NO_MEMORY;
if (volume->InitCheck() < B_OK) {
delete volume;
return B_ERROR;
}
*_root = volume->Root();
return B_OK;
}
file_system_module_info gFATFileSystemModule = {
"file_systems/dosfs/v1",
kPartitionTypeFAT32, // XXX:FIXME: FAT16 too ?
dosfs_identify_file_system,
dosfs_get_file_system
};

View File

@ -0,0 +1,85 @@
/*
** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#ifndef VOLUME_H
#define VOLUME_H
#include "fatfs.h"
#include <SupportDefs.h>
namespace boot {
class Partition;
}
namespace FATFS {
class CachedBlock;
class Directory;
class Volume {
public:
Volume(boot::Partition *partition);
~Volume();
status_t InitCheck();
status_t GetName(char *name, size_t size) const;
int Device() const { return fDevice; }
Directory *Root() { return fRoot; }
int32 FatBits() const { return fFatBits; }
uint32 DataStart() const { return fDataStart; }
int32 BlockSize() const { return fBlockSize; }
int32 ClusterSize() const { return fSectorsPerCluster * fBytesPerSector; }
int32 BlockShift() const { return fBlockShift; }
int32 SectorShift() const { return fSectorShift; }
int32 ClusterShift() const { return fClusterShift; }
int32 NumBlocks() const { return (int32)((off_t)fTotalSectors * fBytesPerSector / fBlockSize); }
int32 NumSectors() const { return fTotalSectors; }
int32 NumClusters() const { return fTotalClusters; }
uint32 NextCluster(uint32 cluster, uint32 skip=0);
bool IsValidCluster(uint32 cluster) const;
bool IsLastCluster(uint32 cluster) const;
uint32 InvalidClusterID() const { return (1 << fFatBits) - 1; }
off_t ToOffset(uint32 cluster) const;
// uint32 ToCluster(off_t offset) const { return offset >> ClusterShift(); }
off_t ToOffset(off_t block) const { return block << BlockShift(); }
uint32 ToBlock(off_t offset) const { return offset >> BlockShift(); }
protected:
int fDevice;
int32 fBlockShift;
int32 fSectorShift;
int32 fClusterShift;
uint32 fBlockSize;
// from the boot/fsinfo sectors
uint32 fBytesPerSector;
uint32 fSectorsPerCluster;
uint32 fReservedSectors;
uint8 fMediaDesc;
uint32 fSectorsPerFat;
uint32 fTotalSectors;
uint8 fFatCount;
uint16 fMaxRootEntries;
uint8 fActiveFat;
uint8 fFatBits;
uint32 fDataStart;
uint32 fTotalClusters;
uint32 fRootDirCluster;
CachedBlock *fCachedBlock;
Directory *fRoot;
};
} // namespace FATFS
#endif /* VOLUME_H */

View File

@ -0,0 +1,49 @@
/*
** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#include "fatfs.h"
#include <boot/partitions.h>
#include <boot/platform.h>
#include <util/kernel_cpp.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
using namespace FATFS;
#if 0
status_t
FATFS::get_root_block(int fDevice, char *buffer, int32 blockSize, off_t partitionSize)
{
// calculate root block position (it depends on the block size)
// ToDo: get the number of reserved blocks out of the disk_environment structure??
// (from the amiga_rdb module)
int32 reservedBlocks = 2;
off_t offset = (((partitionSize / blockSize) - 1 - reservedBlocks) / 2) + reservedBlocks;
// ToDo: this calculation might be incorrect for certain cases.
if (read_pos(fDevice, offset * blockSize, buffer, blockSize) < B_OK)
return B_ERROR;
RootBlock root(buffer, blockSize);
if (root.ValidateCheckSum() < B_OK)
return B_BAD_DATA;
//printf("primary = %ld, secondary = %ld\n", root.PrimaryType(), root.SecondaryType());
if (!root.IsRootBlock())
return B_BAD_TYPE;
return B_OK;
}
#endif

View File

@ -0,0 +1,42 @@
/*
** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#ifndef FATFS_H
#define FATFS_H
#include <SupportDefs.h>
#include <ByteOrder.h>
namespace FATFS {
class Volume;
// mode bits
#define FAT_READ_ONLY 1
#define FAT_HIDDEN 2
#define FAT_SYSTEM 4
#define FAT_VOLUME 8
#define FAT_SUBDIR 16
#define FAT_ARCHIVE 32
#define read32(buffer,off) \
B_LENDIAN_TO_HOST_INT32(*(uint32 *)&buffer[off])
#define read16(buffer,off) \
B_LENDIAN_TO_HOST_INT16(*(uint16 *)&buffer[off])
enum name_lengths {
FATFS_BASENAME_LENGTH = 8,
FATFS_EXTNAME_LENGTH = 3,
FATFS_NAME_LENGTH = 12,
};
status_t get_root_block(int fDevice, char *buffer, int32 blockSize, off_t partitionSize);
} // namespace FATFS
#endif /* FATFS_H */