The boot loader now has tarfs support needed for booting from CD-ROM.
It expects the zipped TAR at offset 192 kB on the boot image. This work was mostly done by Ingo during BeGeistert. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14343 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
b67b9d8c87
commit
85a53ea280
@ -18,6 +18,7 @@ UsePrivateHeaders [ FDirName storage ] ;
|
||||
|
||||
BOOT_SUPPORT_FILE_SYSTEM_BFS
|
||||
BOOT_SUPPORT_FILE_SYSTEM_AMIGA_FFS
|
||||
BOOT_SUPPORT_FILE_SYSTEM_TARFS
|
||||
;
|
||||
|
||||
defines = [ FDefines $(defines) ] ;
|
||||
|
@ -1,5 +1,6 @@
|
||||
SubDir OBOS_TOP src system boot loader file_systems ;
|
||||
|
||||
SubInclude OBOS_TOP src system boot loader file_systems amiga_ffs ;
|
||||
SubInclude OBOS_TOP src system boot loader file_systems bfs ;
|
||||
SubInclude OBOS_TOP src system boot loader file_systems hfs_plus ;
|
||||
SubInclude OBOS_TOP src system boot loader file_systems amiga_ffs ;
|
||||
SubInclude OBOS_TOP src system boot loader file_systems tarfs ;
|
||||
|
19
src/system/boot/loader/file_systems/tarfs/Jamfile
Normal file
19
src/system/boot/loader/file_systems/tarfs/Jamfile
Normal file
@ -0,0 +1,19 @@
|
||||
SubDir OBOS_TOP src system boot loader file_systems tarfs ;
|
||||
|
||||
UseHeaders [ FDirName $(OBOS_TOP) headers libs zlib ] ;
|
||||
|
||||
UsePrivateHeaders [ FDirName kernel boot platform $(OBOS_BOOT_PLATFORM) ] ;
|
||||
UsePrivateHeaders [ FDirName kernel disk_device_manager ] ;
|
||||
UsePrivateHeaders shared storage ;
|
||||
SubDirHdrs $(OBOS_TOP) headers libs zlib ;
|
||||
|
||||
SubDirC++Flags -fno-rtti ;
|
||||
#SubDirCcFlags -DGUNZIP=1 ;
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(OBOS_TOP) src libs zlib ] ;
|
||||
|
||||
KernelStaticLibrary boot_tarfs :
|
||||
tarfs.cpp
|
||||
inflate.c
|
||||
: -fno-pic
|
||||
;
|
616
src/system/boot/loader/file_systems/tarfs/tarfs.cpp
Normal file
616
src/system/boot/loader/file_systems/tarfs/tarfs.cpp
Normal file
@ -0,0 +1,616 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, bonefish@cs.tu-berlin.de. All rights reserved.
|
||||
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "tarfs.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <OS.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <boot/partitions.h>
|
||||
#include <boot/platform.h>
|
||||
#include <util/kernel_cpp.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
|
||||
static const uint32 kCompressedArchiveOffset = 192 * 1024; // at 192 kB
|
||||
static const size_t kTarRegionSize = 4 * 1024 * 1024; // 4 MB
|
||||
|
||||
namespace TarFS {
|
||||
|
||||
struct RegionDelete {
|
||||
inline void operator()(void *memory)
|
||||
{
|
||||
platform_free_region(memory, kTarRegionSize);
|
||||
}
|
||||
};
|
||||
|
||||
struct RegionDeleter : BPrivate::AutoDeleter<void, RegionDelete> {
|
||||
RegionDeleter() : BPrivate::AutoDeleter<void, RegionDelete>() {}
|
||||
RegionDeleter(void *memory) : BPrivate::AutoDeleter<void, RegionDelete>(memory) {}
|
||||
};
|
||||
|
||||
class Directory;
|
||||
|
||||
class Entry : public DoublyLinkedListLinkImpl<Entry> {
|
||||
public:
|
||||
Entry(const char *name) : fName(name) {
|
||||
printf("created Entry %p: %s\n", this, fName);
|
||||
}
|
||||
virtual ~Entry() {}
|
||||
|
||||
const char *Name() const { return fName; }
|
||||
virtual ::Node *ToNode() = 0;
|
||||
virtual TarFS::Directory *ToTarDirectory() { return NULL; }
|
||||
|
||||
protected:
|
||||
const char *fName;
|
||||
};
|
||||
|
||||
|
||||
typedef DoublyLinkedList<TarFS::Entry> EntryList;
|
||||
typedef EntryList::Iterator EntryIterator;
|
||||
|
||||
|
||||
class Node : public ::Node, public Entry {
|
||||
public:
|
||||
Node(tar_header *header, const char *name);
|
||||
virtual ~Node();
|
||||
|
||||
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 ::Node *ToNode() { return this; }
|
||||
|
||||
private:
|
||||
tar_header *fHeader;
|
||||
off_t fSize;
|
||||
};
|
||||
|
||||
|
||||
class Directory : public ::Directory, public Entry {
|
||||
public:
|
||||
Directory(const char *name);
|
||||
virtual ~Directory();
|
||||
|
||||
virtual status_t Open(void **_cookie, int mode);
|
||||
virtual status_t Close(void *cookie);
|
||||
|
||||
virtual status_t GetName(char *nameBuffer, size_t bufferSize) const;
|
||||
|
||||
virtual TarFS::Entry *LookupEntry(const char *name);
|
||||
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 ::Node *ToNode() { return this; };
|
||||
virtual TarFS::Directory *ToTarDirectory() { return this; }
|
||||
|
||||
status_t AddDirectory(char *dirName, TarFS::Directory **_dir = NULL);
|
||||
status_t AddFile(tar_header *header);
|
||||
|
||||
private:
|
||||
typedef ::Directory _inherited;
|
||||
|
||||
EntryList fEntries;
|
||||
};
|
||||
|
||||
class Volume : public TarFS::Directory {
|
||||
public:
|
||||
Volume();
|
||||
~Volume();
|
||||
|
||||
status_t Init(boot::Partition *partition);
|
||||
|
||||
TarFS::Directory *Root() { return this; }
|
||||
};
|
||||
|
||||
} // namespace TarFS
|
||||
|
||||
//using namespace TarFS;
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
bool
|
||||
skip_gzip_header(z_stream *stream)
|
||||
{
|
||||
uint8 *buffer = (uint8 *)stream->next_in;
|
||||
|
||||
// check magic and skip method
|
||||
if (buffer[0] != 0x1f || buffer[1] != 0x8b)
|
||||
return false;
|
||||
|
||||
uint32 offset = 3;
|
||||
|
||||
// we need the flags field to determine the length of the header
|
||||
int flags = buffer[offset++];
|
||||
|
||||
offset += 6;
|
||||
|
||||
if ((flags & 0x04) != 0) {
|
||||
// skip extra field
|
||||
offset += buffer[offset++] | (buffer[offset++] << 8);
|
||||
if (offset >= stream->avail_in)
|
||||
return false;
|
||||
}
|
||||
if ((flags & 0x08) != 0) {
|
||||
// skip original name
|
||||
while (buffer[offset++])
|
||||
;
|
||||
}
|
||||
if ((flags & 0x10) != 0) {
|
||||
// skip comment
|
||||
while (buffer[offset++])
|
||||
;
|
||||
}
|
||||
if ((flags & 0x02) != 0) {
|
||||
// skip CRC
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
if (offset >= stream->avail_in)
|
||||
return false;
|
||||
|
||||
stream->next_in += offset;
|
||||
stream->avail_in -= offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
TarFS::Node::Node(tar_header *header, const char *name)
|
||||
:
|
||||
TarFS::Entry(name),
|
||||
fHeader(header)
|
||||
{
|
||||
fSize = strtol(header->size, NULL, 8);
|
||||
}
|
||||
|
||||
|
||||
TarFS::Node::~Node()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
TarFS::Node::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
|
||||
{
|
||||
if (pos < 0 || !buffer)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (pos >= fSize || bufferSize == 0)
|
||||
return 0;
|
||||
|
||||
size_t toRead = fSize - pos;
|
||||
if (toRead > bufferSize)
|
||||
toRead = bufferSize;
|
||||
|
||||
memcpy(buffer, (char*)fHeader + 512 + pos, toRead);
|
||||
|
||||
return toRead;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
TarFS::Node::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
|
||||
{
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TarFS::Node::GetName(char *nameBuffer, size_t bufferSize) const
|
||||
{
|
||||
return strlcpy(nameBuffer, Name(), bufferSize) >= bufferSize ? B_BUFFER_OVERFLOW : B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
TarFS::Directory::Directory(const char *name)
|
||||
: TarFS::Entry(name)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TarFS::Directory::~Directory()
|
||||
{
|
||||
while (TarFS::Entry *entry = fEntries.Head()) {
|
||||
fEntries.Remove(entry);
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TarFS::Directory::Open(void **_cookie, int mode)
|
||||
{
|
||||
_inherited::Open(_cookie, mode);
|
||||
|
||||
EntryIterator *iterator = new EntryIterator(fEntries.GetIterator());
|
||||
if (iterator == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
*_cookie = iterator;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TarFS::Directory::Close(void *cookie)
|
||||
{
|
||||
_inherited::Close(cookie);
|
||||
|
||||
delete (EntryIterator *)cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TarFS::Directory::GetName(char *nameBuffer, size_t bufferSize) const
|
||||
{
|
||||
return strlcpy(nameBuffer, Name(), bufferSize) >= bufferSize ? B_BUFFER_OVERFLOW : B_OK;
|
||||
}
|
||||
|
||||
|
||||
TarFS::Entry *
|
||||
TarFS::Directory::LookupEntry(const char *name)
|
||||
{
|
||||
EntryIterator iterator(fEntries.GetIterator());
|
||||
|
||||
while (iterator.HasNext()) {
|
||||
TarFS::Entry *entry = iterator.Next();
|
||||
if (strcmp(name, entry->Name()) == 0)
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
::Node *
|
||||
TarFS::Directory::Lookup(const char *name, bool /*traverseLinks*/)
|
||||
{
|
||||
if (TarFS::Entry *entry = LookupEntry(name)) {
|
||||
entry->ToNode()->Acquire();
|
||||
// our entries are not supposed to be deleted after use
|
||||
return entry->ToNode();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TarFS::Directory::GetNextEntry(void *_cookie, char *name, size_t size)
|
||||
{
|
||||
EntryIterator *iterator = (EntryIterator *)_cookie;
|
||||
TarFS::Entry *entry = iterator->Next();
|
||||
|
||||
if (entry != NULL) {
|
||||
strlcpy(name, entry->Name(), size);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TarFS::Directory::GetNextNode(void *_cookie, Node **_node)
|
||||
{
|
||||
EntryIterator *iterator = (EntryIterator *)_cookie;
|
||||
TarFS::Entry *entry = iterator->Next();
|
||||
|
||||
if (entry != NULL) {
|
||||
*_node = entry->ToNode();
|
||||
return B_OK;
|
||||
}
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TarFS::Directory::Rewind(void *_cookie)
|
||||
{
|
||||
EntryIterator *iterator = (EntryIterator *)_cookie;
|
||||
*iterator = fEntries.GetIterator();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TarFS::Directory::AddDirectory(char *dirName, TarFS::Directory **_dir)
|
||||
{
|
||||
char *subDir = strchr(dirName, '/');
|
||||
if (subDir) {
|
||||
// skip slashes
|
||||
while (*subDir == '/') {
|
||||
*subDir = '\0';
|
||||
subDir++;
|
||||
}
|
||||
|
||||
if (*subDir == '\0') {
|
||||
// a trailing slash
|
||||
subDir = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// check, whether the directory does already exist
|
||||
Entry *entry = LookupEntry(dirName);
|
||||
TarFS::Directory *dir = (entry ? entry->ToTarDirectory() : NULL);
|
||||
if (entry) {
|
||||
if (!dir)
|
||||
return B_ERROR;
|
||||
} else {
|
||||
// doesn't exist yet -- create it
|
||||
dir = new TarFS::Directory(dirName);
|
||||
if (!dir)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fEntries.Add(dir);
|
||||
}
|
||||
|
||||
// recursively create the subdirectories
|
||||
if (subDir) {
|
||||
status_t error = dir->AddDirectory(subDir, &dir);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (_dir)
|
||||
*_dir = dir;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TarFS::Directory::AddFile(tar_header *header)
|
||||
{
|
||||
char *leaf = strrchr(header->name, '/');
|
||||
char *dirName = NULL;
|
||||
if (leaf) {
|
||||
dirName = header->name;
|
||||
*leaf = '\0';
|
||||
leaf++;
|
||||
} else
|
||||
leaf = header->name;
|
||||
|
||||
// create the parent directory
|
||||
TarFS::Directory *dir = this;
|
||||
if (dirName) {
|
||||
status_t error = AddDirectory(dirName, &dir);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
}
|
||||
|
||||
// create the node
|
||||
TarFS::Node *file = new TarFS::Node(header, leaf);
|
||||
if (!file)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
dir->fEntries.Add(file);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TarFS::Directory::IsEmpty()
|
||||
{
|
||||
return fEntries.IsEmpty();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
TarFS::Volume::Volume()
|
||||
: TarFS::Directory("CD/Floppy Boot Disk")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TarFS::Volume::~Volume()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TarFS::Volume::Init(boot::Partition *partition)
|
||||
{
|
||||
void *cookie;
|
||||
status_t error = partition->Open(&cookie, O_RDONLY);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
struct PartitionCloser {
|
||||
boot::Partition *partition;
|
||||
void *cookie;
|
||||
|
||||
PartitionCloser(boot::Partition *partition, void *cookie)
|
||||
: partition(partition),
|
||||
cookie(cookie)
|
||||
{
|
||||
}
|
||||
|
||||
~PartitionCloser()
|
||||
{
|
||||
partition->Close(cookie);
|
||||
}
|
||||
} _(partition, cookie);
|
||||
|
||||
RegionDeleter regionDeleter;
|
||||
|
||||
char *out = NULL;
|
||||
|
||||
char in[512];
|
||||
z_stream zStream = {
|
||||
(Bytef*)in, // next in
|
||||
sizeof(in), // avail in
|
||||
0, // total in
|
||||
NULL, // next out
|
||||
0, // avail out
|
||||
0, // total out
|
||||
0, // msg
|
||||
0, // state
|
||||
Z_NULL, // zalloc
|
||||
Z_NULL, // zfree
|
||||
Z_NULL, // opaque
|
||||
0, // data type
|
||||
0, // adler
|
||||
0, // reserved
|
||||
};
|
||||
|
||||
int status;
|
||||
uint32 offset = kCompressedArchiveOffset;
|
||||
|
||||
do {
|
||||
if (partition->ReadAt(cookie, offset, in, sizeof(in)) != sizeof(in)) {
|
||||
status = Z_STREAM_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
zStream.avail_in = sizeof(in);
|
||||
zStream.next_in = (Bytef *)in;
|
||||
|
||||
if (offset == kCompressedArchiveOffset) {
|
||||
// check and skip gzip header
|
||||
if (!skip_gzip_header(&zStream))
|
||||
return B_BAD_DATA;
|
||||
|
||||
if (platform_allocate_region((void **)&out, kTarRegionSize,
|
||||
B_READ_AREA | B_WRITE_AREA) != B_OK)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
regionDeleter.SetTo(out);
|
||||
zStream.avail_out = kTarRegionSize;
|
||||
zStream.next_out = (Bytef *)out;
|
||||
|
||||
status = inflateInit2(&zStream, -15);
|
||||
if (status != Z_OK)
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
status = inflate(&zStream, Z_SYNC_FLUSH);
|
||||
offset += sizeof(in);
|
||||
|
||||
if (zStream.avail_in != 0 && status != Z_STREAM_END)
|
||||
printf("buhuuu");
|
||||
} while (status == Z_OK);
|
||||
|
||||
inflateEnd(&zStream);
|
||||
|
||||
if (status != Z_STREAM_END)
|
||||
return B_BAD_DATA;
|
||||
|
||||
status = B_OK;
|
||||
|
||||
// parse the tar file
|
||||
char *block = out;
|
||||
int blockCount = zStream.total_out / BLOCK_SIZE;
|
||||
int blockIndex = 0;
|
||||
|
||||
while (blockIndex < blockCount) {
|
||||
// check header
|
||||
tar_header *header = (tar_header*)(block + blockIndex * BLOCK_SIZE);
|
||||
//dump_header(*header);
|
||||
|
||||
if (header->magic[0] == '\0')
|
||||
break;
|
||||
|
||||
if (strcmp(header->magic, kTarHeaderMagic) != 0) {
|
||||
if (strcmp(header->magic, kOldTarHeaderMagic) != 0) {
|
||||
fprintf(stderr, "Bad tar header magic in block %d.\n",
|
||||
blockIndex);
|
||||
status = B_BAD_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
off_t size = strtol(header->size, NULL, 8);
|
||||
|
||||
// TODO: this is old-style GNU tar which probably won't work with newer ones...
|
||||
switch (header->type) {
|
||||
case TAR_FILE:
|
||||
case TAR_FILE2:
|
||||
status = AddFile(header);
|
||||
break;
|
||||
|
||||
case TAR_DIRECTORY:
|
||||
status = AddDirectory(header->name, NULL);
|
||||
break;
|
||||
|
||||
case TAR_LONG_NAME:
|
||||
// this is a long file name
|
||||
// TODO: read long name
|
||||
default:
|
||||
// unsupported type
|
||||
status = B_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// next block
|
||||
blockIndex += (size + 2 * BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||
}
|
||||
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
regionDeleter.Detach();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
static status_t
|
||||
tarfs_get_file_system(boot::Partition *partition, ::Directory **_root)
|
||||
{
|
||||
// TODO: Who owns the Volume object created here?
|
||||
TarFS::Volume *volume = new TarFS::Volume;
|
||||
if (volume == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
if (volume->Init(partition) < B_OK) {
|
||||
delete volume;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
*_root = volume->Root();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
file_system_module_info gTarFileSystemModule = {
|
||||
"file_systems/tarfs/v1",
|
||||
kPartitionTypeTarFS,
|
||||
tarfs_get_file_system
|
||||
};
|
||||
|
45
src/system/boot/loader/file_systems/tarfs/tarfs.h
Normal file
45
src/system/boot/loader/file_systems/tarfs/tarfs.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, bonefish@cs.tu-berlin.de. All rights reserved.
|
||||
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef TAR_FS_H
|
||||
#define TAR_FS_H
|
||||
|
||||
|
||||
enum {
|
||||
BLOCK_SIZE = 512,
|
||||
};
|
||||
|
||||
struct tar_header {
|
||||
char name[100];
|
||||
char mode[8];
|
||||
char uid[8];
|
||||
char gid[8];
|
||||
char size[12];
|
||||
char modification_time[12];
|
||||
char check_sum[8];
|
||||
char type;
|
||||
char linkname[100];
|
||||
char magic[6];
|
||||
char version[2];
|
||||
char user_name[32];
|
||||
char group_name[32];
|
||||
char device_major[8];
|
||||
char device_minor[8];
|
||||
char prefix[155];
|
||||
};
|
||||
|
||||
static const char *kTarHeaderMagic = "ustar";
|
||||
static const char *kOldTarHeaderMagic = "ustar ";
|
||||
|
||||
// the relevant entry types
|
||||
enum {
|
||||
TAR_FILE = '0',
|
||||
TAR_FILE2 = '\0',
|
||||
TAR_DIRECTORY = '5',
|
||||
TAR_LONG_NAME = 'L',
|
||||
};
|
||||
|
||||
#endif // TAR_FS_H
|
@ -57,6 +57,9 @@ static file_system_module_info *sFileSystemModules[] = {
|
||||
#ifdef BOOT_SUPPORT_FILE_SYSTEM_HFS_PLUS
|
||||
&gHFSPlusFileSystemModule,
|
||||
#endif
|
||||
#ifdef BOOT_SUPPORT_FILE_SYSTEM_TARFS
|
||||
&gTarFileSystemModule,
|
||||
#endif
|
||||
};
|
||||
static const int32 sNumFileSystemModules = sizeof(sFileSystemModules) / sizeof(file_system_module_info *);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user