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:
parent
a04a170937
commit
2cf4975b4b
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 ;
|
||||
|
74
src/system/boot/loader/file_systems/fat/CachedBlock.cpp
Normal file
74
src/system/boot/loader/file_systems/fat/CachedBlock.cpp
Normal 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;
|
||||
}
|
||||
|
41
src/system/boot/loader/file_systems/fat/CachedBlock.h
Normal file
41
src/system/boot/loader/file_systems/fat/CachedBlock.h
Normal 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 */
|
298
src/system/boot/loader/file_systems/fat/Directory.cpp
Normal file
298
src/system/boot/loader/file_systems/fat/Directory.cpp
Normal 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
|
51
src/system/boot/loader/file_systems/fat/Directory.h
Normal file
51
src/system/boot/loader/file_systems/fat/Directory.h
Normal 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 */
|
110
src/system/boot/loader/file_systems/fat/File.cpp
Normal file
110
src/system/boot/loader/file_systems/fat/File.cpp
Normal 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
|
43
src/system/boot/loader/file_systems/fat/File.h
Normal file
43
src/system/boot/loader/file_systems/fat/File.h
Normal 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 */
|
24
src/system/boot/loader/file_systems/fat/Jamfile
Normal file
24
src/system/boot/loader/file_systems/fat/Jamfile
Normal 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
|
||||
;
|
268
src/system/boot/loader/file_systems/fat/Stream.cpp
Normal file
268
src/system/boot/loader/file_systems/fat/Stream.cpp
Normal 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;
|
||||
}
|
57
src/system/boot/loader/file_systems/fat/Stream.h
Normal file
57
src/system/boot/loader/file_systems/fat/Stream.h
Normal 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 */
|
299
src/system/boot/loader/file_systems/fat/Volume.cpp
Normal file
299
src/system/boot/loader/file_systems/fat/Volume.cpp
Normal 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
|
||||
};
|
||||
|
85
src/system/boot/loader/file_systems/fat/Volume.h
Normal file
85
src/system/boot/loader/file_systems/fat/Volume.h
Normal 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 */
|
49
src/system/boot/loader/file_systems/fat/fatfs.cpp
Normal file
49
src/system/boot/loader/file_systems/fat/fatfs.cpp
Normal 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
|
||||
|
42
src/system/boot/loader/file_systems/fat/fatfs.h
Normal file
42
src/system/boot/loader/file_systems/fat/fatfs.h
Normal 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 */
|
||||
|
Loading…
Reference in New Issue
Block a user