Add libmount.
This commit is contained in:
parent
aff8f4d89c
commit
e6a1cd6dee
1
Makefile
1
Makefile
|
@ -9,6 +9,7 @@ libc \
|
||||||
libm \
|
libm \
|
||||||
libpthread \
|
libpthread \
|
||||||
dispd \
|
dispd \
|
||||||
|
libmount \
|
||||||
bench \
|
bench \
|
||||||
carray \
|
carray \
|
||||||
editor \
|
editor \
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
libmount.a
|
||||||
|
*.o
|
|
@ -0,0 +1,46 @@
|
||||||
|
SOFTWARE_MEANT_FOR_SORTIX=1
|
||||||
|
include ../build-aux/platform.mak
|
||||||
|
include ../build-aux/compiler.mak
|
||||||
|
include ../build-aux/version.mak
|
||||||
|
include ../build-aux/dirs.mak
|
||||||
|
|
||||||
|
OPTLEVEL?=$(DEFAULT_OPTLEVEL)
|
||||||
|
CFLAGS?=$(OPTLEVEL)
|
||||||
|
|
||||||
|
CFLAGS:=$(CFLAGS) -Wall -Wextra
|
||||||
|
CPPFLAGS:=$(CPPFLAGS) -Iinclude
|
||||||
|
|
||||||
|
OBJS:=\
|
||||||
|
biosboot.o \
|
||||||
|
blockdevice.o \
|
||||||
|
devices.o \
|
||||||
|
crc32.o \
|
||||||
|
ext2.o \
|
||||||
|
extended.o \
|
||||||
|
filesystem.o \
|
||||||
|
gpt.o \
|
||||||
|
harddisk.o \
|
||||||
|
mbr.o \
|
||||||
|
partition.o \
|
||||||
|
uuid.o \
|
||||||
|
|
||||||
|
all: libmount.a
|
||||||
|
|
||||||
|
.PHONY: all clean install
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) $(CPPFLAGS) -std=gnu11 -c $< -o $@
|
||||||
|
|
||||||
|
libmount.a: $(OBJS)
|
||||||
|
$(AR) rcs $@ $(OBJS)
|
||||||
|
|
||||||
|
install: libmount.a
|
||||||
|
mkdir -p $(DESTDIR)$(INCLUDEDIR)
|
||||||
|
cp -RTv include $(DESTDIR)$(INCLUDEDIR)
|
||||||
|
mkdir -p $(DESTDIR)$(LIBDIR)
|
||||||
|
cp libmount.a $(DESTDIR)$(LIBDIR)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f libmount.a
|
||||||
|
rm -f $(OBJS)
|
||||||
|
rm -f *.o
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
biosboot.c
|
||||||
|
GPT bios boot partition.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <mount/biosboot.h>
|
||||||
|
#include <mount/blockdevice.h>
|
||||||
|
#include <mount/filesystem.h>
|
||||||
|
#include <mount/partition.h>
|
||||||
|
#include <mount/uuid.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static size_t biosboot_probe_amount(struct blockdevice* bdev)
|
||||||
|
{
|
||||||
|
(void) bdev;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool biosboot_probe(struct blockdevice* bdev,
|
||||||
|
const unsigned char* leading,
|
||||||
|
size_t amount)
|
||||||
|
{
|
||||||
|
(void) leading;
|
||||||
|
(void) amount;
|
||||||
|
struct partition* p = bdev->p;
|
||||||
|
if ( !p )
|
||||||
|
return false;
|
||||||
|
if ( p->table_type != PARTITION_TABLE_TYPE_GPT )
|
||||||
|
return false;
|
||||||
|
unsigned char uuid[16];
|
||||||
|
uuid_from_string(uuid, BIOSBOOT_GPT_TYPE_UUID);
|
||||||
|
return memcmp(p->gpt_type_guid, uuid, 16) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void biosboot_release(struct filesystem* fs)
|
||||||
|
{
|
||||||
|
if ( !fs )
|
||||||
|
return;
|
||||||
|
free(fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum filesystem_error biosboot_inspect(struct filesystem** fs_ptr,
|
||||||
|
struct blockdevice* bdev)
|
||||||
|
{
|
||||||
|
*fs_ptr = NULL;
|
||||||
|
struct filesystem* fs = CALLOC_TYPE(struct filesystem);
|
||||||
|
if ( !fs )
|
||||||
|
return FILESYSTEM_ERROR_ERRNO;
|
||||||
|
fs->bdev = bdev;
|
||||||
|
fs->handler = &biosboot_handler;
|
||||||
|
fs->handler_private = NULL;
|
||||||
|
fs->fstype_name = "biosboot";
|
||||||
|
return *fs_ptr = fs, FILESYSTEM_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct filesystem_handler biosboot_handler =
|
||||||
|
{
|
||||||
|
.handler_name = "biosboot",
|
||||||
|
.probe_amount = biosboot_probe_amount,
|
||||||
|
.probe = biosboot_probe,
|
||||||
|
.inspect = biosboot_inspect,
|
||||||
|
.release = biosboot_release,
|
||||||
|
};
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015, 2016.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
blockdevice.c
|
||||||
|
Block device abstraction.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ioleast.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <mount/blockdevice.h>
|
||||||
|
#include <mount/harddisk.h>
|
||||||
|
#include <mount/partition.h>
|
||||||
|
|
||||||
|
blksize_t blockdevice_logical_block_size(const struct blockdevice* bdev)
|
||||||
|
{
|
||||||
|
while ( bdev->p )
|
||||||
|
bdev = bdev->p->parent_bdev;
|
||||||
|
assert(bdev->hd);
|
||||||
|
return bdev->hd->logical_block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blockdevice_check_reasonable_block_size(blksize_t size)
|
||||||
|
{
|
||||||
|
if ( size < 512 ) // Violates assumptions.
|
||||||
|
return false;
|
||||||
|
for ( blksize_t cmp = 512; cmp <= 65536; cmp *= 2 )
|
||||||
|
if ( cmp == size )
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t blockdevice_size(const struct blockdevice* bdev)
|
||||||
|
{
|
||||||
|
if ( bdev->p )
|
||||||
|
return bdev->p->length;
|
||||||
|
assert(bdev->hd);
|
||||||
|
return bdev->hd->st.st_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t blockdevice_preadall(const struct blockdevice* bdev,
|
||||||
|
void* buffer,
|
||||||
|
size_t count,
|
||||||
|
off_t off)
|
||||||
|
{
|
||||||
|
if ( off < 0 )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
while ( bdev->p )
|
||||||
|
{
|
||||||
|
if ( bdev->p->length < off )
|
||||||
|
return 0;
|
||||||
|
off_t available = bdev->p->length - off;
|
||||||
|
if ( (uintmax_t) available < (uintmax_t) count )
|
||||||
|
count = (size_t) available;
|
||||||
|
if ( __builtin_add_overflow(bdev->p->start, off, &off) )
|
||||||
|
return 0;
|
||||||
|
bdev = bdev->p->parent_bdev;
|
||||||
|
}
|
||||||
|
assert(bdev->hd);
|
||||||
|
return preadall(bdev->hd->fd, buffer, count, off);
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/* crc32.c -- compute the CRC-32 of a data stream
|
||||||
|
* Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler
|
||||||
|
* Adapted by Jonas 'Sortie' Termansen for Sortix libmount in 2015.
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
|
* arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software
|
||||||
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <mount/gpt.h>
|
||||||
|
|
||||||
|
uint32_t gpt_crc32(const void* buffer_ptr, size_t size)
|
||||||
|
{
|
||||||
|
/* generate a crc for every 8-bit value */
|
||||||
|
uint32_t poly = 0xedb88320UL;
|
||||||
|
uint32_t crc_table[256];
|
||||||
|
for ( unsigned int n = 0; n < 256; n++ )
|
||||||
|
{
|
||||||
|
uint32_t c = n;
|
||||||
|
for ( unsigned int k = 0; k < 8; k++ )
|
||||||
|
c = c & 1 ? poly ^ (c >> 1) : c >> 1;
|
||||||
|
crc_table[n] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculate bytewise crc of input buffer */
|
||||||
|
const unsigned char* buffer = (const unsigned char*) buffer_ptr;
|
||||||
|
uint32_t crc = 0xffffffffUL;
|
||||||
|
for ( size_t i = 0; i < size; i++ )
|
||||||
|
crc = crc_table[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8);
|
||||||
|
return crc ^ 0xffffffffUL;
|
||||||
|
}
|
|
@ -0,0 +1,170 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
devices.c
|
||||||
|
Locate block devices.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <mount/devices.h>
|
||||||
|
#include <mount/harddisk.h>
|
||||||
|
|
||||||
|
static bool is_partition_name(const char* path)
|
||||||
|
{
|
||||||
|
const char* name = path;
|
||||||
|
for ( size_t i = 0; path[i]; i++ )
|
||||||
|
if ( path[i] == '/' )
|
||||||
|
name = path + i + 1;
|
||||||
|
if ( !isalpha((unsigned char) *name) )
|
||||||
|
return false;
|
||||||
|
name++;
|
||||||
|
while ( isalpha((unsigned char) *name) )
|
||||||
|
name++;
|
||||||
|
if ( !isdigit((unsigned char) *name) )
|
||||||
|
return false;
|
||||||
|
name++;
|
||||||
|
while ( isdigit((unsigned char) *name) )
|
||||||
|
name++;
|
||||||
|
if ( *name != 'p' )
|
||||||
|
return false;
|
||||||
|
name++;
|
||||||
|
if ( !isdigit((unsigned char) *name) )
|
||||||
|
return false;
|
||||||
|
name++;
|
||||||
|
while ( isdigit((unsigned char) *name) )
|
||||||
|
name++;
|
||||||
|
return *name == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool devices_iterate_path(bool (*callback)(void*, const char*), void* ctx)
|
||||||
|
{
|
||||||
|
const char* dev_path = "/dev";
|
||||||
|
DIR* dir = opendir(dev_path);
|
||||||
|
if ( !dir )
|
||||||
|
return errno == ENOENT;
|
||||||
|
// TODO: This readdir loop can be derailed if the callback creates devices.
|
||||||
|
struct dirent* entry;
|
||||||
|
while ( (errno = 0, entry = readdir(dir)) )
|
||||||
|
{
|
||||||
|
if ( entry->d_name[0] == '.' )
|
||||||
|
continue;
|
||||||
|
if ( entry->d_type != DT_UNKNOWN && entry->d_type != DT_BLK )
|
||||||
|
continue;
|
||||||
|
// TODO: Remove this once partitions identify themselves as such and
|
||||||
|
// libmount doesn't allow using them as a real full block device.
|
||||||
|
if ( is_partition_name(entry->d_name) )
|
||||||
|
continue;
|
||||||
|
char* path;
|
||||||
|
if ( asprintf(&path, "%s/%s", dev_path, entry->d_name) < 0 )
|
||||||
|
return closedir(dir), false;
|
||||||
|
bool success = callback(ctx, path);
|
||||||
|
free(path);
|
||||||
|
if ( !success )
|
||||||
|
return closedir(dir), false;
|
||||||
|
}
|
||||||
|
bool success = errno == 0;
|
||||||
|
closedir(dir);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct devices_iterate_open
|
||||||
|
{
|
||||||
|
void* ctx;
|
||||||
|
bool (*callback)(void*, struct harddisk*);
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool devices_iterate_open_callback(void* ctx_ptr, const char* path)
|
||||||
|
{
|
||||||
|
struct devices_iterate_open* ctx = (struct devices_iterate_open*) ctx_ptr;
|
||||||
|
struct harddisk* hd = harddisk_openat(AT_FDCWD, path, O_RDWR);
|
||||||
|
if ( !hd )
|
||||||
|
{
|
||||||
|
int true_errno = errno;
|
||||||
|
struct stat st;
|
||||||
|
if ( lstat(path, 0) == 0 && !S_ISBLK(st.st_mode) )
|
||||||
|
return true;
|
||||||
|
errno = true_errno;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( !harddisk_inspect_blockdevice(hd) )
|
||||||
|
{
|
||||||
|
bool success = errno == ENOTBLK;
|
||||||
|
harddisk_close(hd);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
return ctx->callback(ctx->ctx, hd);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool devices_iterate_open(bool (*callback)(void*, struct harddisk*), void* ctx)
|
||||||
|
{
|
||||||
|
struct devices_iterate_open myctx;
|
||||||
|
myctx.ctx = ctx;
|
||||||
|
myctx.callback = callback;
|
||||||
|
return devices_iterate_path(devices_iterate_open_callback, &myctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct devices_open_all
|
||||||
|
{
|
||||||
|
struct harddisk** hds;
|
||||||
|
size_t hds_count;
|
||||||
|
size_t hds_allocated;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool devices_open_all_callback(void* ctx_ptr, struct harddisk* hd)
|
||||||
|
{
|
||||||
|
struct devices_open_all* ctx = (struct devices_open_all*) ctx_ptr;
|
||||||
|
if ( ctx->hds_count == ctx->hds_allocated )
|
||||||
|
{
|
||||||
|
size_t new_allocated = ctx->hds_allocated ? 2 * ctx->hds_allocated : 16;
|
||||||
|
struct harddisk** new_hds = (struct harddisk**)
|
||||||
|
reallocarray(ctx->hds, new_allocated, sizeof(struct harddisk*));
|
||||||
|
if ( !new_hds )
|
||||||
|
return harddisk_close(hd), false;
|
||||||
|
ctx->hds = new_hds;
|
||||||
|
ctx->hds_allocated = new_allocated;
|
||||||
|
}
|
||||||
|
ctx->hds[ctx->hds_count++] = hd;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool devices_open_all(struct harddisk*** hds_ptr, size_t* hds_count_ptr)
|
||||||
|
{
|
||||||
|
struct devices_open_all myctx;
|
||||||
|
myctx.hds = NULL;
|
||||||
|
myctx.hds_count = 0;
|
||||||
|
myctx.hds_allocated = 0;
|
||||||
|
if ( !devices_iterate_open(devices_open_all_callback, &myctx) )
|
||||||
|
{
|
||||||
|
for ( size_t i = 0; i < myctx.hds_count; i++ )
|
||||||
|
harddisk_close(myctx.hds[i]);
|
||||||
|
free(myctx.hds);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*hds_ptr = myctx.hds;
|
||||||
|
*hds_count_ptr = myctx.hds_count;
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,172 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
ext2.c
|
||||||
|
ext2 filesystem.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <endian.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <mount/blockdevice.h>
|
||||||
|
#include <mount/ext2.h>
|
||||||
|
#include <mount/filesystem.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
void ext2_superblock_decode(struct ext2_superblock* sb)
|
||||||
|
{
|
||||||
|
sb->s_inodes_count = le32toh(sb->s_inodes_count);
|
||||||
|
sb->s_blocks_count = le32toh(sb->s_blocks_count);
|
||||||
|
sb->s_r_blocks_count = le32toh(sb->s_r_blocks_count);
|
||||||
|
sb->s_free_blocks_count = le32toh(sb->s_free_blocks_count);
|
||||||
|
sb->s_free_inodes_count = le32toh(sb->s_free_inodes_count);
|
||||||
|
sb->s_first_data_block = le32toh(sb->s_first_data_block);
|
||||||
|
sb->s_log_block_size = le32toh(sb->s_log_block_size);
|
||||||
|
sb->s_log_frag_size = (int32_t) le32toh((uint32_t) sb->s_log_frag_size);
|
||||||
|
sb->s_blocks_per_group = le32toh(sb->s_blocks_per_group);
|
||||||
|
sb->s_frags_per_group = le32toh(sb->s_frags_per_group);
|
||||||
|
sb->s_inodes_per_group = le32toh(sb->s_inodes_per_group);
|
||||||
|
sb->s_mtime = le32toh(sb->s_mtime);
|
||||||
|
sb->s_wtime = le32toh(sb->s_wtime);
|
||||||
|
sb->s_mnt_count = le16toh(sb->s_mnt_count);
|
||||||
|
sb->s_max_mnt_count = le16toh(sb->s_max_mnt_count);
|
||||||
|
sb->s_magic = le16toh(sb->s_magic);
|
||||||
|
sb->s_state = le16toh(sb->s_state);
|
||||||
|
sb->s_errors = le16toh(sb->s_errors);
|
||||||
|
sb->s_minor_rev_level = le16toh(sb->s_minor_rev_level);
|
||||||
|
sb->s_lastcheck = le32toh(sb->s_lastcheck);
|
||||||
|
sb->s_checkinterval = le32toh(sb->s_checkinterval);
|
||||||
|
sb->s_creator_os = le32toh(sb->s_creator_os);
|
||||||
|
sb->s_rev_level = le32toh(sb->s_rev_level);
|
||||||
|
sb->s_def_resuid = le16toh(sb->s_def_resuid);
|
||||||
|
sb->s_def_resgid = le16toh(sb->s_def_resgid);
|
||||||
|
sb->s_first_ino = le32toh(sb->s_first_ino);
|
||||||
|
sb->s_inode_size = le16toh(sb->s_inode_size);
|
||||||
|
sb->s_block_group_nr = le16toh(sb->s_block_group_nr);
|
||||||
|
sb->s_feature_compat = le32toh(sb->s_feature_compat);
|
||||||
|
sb->s_feature_incompat = le32toh(sb->s_feature_incompat);
|
||||||
|
sb->s_feature_ro_compat = le32toh(sb->s_feature_ro_compat);
|
||||||
|
// s_uuid is endian agnostic.
|
||||||
|
// s_volume_name is endian agnostic.
|
||||||
|
// s_last_mounted is endian agnostic.
|
||||||
|
sb->s_algo_bitmap = le32toh(sb->s_algo_bitmap);
|
||||||
|
// s_prealloc_blocks is endian agnostic.
|
||||||
|
// s_prealloc_dir_blocks is endian agnostic.
|
||||||
|
sb->alignment0 = le16toh(sb->alignment0);
|
||||||
|
// s_journal_uuid is endian agnostic.
|
||||||
|
sb->s_journal_inum = le32toh(sb->s_journal_inum);
|
||||||
|
sb->s_journal_dev = le32toh(sb->s_journal_dev);
|
||||||
|
sb->s_last_orphan = le32toh(sb->s_last_orphan);
|
||||||
|
for ( size_t i = 0; i < 4; i++ )
|
||||||
|
sb->s_hash_seed[i] = le32toh(sb->s_hash_seed[i]);
|
||||||
|
// s_def_hash_version is endian agnostic.
|
||||||
|
// alignment1 is endian agnostic.
|
||||||
|
sb->s_default_mount_options = le32toh(sb->s_default_mount_options);
|
||||||
|
sb->s_first_meta_bg = le32toh(sb->s_first_meta_bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t ext2_probe_amount(struct blockdevice* bdev)
|
||||||
|
{
|
||||||
|
(void) bdev;
|
||||||
|
return 1024 + sizeof(struct ext2_superblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ext2_probe(struct blockdevice* bdev,
|
||||||
|
const unsigned char* leading,
|
||||||
|
size_t amount)
|
||||||
|
{
|
||||||
|
(void) bdev;
|
||||||
|
if ( amount < 1024 )
|
||||||
|
return false;
|
||||||
|
leading += 1024;
|
||||||
|
amount -= 1024;
|
||||||
|
if ( amount < sizeof(struct ext2_superblock) )
|
||||||
|
return false;
|
||||||
|
struct ext2_superblock sb;
|
||||||
|
memcpy(&sb, leading, sizeof(sb));
|
||||||
|
ext2_superblock_decode(&sb);
|
||||||
|
if ( sb.s_magic != EXT2_SUPER_MAGIC )
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ext2_private
|
||||||
|
{
|
||||||
|
struct ext2_superblock sb;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ext2_release(struct filesystem* fs)
|
||||||
|
{
|
||||||
|
if ( !fs )
|
||||||
|
return;
|
||||||
|
struct ext2_private* priv = (struct ext2_private*) fs->handler_private;
|
||||||
|
free(priv);
|
||||||
|
free(fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum filesystem_error ext2_inspect(struct filesystem** fs_ptr,
|
||||||
|
struct blockdevice* bdev)
|
||||||
|
{
|
||||||
|
*fs_ptr = NULL;
|
||||||
|
struct filesystem* fs = CALLOC_TYPE(struct filesystem);
|
||||||
|
if ( !fs )
|
||||||
|
return FILESYSTEM_ERROR_ERRNO;
|
||||||
|
struct ext2_private* priv = CALLOC_TYPE(struct ext2_private);
|
||||||
|
if ( !priv )
|
||||||
|
return free(fs), FILESYSTEM_ERROR_ERRNO;
|
||||||
|
fs->bdev = bdev;
|
||||||
|
fs->handler = &ext2_handler;
|
||||||
|
fs->handler_private = priv;
|
||||||
|
struct ext2_superblock* sb = &priv->sb;
|
||||||
|
if ( blockdevice_preadall(bdev, sb, sizeof(*sb), 1024) != sizeof(*sb) )
|
||||||
|
return ext2_release(fs), FILESYSTEM_ERROR_ERRNO;
|
||||||
|
ext2_superblock_decode(sb);
|
||||||
|
fs->fstype_name = "ext2";
|
||||||
|
fs->fsck = "fsck.ext2";
|
||||||
|
fs->driver = "extfs";
|
||||||
|
fs->flags |= FILESYSTEM_FLAG_UUID;
|
||||||
|
memcpy(&fs->uuid, sb->s_uuid, 16);
|
||||||
|
struct timespec now;
|
||||||
|
clock_gettime(CLOCK_REALTIME, &now);
|
||||||
|
time_t next_check = (time_t)
|
||||||
|
((uintmax_t) sb->s_lastcheck + (uintmax_t) sb->s_checkinterval);
|
||||||
|
if ( sb->s_state != EXT2_VALID_FS )
|
||||||
|
fs->flags |= FILESYSTEM_FLAG_FSCK_SHOULD |
|
||||||
|
FILESYSTEM_FLAG_FSCK_MUST;
|
||||||
|
else if ( sb->s_max_mnt_count && sb->s_max_mnt_count <= sb->s_mnt_count )
|
||||||
|
fs->flags |= FILESYSTEM_FLAG_FSCK_SHOULD;
|
||||||
|
else if ( sb->s_checkinterval && next_check <= now.tv_sec )
|
||||||
|
fs->flags |= FILESYSTEM_FLAG_FSCK_SHOULD;
|
||||||
|
return *fs_ptr = fs, FILESYSTEM_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct filesystem_handler ext2_handler =
|
||||||
|
{
|
||||||
|
.handler_name = "ext2",
|
||||||
|
.probe_amount = ext2_probe_amount,
|
||||||
|
.probe = ext2_probe,
|
||||||
|
.inspect = ext2_inspect,
|
||||||
|
.release = ext2_release,
|
||||||
|
};
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
extended.c
|
||||||
|
MBR extended partition.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <mount/blockdevice.h>
|
||||||
|
#include <mount/extended.h>
|
||||||
|
#include <mount/filesystem.h>
|
||||||
|
#include <mount/partition.h>
|
||||||
|
#include <mount/uuid.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static size_t extended_probe_amount(struct blockdevice* bdev)
|
||||||
|
{
|
||||||
|
(void) bdev;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool extended_probe(struct blockdevice* bdev,
|
||||||
|
const unsigned char* leading,
|
||||||
|
size_t amount)
|
||||||
|
{
|
||||||
|
(void) leading;
|
||||||
|
(void) amount;
|
||||||
|
struct partition* p = bdev->p;
|
||||||
|
if ( !p )
|
||||||
|
return false;
|
||||||
|
return p->table_type == PARTITION_TABLE_TYPE_MBR &&
|
||||||
|
(p->mbr_system_id == 0x05 ||
|
||||||
|
p->mbr_system_id == 0x0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void extended_release(struct filesystem* fs)
|
||||||
|
{
|
||||||
|
if ( !fs )
|
||||||
|
return;
|
||||||
|
free(fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum filesystem_error extended_inspect(struct filesystem** fs_ptr,
|
||||||
|
struct blockdevice* bdev)
|
||||||
|
{
|
||||||
|
*fs_ptr = NULL;
|
||||||
|
struct filesystem* fs = CALLOC_TYPE(struct filesystem);
|
||||||
|
if ( !fs )
|
||||||
|
return FILESYSTEM_ERROR_ERRNO;
|
||||||
|
fs->bdev = bdev;
|
||||||
|
fs->handler = &extended_handler;
|
||||||
|
fs->handler_private = NULL;
|
||||||
|
fs->fstype_name = "extended";
|
||||||
|
return *fs_ptr = fs, FILESYSTEM_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct filesystem_handler extended_handler =
|
||||||
|
{
|
||||||
|
.handler_name = "extended",
|
||||||
|
.probe_amount = extended_probe_amount,
|
||||||
|
.probe = extended_probe,
|
||||||
|
.inspect = extended_inspect,
|
||||||
|
.release = extended_release,
|
||||||
|
};
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
filesystem.c
|
||||||
|
Filesystem abstraction.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <mount/biosboot.h>
|
||||||
|
#include <mount/blockdevice.h>
|
||||||
|
#include <mount/ext2.h>
|
||||||
|
#include <mount/extended.h>
|
||||||
|
#include <mount/filesystem.h>
|
||||||
|
#include <mount/partition.h>
|
||||||
|
|
||||||
|
const char* filesystem_error_string(enum filesystem_error error)
|
||||||
|
{
|
||||||
|
switch ( error )
|
||||||
|
{
|
||||||
|
case FILESYSTEM_ERROR_NONE:
|
||||||
|
break;
|
||||||
|
case FILESYSTEM_ERROR_ABSENT:
|
||||||
|
return "No filesystem found";
|
||||||
|
case FILESYSTEM_ERROR_UNRECOGNIZED:
|
||||||
|
return "Unrecognized filesystem type";
|
||||||
|
case FILESYSTEM_ERROR_ERRNO:
|
||||||
|
return (const char*) strerror(errno);
|
||||||
|
}
|
||||||
|
return "Unknown error condition";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct filesystem_handler* filesystem_handlers[] =
|
||||||
|
{
|
||||||
|
&biosboot_handler,
|
||||||
|
&extended_handler,
|
||||||
|
&ext2_handler,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void filesystem_release(struct filesystem* fs)
|
||||||
|
{
|
||||||
|
if ( !fs || !fs->handler )
|
||||||
|
return;
|
||||||
|
fs->handler->release(fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum filesystem_error
|
||||||
|
blockdevice_inspect_filesystem(struct filesystem** fs_ptr,
|
||||||
|
struct blockdevice* bdev)
|
||||||
|
{
|
||||||
|
*fs_ptr = NULL;
|
||||||
|
size_t leading_size = 65536;
|
||||||
|
for ( size_t i = 0; filesystem_handlers[i]; i++ )
|
||||||
|
{
|
||||||
|
size_t amount = filesystem_handlers[i]->probe_amount(bdev);
|
||||||
|
if ( leading_size < amount )
|
||||||
|
leading_size = amount;
|
||||||
|
}
|
||||||
|
unsigned char* leading = (unsigned char*) malloc(leading_size);
|
||||||
|
if ( !leading )
|
||||||
|
return *fs_ptr = NULL, FILESYSTEM_ERROR_ERRNO;
|
||||||
|
size_t amount = blockdevice_preadall(bdev, leading, leading_size, 0);
|
||||||
|
if ( amount < leading_size && errno != EEOF )
|
||||||
|
return free(leading), *fs_ptr = NULL, FILESYSTEM_ERROR_ERRNO;
|
||||||
|
for ( size_t i = 0; filesystem_handlers[i]; i++ )
|
||||||
|
{
|
||||||
|
if ( !filesystem_handlers[i]->probe(bdev, leading, amount) )
|
||||||
|
continue;
|
||||||
|
free(leading);
|
||||||
|
return filesystem_handlers[i]->inspect(fs_ptr, bdev);
|
||||||
|
}
|
||||||
|
for ( size_t i = 0; i < amount; i++ )
|
||||||
|
if ( !leading[i] )
|
||||||
|
return free(leading), FILESYSTEM_ERROR_UNRECOGNIZED;
|
||||||
|
return free(leading), FILESYSTEM_ERROR_ABSENT;
|
||||||
|
}
|
|
@ -0,0 +1,325 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
gpt.c
|
||||||
|
GUID Partition Table.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <endian.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#include <mount/blockdevice.h>
|
||||||
|
#include <mount/gpt.h>
|
||||||
|
#include <mount/harddisk.h>
|
||||||
|
#include <mount/partition.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
void gpt_decode(struct gpt* v)
|
||||||
|
{
|
||||||
|
// signature is endian agnostic.
|
||||||
|
v->revision = le32toh(v->revision);
|
||||||
|
v->header_size = le32toh(v->header_size);
|
||||||
|
v->header_crc32 = le32toh(v->header_crc32);
|
||||||
|
v->reserved0 = le32toh(v->reserved0);
|
||||||
|
v->my_lba = le64toh(v->my_lba);
|
||||||
|
v->alternate_lba = le64toh(v->alternate_lba);
|
||||||
|
v->first_usable_lba = le64toh(v->first_usable_lba);
|
||||||
|
v->last_usable_lba = le64toh(v->last_usable_lba);
|
||||||
|
// disk_guid is endian agnostic.
|
||||||
|
v->partition_entry_lba = le64toh(v->partition_entry_lba);
|
||||||
|
v->number_of_partition_entries = le32toh(v->number_of_partition_entries);
|
||||||
|
v->size_of_partition_entry = le32toh(v->size_of_partition_entry);
|
||||||
|
v->partition_entry_array_crc32 = le32toh(v->partition_entry_array_crc32);
|
||||||
|
// reserved bytes are endian agnostic.
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpt_encode(struct gpt* v)
|
||||||
|
{
|
||||||
|
// signature is endian agnostic.
|
||||||
|
v->revision = htole32(v->revision);
|
||||||
|
v->header_size = htole32(v->header_size);
|
||||||
|
v->header_crc32 = htole32(v->header_crc32);
|
||||||
|
v->reserved0 = htole32(v->reserved0);
|
||||||
|
v->my_lba = htole64(v->my_lba);
|
||||||
|
v->alternate_lba = htole64(v->alternate_lba);
|
||||||
|
v->first_usable_lba = htole64(v->first_usable_lba);
|
||||||
|
v->last_usable_lba = htole64(v->last_usable_lba);
|
||||||
|
// disk_guid is endian agnostic.
|
||||||
|
v->partition_entry_lba = htole64(v->partition_entry_lba);
|
||||||
|
v->number_of_partition_entries = htole32(v->number_of_partition_entries);
|
||||||
|
v->size_of_partition_entry = htole32(v->size_of_partition_entry);
|
||||||
|
v->partition_entry_array_crc32 = htole32(v->partition_entry_array_crc32);
|
||||||
|
// reserved bytes are endian agnostic.
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpt_partition_decode(struct gpt_partition* v)
|
||||||
|
{
|
||||||
|
// partition_type_guid is endian agnostic.
|
||||||
|
// unique_partition_guid is endian agnostic.
|
||||||
|
v->starting_lba = le64toh(v->starting_lba);
|
||||||
|
v->ending_lba = le64toh(v->ending_lba);
|
||||||
|
v->attributes = le64toh(v->attributes);
|
||||||
|
for ( size_t i = 0; i < GPT_PARTITION_NAME_LENGTH; i++ )
|
||||||
|
v->partition_name[i] = le16toh(v->partition_name[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpt_partition_encode(struct gpt_partition* v)
|
||||||
|
{
|
||||||
|
// partition_type_guid is endian agnostic.
|
||||||
|
// unique_partition_guid is endian agnostic.
|
||||||
|
v->starting_lba = htole64(v->starting_lba);
|
||||||
|
v->ending_lba = htole64(v->ending_lba);
|
||||||
|
v->attributes = htole64(v->attributes);
|
||||||
|
for ( size_t i = 0; i < GPT_PARTITION_NAME_LENGTH; i++ )
|
||||||
|
v->partition_name[i] = htole16(v->partition_name[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* gpt_decode_utf16(uint16_t* string, size_t length)
|
||||||
|
{
|
||||||
|
mbstate_t ps;
|
||||||
|
memset(&ps, 0, sizeof(ps));
|
||||||
|
|
||||||
|
char* result = NULL;
|
||||||
|
size_t result_used = 0;
|
||||||
|
size_t result_length = 0;
|
||||||
|
|
||||||
|
for ( size_t i = 0; true; i++ )
|
||||||
|
{
|
||||||
|
wchar_t wc;
|
||||||
|
if ( length <= i )
|
||||||
|
wc = L'\0';
|
||||||
|
else if ( 0xDC00 <= string[i] && string[i] <= 0xDFFF )
|
||||||
|
return free(result), errno = EILSEQ, (char*) NULL;
|
||||||
|
else if ( 0xD800 <= string[i] && string[i] <= 0xDBFF )
|
||||||
|
{
|
||||||
|
uint16_t high = string[i] - 0xD800;
|
||||||
|
if ( i + 1 == length )
|
||||||
|
return free(result), errno = EILSEQ, (char*) NULL;
|
||||||
|
if ( !(0xDC00 <= string[i+1] && string[i] <= 0xDFFF) )
|
||||||
|
return free(result), errno = EILSEQ, (char*) NULL;
|
||||||
|
uint16_t low = string[++i] - 0xDC00;
|
||||||
|
wc = (((wchar_t) high << 10) | ((wchar_t) low << 0)) + 0x10000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
wc = (wchar_t) string[i++];
|
||||||
|
char mb[MB_CUR_MAX];
|
||||||
|
size_t amount = wcrtomb(mb, wc, &ps);
|
||||||
|
if ( amount == (size_t) -1 )
|
||||||
|
return free(result), (char*) NULL;
|
||||||
|
for ( size_t n = 0; n < amount; n++ )
|
||||||
|
{
|
||||||
|
if ( result_used == result_length )
|
||||||
|
{
|
||||||
|
// TODO: Potential overflow.
|
||||||
|
size_t new_length = result_length ? 2 * result_length : length;
|
||||||
|
char* new_result = (char*) realloc(result, new_length);
|
||||||
|
if ( !new_result )
|
||||||
|
return free(result), (char*) NULL;
|
||||||
|
result = new_result;
|
||||||
|
result_length = new_length;
|
||||||
|
}
|
||||||
|
result[result_used++] = mb[n];
|
||||||
|
}
|
||||||
|
if ( wc == L'\0' )
|
||||||
|
{
|
||||||
|
char* new_result = (char*) realloc(result, result_used);
|
||||||
|
if ( new_result )
|
||||||
|
result = new_result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpt_partition_table_release(struct gpt_partition_table* pt)
|
||||||
|
{
|
||||||
|
if ( !pt )
|
||||||
|
return;
|
||||||
|
free(pt->rpt);
|
||||||
|
free(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gpt_check_power_of_two(uintmax_t value,
|
||||||
|
uintmax_t low,
|
||||||
|
uintmax_t high)
|
||||||
|
{
|
||||||
|
for ( uintmax_t cmp = low; cmp <= high; cmp *= 2 )
|
||||||
|
if ( value == cmp )
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum partition_error
|
||||||
|
blockdevice_get_partition_table_gpt(struct partition_table** pt_ptr,
|
||||||
|
struct blockdevice* bdev)
|
||||||
|
{
|
||||||
|
*pt_ptr = NULL;
|
||||||
|
blksize_t logical_block_size = blockdevice_logical_block_size(bdev);
|
||||||
|
if ( !blockdevice_check_reasonable_block_size(logical_block_size) )
|
||||||
|
return errno = EINVAL, PARTITION_ERROR_ERRNO;
|
||||||
|
off_t device_size = blockdevice_size(bdev);
|
||||||
|
const char* device_path = bdev->p ? bdev->p->path : bdev->hd->path;
|
||||||
|
|
||||||
|
unsigned char* gpt_block = (unsigned char*) malloc(logical_block_size);
|
||||||
|
if ( !gpt_block )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
if ( blockdevice_preadall(bdev, gpt_block, logical_block_size,
|
||||||
|
1 * logical_block_size) != (size_t) logical_block_size )
|
||||||
|
return free(gpt_block), PARTITION_ERROR_ERRNO;
|
||||||
|
|
||||||
|
struct gpt gpt;
|
||||||
|
memcpy(&gpt, gpt_block, sizeof(gpt));
|
||||||
|
gpt_decode(&gpt);
|
||||||
|
|
||||||
|
if ( memcmp(gpt.signature, "EFI PART", 8) != 0 )
|
||||||
|
return PARTITION_ERROR_INVALID;
|
||||||
|
static_assert( 92 == sizeof(gpt) - sizeof(gpt.reserved1),
|
||||||
|
"92 == sizeof(gpt) - sizeof(gpt.reserved1)");
|
||||||
|
if ( gpt.header_size < 92 )
|
||||||
|
return free(gpt_block), PARTITION_ERROR_INVALID;
|
||||||
|
|
||||||
|
struct partition_table* pt = CALLOC_TYPE(struct partition_table);
|
||||||
|
if ( !pt )
|
||||||
|
return free(gpt_block), PARTITION_ERROR_ERRNO;
|
||||||
|
*pt_ptr = pt;
|
||||||
|
pt->type = PARTITION_TABLE_TYPE_GPT;
|
||||||
|
size_t pt__partitions_length = 0;
|
||||||
|
|
||||||
|
if ( logical_block_size < gpt.header_size )
|
||||||
|
return free(gpt_block), PARTITION_ERROR_HEADER_TOO_LARGE;
|
||||||
|
|
||||||
|
struct gpt_partition_table* gptpt = CALLOC_TYPE(struct gpt_partition_table);
|
||||||
|
if ( !gptpt )
|
||||||
|
return free(gpt_block), PARTITION_ERROR_ERRNO;
|
||||||
|
pt->raw_partition_table = gptpt;
|
||||||
|
memcpy(&gptpt->gpt, gpt_block, sizeof(gptpt->gpt));
|
||||||
|
|
||||||
|
struct gpt* check_gpt = (struct gpt*) gpt_block;
|
||||||
|
check_gpt->header_crc32 = 0;
|
||||||
|
uint32_t checksum = gpt_crc32(gpt_block, gpt.header_size);
|
||||||
|
free(gpt_block);
|
||||||
|
if ( checksum != gpt.header_crc32 )
|
||||||
|
return PARTITION_ERROR_CHECKSUM;
|
||||||
|
|
||||||
|
memcpy(pt->gpt_disk_guid, gpt.disk_guid, 16);
|
||||||
|
|
||||||
|
if ( !gpt_check_power_of_two(gpt.size_of_partition_entry,
|
||||||
|
sizeof(struct gpt_partition), 65536) )
|
||||||
|
return PARTITION_ERROR_INVALID;
|
||||||
|
if ( gpt.my_lba != 1 )
|
||||||
|
return PARTITION_ERROR_INVALID;
|
||||||
|
|
||||||
|
if ( gpt.my_lba >= gpt.first_usable_lba )
|
||||||
|
return PARTITION_ERROR_INVALID;
|
||||||
|
// TODO: Ensure nothing collides with anything else.
|
||||||
|
if ( gpt.partition_entry_lba <= 1 )
|
||||||
|
return PARTITION_ERROR_INVALID;
|
||||||
|
if ( gpt.last_usable_lba < gpt.first_usable_lba )
|
||||||
|
return PARTITION_ERROR_INVALID;
|
||||||
|
|
||||||
|
// TODO: Potential overflow.
|
||||||
|
pt->usable_start = (off_t) gpt.first_usable_lba * (off_t) logical_block_size;
|
||||||
|
pt->usable_end = ((off_t) gpt.last_usable_lba + 1) * (off_t) logical_block_size;
|
||||||
|
if ( device_size < pt->usable_end )
|
||||||
|
return PARTITION_ERROR_INVALID;
|
||||||
|
|
||||||
|
// TODO: Potential overflow.
|
||||||
|
size_t rpt_size = (size_t) gpt.size_of_partition_entry *
|
||||||
|
(size_t) gpt.number_of_partition_entries;
|
||||||
|
off_t rpt_off = (off_t) gpt.partition_entry_lba * (off_t) logical_block_size;
|
||||||
|
off_t rpt_end = rpt_off + rpt_off;
|
||||||
|
if ( pt->usable_start < rpt_end )
|
||||||
|
return PARTITION_ERROR_INVALID;
|
||||||
|
if ( !(gptpt->rpt = (unsigned char*) malloc(rpt_size)) )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
unsigned char* rpt = gptpt->rpt;
|
||||||
|
if ( blockdevice_preadall(bdev, rpt, rpt_size, rpt_off) != rpt_size )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
if ( gpt.partition_entry_array_crc32 != gpt_crc32(rpt, rpt_size) )
|
||||||
|
return PARTITION_ERROR_CHECKSUM;
|
||||||
|
|
||||||
|
for ( uint32_t i = 0; i < gpt.number_of_partition_entries; i++ )
|
||||||
|
{
|
||||||
|
size_t pentry_off = (size_t) i * (size_t) gpt.size_of_partition_entry;
|
||||||
|
struct gpt_partition pentry;
|
||||||
|
memcpy(&pentry, rpt + pentry_off, sizeof(pentry));
|
||||||
|
gpt_partition_decode(&pentry);
|
||||||
|
if ( memiszero(pentry.partition_type_guid, 16) )
|
||||||
|
continue;
|
||||||
|
if ( pentry.ending_lba < pentry.starting_lba )
|
||||||
|
return PARTITION_ERROR_END_BEFORE_START;
|
||||||
|
// TODO: Potential overflow.
|
||||||
|
uint64_t lba_count = (pentry.ending_lba - pentry.starting_lba) + 1;
|
||||||
|
off_t start = (off_t) pentry.starting_lba * (off_t) logical_block_size;
|
||||||
|
if ( start < pt->usable_start )
|
||||||
|
return PARTITION_ERROR_BEFORE_USABLE;
|
||||||
|
off_t length = (off_t) lba_count * (off_t) logical_block_size;
|
||||||
|
if ( pt->usable_end < start || pt->usable_end - start < length )
|
||||||
|
return PARTITION_ERROR_BEYOND_USABLE;
|
||||||
|
struct partition* p = CALLOC_TYPE(struct partition);
|
||||||
|
if ( !p )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
memset(&p->bdev, 0, sizeof(p->bdev));
|
||||||
|
p->bdev.p = p;
|
||||||
|
p->parent_bdev = bdev;
|
||||||
|
p->index = 1 + i;
|
||||||
|
p->start = start;
|
||||||
|
p->length = length;
|
||||||
|
p->type = PARTITION_TYPE_PRIMARY;
|
||||||
|
p->table_type = PARTITION_TABLE_TYPE_GPT;
|
||||||
|
memcpy(p->gpt_type_guid, pentry.partition_type_guid, 16);
|
||||||
|
memcpy(p->gpt_unique_guid, pentry.unique_partition_guid, 16);
|
||||||
|
p->gpt_attributes = pentry.attributes;
|
||||||
|
if ( !array_add((void***) &pt->partitions,
|
||||||
|
&pt->partitions_count,
|
||||||
|
&pt__partitions_length,
|
||||||
|
p) )
|
||||||
|
return free(p), PARTITION_ERROR_ERRNO;
|
||||||
|
if ( !(p->gpt_name = gpt_decode_utf16(pentry.partition_name,
|
||||||
|
GPT_PARTITION_NAME_LENGTH)) )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
if ( device_path &&
|
||||||
|
asprintf(&p->path, "%sp%u", device_path, p->index) < 0 )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(pt->partitions, pt->partitions_count, sizeof(pt->partitions[0]),
|
||||||
|
partition_compare_start_indirect);
|
||||||
|
for ( size_t i = 1; i < pt->partitions_count; i++ )
|
||||||
|
{
|
||||||
|
struct partition* a = pt->partitions[i-1];
|
||||||
|
struct partition* b = pt->partitions[i];
|
||||||
|
if ( partition_check_overlap(a, b->start, b->length) )
|
||||||
|
return PARTITION_ERROR_OVERLAP;
|
||||||
|
}
|
||||||
|
qsort(pt->partitions, pt->partitions_count, sizeof(pt->partitions[0]),
|
||||||
|
partition_compare_index_indirect);
|
||||||
|
|
||||||
|
return PARTITION_ERROR_NONE;
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
harddisk.c
|
||||||
|
Harddisk abstraction.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <mount/harddisk.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static char* atcgetblob(int fd, const char* name, size_t* size_ptr)
|
||||||
|
{
|
||||||
|
ssize_t size = tcgetblob(fd, name, NULL, 0);
|
||||||
|
if ( size < 0 )
|
||||||
|
return NULL;
|
||||||
|
char* result = (char*) malloc((size_t) size + 1);
|
||||||
|
if ( !result )
|
||||||
|
return NULL;
|
||||||
|
ssize_t second_size = tcgetblob(fd, name, result, (size_t) size);
|
||||||
|
if ( second_size != size )
|
||||||
|
return free(result), (char*) NULL;
|
||||||
|
result[(size_t) size] = '\0';
|
||||||
|
if ( size_ptr )
|
||||||
|
*size_ptr = (size_t) size;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct harddisk* harddisk_openat(int dirfd, const char* relpath, int rdwr)
|
||||||
|
{
|
||||||
|
struct harddisk* hd = CALLOC_TYPE(struct harddisk);
|
||||||
|
if ( !hd )
|
||||||
|
return (struct harddisk*) NULL;
|
||||||
|
memset(&hd->bdev, 0, sizeof(hd->bdev));
|
||||||
|
hd->bdev.hd = hd;
|
||||||
|
if ( (hd->fd = openat(dirfd, relpath, rdwr)) < 0 )
|
||||||
|
return harddisk_close(hd), (struct harddisk*) NULL;
|
||||||
|
if ( !(hd->path = canonicalize_file_name_at(dirfd, relpath)) )
|
||||||
|
return harddisk_close(hd), (struct harddisk*) NULL;
|
||||||
|
if ( fstat(hd->fd, &hd->st) < 0 )
|
||||||
|
return harddisk_close(hd), (struct harddisk*) NULL;
|
||||||
|
return hd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool harddisk_inspect_blockdevice(struct harddisk* hd)
|
||||||
|
{
|
||||||
|
if ( !S_ISBLK(hd->st.st_mode) )
|
||||||
|
return errno = ENOTBLK, false;
|
||||||
|
if ( tcgetblob(hd->fd, "harddisk-driver", NULL, 0) < 0 )
|
||||||
|
{
|
||||||
|
if ( errno == ENOENT )
|
||||||
|
errno = ENOTBLK;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( !(hd->driver = atcgetblob(hd->fd, "harddisk-driver", NULL)) ||
|
||||||
|
!(hd->model = atcgetblob(hd->fd, "harddisk-model", NULL)) ||
|
||||||
|
!(hd->serial = atcgetblob(hd->fd, "harddisk-serial", NULL)) )
|
||||||
|
return harddisk_close(hd), false;
|
||||||
|
char* str;
|
||||||
|
if ( !(str = atcgetblob(hd->fd, "harddisk-block-size", NULL)) )
|
||||||
|
return harddisk_close(hd), false;
|
||||||
|
hd->logical_block_size = (blksize_t) strtoumax(str, NULL, 10);
|
||||||
|
free(str);
|
||||||
|
if ( !(str = atcgetblob(hd->fd, "harddisk-cylinders", NULL)) )
|
||||||
|
return harddisk_close(hd), false;
|
||||||
|
hd->cylinders = (uint16_t) strtoul(str, NULL, 10);
|
||||||
|
free(str);
|
||||||
|
if ( !(str = atcgetblob(hd->fd, "harddisk-heads", NULL)) )
|
||||||
|
return harddisk_close(hd), false;
|
||||||
|
hd->heads = (uint16_t) strtoul(str, NULL, 10);
|
||||||
|
free(str);
|
||||||
|
if ( !(str = atcgetblob(hd->fd, "harddisk-sectors", NULL)) )
|
||||||
|
return harddisk_close(hd), false;
|
||||||
|
hd->sectors = (uint16_t) strtoul(str, NULL, 10);
|
||||||
|
free(str);
|
||||||
|
// TODO: To avoid potential overflow bugs (assuming malicious filesystem),
|
||||||
|
// reject ridiculous block sizes.
|
||||||
|
if ( 65536 < hd->logical_block_size )
|
||||||
|
return harddisk_close(hd), errno = EINVAL, false;
|
||||||
|
if ( hd->logical_block_size < 512 )
|
||||||
|
return harddisk_close(hd), errno = EINVAL, false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void harddisk_close(struct harddisk* hd)
|
||||||
|
{
|
||||||
|
if ( 0 <= hd->fd )
|
||||||
|
close(hd->fd);
|
||||||
|
free(hd->path);
|
||||||
|
free(hd->driver);
|
||||||
|
free(hd->model);
|
||||||
|
free(hd->serial);
|
||||||
|
free(hd);
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mount/biosboot.h
|
||||||
|
GPT bios boot partition.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_MOUNT_BIOSBOOT_H
|
||||||
|
#define INCLUDE_MOUNT_BIOSBOOT_H
|
||||||
|
|
||||||
|
#include <mount/filesystem.h>
|
||||||
|
|
||||||
|
#define BIOSBOOT_GPT_TYPE_UUID "48616821-4964-6f6e-744e-656564454649"
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const struct filesystem_handler biosboot_handler;
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mount/blockdevice.h
|
||||||
|
Block device abstraction.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_MOUNT_BLOCKDEVICE_H
|
||||||
|
#define INCLUDE_MOUNT_BLOCKDEVICE_H
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#if !defined(__cplusplus)
|
||||||
|
#include <stdbool.h>
|
||||||
|
#endif
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <mount/error.h>
|
||||||
|
|
||||||
|
struct filesystem;
|
||||||
|
struct harddisk;
|
||||||
|
struct partition;
|
||||||
|
struct partition_table;
|
||||||
|
|
||||||
|
struct blockdevice
|
||||||
|
{
|
||||||
|
struct harddisk* hd;
|
||||||
|
struct partition* p;
|
||||||
|
struct partition_table* pt;
|
||||||
|
struct filesystem* fs;
|
||||||
|
enum partition_error pt_error;
|
||||||
|
enum filesystem_error fs_error;
|
||||||
|
void* user_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
blksize_t blockdevice_logical_block_size(const struct blockdevice*);
|
||||||
|
bool blockdevice_check_reasonable_block_size(blksize_t);
|
||||||
|
off_t blockdevice_size(const struct blockdevice*);
|
||||||
|
size_t blockdevice_preadall(const struct blockdevice*, void*, size_t, off_t);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mount/devices.h
|
||||||
|
Locate block devices.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_MOUNT_DEVICES_H
|
||||||
|
#define INCLUDE_MOUNT_DEVICES_H
|
||||||
|
|
||||||
|
#if !defined(__cplusplus)
|
||||||
|
#include <stdbool.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct harddisk;
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool devices_iterate_path(bool (*)(void*, const char*), void*);
|
||||||
|
bool devices_iterate_open(bool (*)(void*, struct harddisk*), void*);
|
||||||
|
bool devices_open_all(struct harddisk***, size_t*);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mount/error.h
|
||||||
|
Error enumerations.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_MOUNT_ERROR_H
|
||||||
|
#define INCLUDE_MOUNT_ERROR_H
|
||||||
|
|
||||||
|
enum filesystem_error
|
||||||
|
{
|
||||||
|
FILESYSTEM_ERROR_NONE,
|
||||||
|
FILESYSTEM_ERROR_ABSENT,
|
||||||
|
FILESYSTEM_ERROR_UNRECOGNIZED,
|
||||||
|
FILESYSTEM_ERROR_ERRNO,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum partition_error
|
||||||
|
{
|
||||||
|
PARTITION_ERROR_NONE,
|
||||||
|
PARTITION_ERROR_ABSENT,
|
||||||
|
PARTITION_ERROR_UNRECOGNIZED,
|
||||||
|
PARTITION_ERROR_ERRNO,
|
||||||
|
PARTITION_ERROR_INVALID,
|
||||||
|
PARTITION_ERROR_HEADER_TOO_LARGE,
|
||||||
|
PARTITION_ERROR_CHECKSUM,
|
||||||
|
PARTITION_ERROR_OVERLAP,
|
||||||
|
PARTITION_ERROR_END_BEFORE_START,
|
||||||
|
PARTITION_ERROR_BEFORE_USABLE,
|
||||||
|
PARTITION_ERROR_BEYOND_DEVICE,
|
||||||
|
PARTITION_ERROR_BEYOND_EXTENDED,
|
||||||
|
PARTITION_ERROR_BEYOND_USABLE,
|
||||||
|
PARTITION_ERROR_TOO_EXTENDED,
|
||||||
|
PARTITION_ERROR_BAD_EXTENDED,
|
||||||
|
PARTITION_ERROR_NONLINEAR_EXTENDED,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mount/ext2.h
|
||||||
|
ext2 filesystem.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_MOUNT_EXT2_H
|
||||||
|
#define INCLUDE_MOUNT_EXT2_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <mount/filesystem.h>
|
||||||
|
|
||||||
|
static const uint16_t EXT2_SUPER_MAGIC = 0xEF53;
|
||||||
|
static const uint16_t EXT2_VALID_FS = 1;
|
||||||
|
static const uint16_t EXT2_ERROR_FS = 2;
|
||||||
|
|
||||||
|
struct ext2_superblock
|
||||||
|
{
|
||||||
|
uint32_t s_inodes_count;
|
||||||
|
uint32_t s_blocks_count;
|
||||||
|
uint32_t s_r_blocks_count;
|
||||||
|
uint32_t s_free_blocks_count;
|
||||||
|
uint32_t s_free_inodes_count;
|
||||||
|
uint32_t s_first_data_block;
|
||||||
|
uint32_t s_log_block_size;
|
||||||
|
int32_t s_log_frag_size;
|
||||||
|
uint32_t s_blocks_per_group;
|
||||||
|
uint32_t s_frags_per_group;
|
||||||
|
uint32_t s_inodes_per_group;
|
||||||
|
uint32_t s_mtime;
|
||||||
|
uint32_t s_wtime;
|
||||||
|
uint16_t s_mnt_count;
|
||||||
|
uint16_t s_max_mnt_count;
|
||||||
|
uint16_t s_magic;
|
||||||
|
uint16_t s_state;
|
||||||
|
uint16_t s_errors;
|
||||||
|
uint16_t s_minor_rev_level;
|
||||||
|
uint32_t s_lastcheck;
|
||||||
|
uint32_t s_checkinterval;
|
||||||
|
uint32_t s_creator_os;
|
||||||
|
uint32_t s_rev_level;
|
||||||
|
uint16_t s_def_resuid;
|
||||||
|
uint16_t s_def_resgid;
|
||||||
|
// EXT2_DYNAMIC_REV
|
||||||
|
uint32_t s_first_ino;
|
||||||
|
uint16_t s_inode_size;
|
||||||
|
uint16_t s_block_group_nr;
|
||||||
|
uint32_t s_feature_compat;
|
||||||
|
uint32_t s_feature_incompat;
|
||||||
|
uint32_t s_feature_ro_compat;
|
||||||
|
uint8_t s_uuid[16];
|
||||||
|
/*uint8_t*/ char s_volume_name[16];
|
||||||
|
/*uint8_t*/ char s_last_mounted[64];
|
||||||
|
uint32_t s_algo_bitmap;
|
||||||
|
// Performance Hints
|
||||||
|
uint8_t s_prealloc_blocks;
|
||||||
|
uint8_t s_prealloc_dir_blocks;
|
||||||
|
uint16_t alignment0;
|
||||||
|
// Journaling Support
|
||||||
|
uint8_t s_journal_uuid[16];
|
||||||
|
uint32_t s_journal_inum;
|
||||||
|
uint32_t s_journal_dev;
|
||||||
|
uint32_t s_last_orphan;
|
||||||
|
// Directory Indexing Support
|
||||||
|
uint32_t s_hash_seed[4];
|
||||||
|
uint8_t s_def_hash_version;
|
||||||
|
uint8_t alignment1[3];
|
||||||
|
// Other options
|
||||||
|
uint32_t s_default_mount_options;
|
||||||
|
uint32_t s_first_meta_bg;
|
||||||
|
uint8_t alignment2[760];
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const struct filesystem_handler ext2_handler;
|
||||||
|
|
||||||
|
void ext2_superblock_decode(struct ext2_superblock*);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mount/extended.h
|
||||||
|
MBR extended partition.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_MOUNT_EXTENDED_H
|
||||||
|
#define INCLUDE_MOUNT_EXTENDED_H
|
||||||
|
|
||||||
|
#include <mount/filesystem.h>
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const struct filesystem_handler extended_handler;
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mount/filesystem.h
|
||||||
|
Filesystem abstraction.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_MOUNT_FILESYSTEM_H
|
||||||
|
#define INCLUDE_MOUNT_FILESYSTEM_H
|
||||||
|
|
||||||
|
#if !defined(__cplusplus)
|
||||||
|
#include <stdbool.h>
|
||||||
|
#endif
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <mount/error.h>
|
||||||
|
|
||||||
|
struct blockdevice;
|
||||||
|
struct filesystem;
|
||||||
|
struct filesystem_handler;
|
||||||
|
|
||||||
|
#define FILESYSTEM_FLAG_UUID (1 << 0)
|
||||||
|
#define FILESYSTEM_FLAG_FSCK_SHOULD (1 << 1)
|
||||||
|
#define FILESYSTEM_FLAG_FSCK_MUST (1 << 2)
|
||||||
|
|
||||||
|
struct filesystem
|
||||||
|
{
|
||||||
|
struct blockdevice* bdev;
|
||||||
|
const struct filesystem_handler* handler;
|
||||||
|
void* handler_private;
|
||||||
|
const char* fstype_name;
|
||||||
|
const char* fsck;
|
||||||
|
const char* driver;
|
||||||
|
int flags;
|
||||||
|
unsigned char uuid[16];
|
||||||
|
void* user_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct filesystem_handler
|
||||||
|
{
|
||||||
|
const char* handler_name;
|
||||||
|
size_t (*probe_amount)(struct blockdevice*);
|
||||||
|
bool (*probe)(struct blockdevice*, const unsigned char*, size_t);
|
||||||
|
enum filesystem_error (*inspect)(struct filesystem**, struct blockdevice*);
|
||||||
|
void (*release)(struct filesystem*);
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char* filesystem_error_string(enum filesystem_error);
|
||||||
|
enum filesystem_error
|
||||||
|
blockdevice_inspect_filesystem(struct filesystem**, struct blockdevice*);
|
||||||
|
void filesystem_release(struct filesystem*);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mount/gpt.h
|
||||||
|
GUID Partition Table.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_MOUNT_GPT_H
|
||||||
|
#define INCLUDE_MOUNT_GPT_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct blockdevice;
|
||||||
|
struct partition_table;
|
||||||
|
|
||||||
|
struct gpt
|
||||||
|
{
|
||||||
|
char signature[8];
|
||||||
|
uint32_t revision;
|
||||||
|
uint32_t header_size;
|
||||||
|
uint32_t header_crc32;
|
||||||
|
uint32_t reserved0;
|
||||||
|
uint64_t my_lba;
|
||||||
|
uint64_t alternate_lba;
|
||||||
|
uint64_t first_usable_lba;
|
||||||
|
uint64_t last_usable_lba;
|
||||||
|
unsigned char disk_guid[16];
|
||||||
|
uint64_t partition_entry_lba;
|
||||||
|
uint32_t number_of_partition_entries;
|
||||||
|
uint32_t size_of_partition_entry;
|
||||||
|
uint32_t partition_entry_array_crc32;
|
||||||
|
unsigned char reserved1[420];
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(struct gpt) == 512, "sizeof(struct gpt) == 512");
|
||||||
|
|
||||||
|
#define GPT_PARTITION_NAME_LENGTH 36
|
||||||
|
struct gpt_partition
|
||||||
|
{
|
||||||
|
unsigned char partition_type_guid[16];
|
||||||
|
unsigned char unique_partition_guid[16];
|
||||||
|
uint64_t starting_lba;
|
||||||
|
uint64_t ending_lba;
|
||||||
|
uint64_t attributes;
|
||||||
|
uint16_t partition_name[GPT_PARTITION_NAME_LENGTH];
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(struct gpt_partition) == 128, "sizeof(struct gpt_partition) == 128");
|
||||||
|
|
||||||
|
struct gpt_partition_table
|
||||||
|
{
|
||||||
|
struct gpt gpt;
|
||||||
|
unsigned char* rpt;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void gpt_decode(struct gpt*);
|
||||||
|
void gpt_encode(struct gpt*);
|
||||||
|
void gpt_partition_decode(struct gpt_partition*);
|
||||||
|
void gpt_partition_encode(struct gpt_partition*);
|
||||||
|
char* gpt_decode_utf16(uint16_t* string, size_t length);
|
||||||
|
uint32_t gpt_crc32(const void*, size_t);
|
||||||
|
void gpt_partition_table_release(struct gpt_partition_table*);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mount/harddisk.h
|
||||||
|
Harddisk abstraction.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_MOUNT_HARDDISK_H
|
||||||
|
#define INCLUDE_MOUNT_HARDDISK_H
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#if !defined(__cplusplus)
|
||||||
|
#include <stdbool.h>
|
||||||
|
#endif
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <mount/blockdevice.h>
|
||||||
|
|
||||||
|
struct harddisk
|
||||||
|
{
|
||||||
|
struct blockdevice bdev;
|
||||||
|
struct stat st;
|
||||||
|
int fd;
|
||||||
|
char* path;
|
||||||
|
char* driver;
|
||||||
|
char* model;
|
||||||
|
char* serial;
|
||||||
|
blksize_t logical_block_size;
|
||||||
|
uint16_t cylinders;
|
||||||
|
uint16_t heads;
|
||||||
|
uint16_t sectors;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct harddisk* harddisk_openat(int, const char*, int);
|
||||||
|
bool harddisk_inspect_blockdevice(struct harddisk*);
|
||||||
|
void harddisk_close(struct harddisk*);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mount/mbr.h
|
||||||
|
Master Boot Record.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_MOUNT_MBR_H
|
||||||
|
#define INCLUDE_MOUNT_MBR_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct blockdevice;
|
||||||
|
struct partition_table;
|
||||||
|
|
||||||
|
struct mbr_partition
|
||||||
|
{
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t start_head;
|
||||||
|
uint16_t start_sector_cylinder;
|
||||||
|
uint8_t system_id;
|
||||||
|
uint8_t end_head;
|
||||||
|
uint16_t end_sector_cylinder;
|
||||||
|
uint32_t start_sector;
|
||||||
|
uint32_t total_sectors;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(struct mbr_partition) == 16, "sizeof(struct mbr_partition) == 16");
|
||||||
|
|
||||||
|
struct mbr
|
||||||
|
{
|
||||||
|
uint8_t bootstrap[446];
|
||||||
|
unsigned char partitions[4][16];
|
||||||
|
uint8_t signature[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(struct mbr) == 512, "sizeof(struct mbr) == 512");
|
||||||
|
|
||||||
|
struct mbr_ebr_link
|
||||||
|
{
|
||||||
|
struct mbr ebr;
|
||||||
|
off_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mbr_partition_table
|
||||||
|
{
|
||||||
|
struct mbr mbr;
|
||||||
|
size_t ebr_chain_count;
|
||||||
|
struct mbr_ebr_link* ebr_chain;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool mbr_is_partition_used(const struct mbr_partition* partition);
|
||||||
|
void mbr_partition_decode(struct mbr_partition*);
|
||||||
|
void mbr_partition_encode(struct mbr_partition*);
|
||||||
|
void mbr_partition_table_release(struct mbr_partition_table*);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mount/partition.h
|
||||||
|
Partition abstraction.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_MOUNT_PARTITION_H
|
||||||
|
#define INCLUDE_MOUNT_PARTITION_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#if !defined(__cplusplus)
|
||||||
|
#include <stdbool.h>
|
||||||
|
#endif
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <mount/blockdevice.h>
|
||||||
|
#include <mount/error.h>
|
||||||
|
|
||||||
|
enum partition_type
|
||||||
|
{
|
||||||
|
PARTITION_TYPE_PRIMARY,
|
||||||
|
PARTITION_TYPE_EXTENDED,
|
||||||
|
PARTITION_TYPE_LOGICAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum partition_table_type
|
||||||
|
{
|
||||||
|
PARTITION_TABLE_TYPE_NONE,
|
||||||
|
PARTITION_TABLE_TYPE_UNKNOWN,
|
||||||
|
PARTITION_TABLE_TYPE_MBR,
|
||||||
|
PARTITION_TABLE_TYPE_GPT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct partition
|
||||||
|
{
|
||||||
|
struct blockdevice bdev;
|
||||||
|
struct blockdevice* parent_bdev;
|
||||||
|
char* path;
|
||||||
|
off_t start;
|
||||||
|
off_t length;
|
||||||
|
off_t extended_start;
|
||||||
|
off_t extended_length;
|
||||||
|
enum partition_type type;
|
||||||
|
enum partition_table_type table_type;
|
||||||
|
unsigned int index;
|
||||||
|
unsigned char gpt_type_guid[16];
|
||||||
|
unsigned char gpt_unique_guid[16];
|
||||||
|
unsigned char mbr_system_id;
|
||||||
|
char* gpt_name;
|
||||||
|
uint64_t gpt_attributes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct partition_table
|
||||||
|
{
|
||||||
|
enum partition_table_type type;
|
||||||
|
struct partition** partitions;
|
||||||
|
size_t partitions_count;
|
||||||
|
enum partition_error error;
|
||||||
|
unsigned char gpt_disk_guid[16];
|
||||||
|
void* raw_partition_table;
|
||||||
|
off_t usable_start;
|
||||||
|
off_t usable_end;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int partition_compare_index(const struct partition*, const struct partition*);
|
||||||
|
int partition_compare_index_indirect(const void*, const void*);
|
||||||
|
int partition_compare_start(const struct partition*, const struct partition*);
|
||||||
|
int partition_compare_start_indirect(const void*, const void*);
|
||||||
|
const char* partition_error_string(enum partition_error);
|
||||||
|
bool partition_check_overlap(const struct partition*, off_t, off_t);
|
||||||
|
void partition_release(struct partition*);
|
||||||
|
bool blockdevice_probe_partition_table_type(enum partition_table_type*, struct blockdevice*);
|
||||||
|
enum partition_error
|
||||||
|
blockdevice_get_partition_table(struct partition_table**, struct blockdevice*);
|
||||||
|
enum partition_error
|
||||||
|
blockdevice_get_partition_table_mbr(struct partition_table**, struct blockdevice*);
|
||||||
|
enum partition_error
|
||||||
|
blockdevice_get_partition_table_gpt(struct partition_table**, struct blockdevice*);
|
||||||
|
void partition_table_release(struct partition_table*);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mount/uuid.h
|
||||||
|
Universally unique identifier.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_MOUNT_UUID_H
|
||||||
|
#define INCLUDE_MOUNT_UUID_H
|
||||||
|
|
||||||
|
#if !defined(__cplusplus)
|
||||||
|
#include <stdbool.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UUID_STRING_LENGTH 36 /* and of course a nul byte not included here */
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool uuid_validate(const char*);
|
||||||
|
void uuid_from_string(unsigned char[16], const char*);
|
||||||
|
void uuid_to_string(const unsigned char[16], char*);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,270 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
mbr.c
|
||||||
|
Master Boot Record.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <endian.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <mount/blockdevice.h>
|
||||||
|
#include <mount/harddisk.h>
|
||||||
|
#include <mount/mbr.h>
|
||||||
|
#include <mount/partition.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
void mbr_partition_decode(struct mbr_partition* v)
|
||||||
|
{
|
||||||
|
// flags is endian agnostic.
|
||||||
|
// start_head is endian agnostic.
|
||||||
|
v->start_sector_cylinder = le16toh(v->start_sector_cylinder);
|
||||||
|
v->end_sector_cylinder = le16toh(v->end_sector_cylinder);
|
||||||
|
// system_id is endian agnostic.
|
||||||
|
// end_head is endian agnostic.
|
||||||
|
v->start_sector = le32toh(v->start_sector);
|
||||||
|
v->total_sectors = le32toh(v->total_sectors);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mbr_partition_encode(struct mbr_partition* v)
|
||||||
|
{
|
||||||
|
v->start_sector_cylinder = htole16(v->start_sector_cylinder);
|
||||||
|
v->end_sector_cylinder = htole16(v->end_sector_cylinder);
|
||||||
|
// flags is endian agnostic.
|
||||||
|
// start_head is endian agnostic.
|
||||||
|
v->start_sector = htole32(v->start_sector);
|
||||||
|
v->total_sectors = htole32(v->total_sectors);
|
||||||
|
// system_id is endian agnostic.
|
||||||
|
// end_head is endian agnostic.
|
||||||
|
}
|
||||||
|
|
||||||
|
void mbr_partition_table_release(struct mbr_partition_table* pt)
|
||||||
|
{
|
||||||
|
if ( !pt )
|
||||||
|
return;
|
||||||
|
free(pt->ebr_chain);
|
||||||
|
free(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mbr_is_extended_partition(const struct mbr_partition* partition)
|
||||||
|
{
|
||||||
|
return partition->system_id == 0x05 || // CHS addressing.
|
||||||
|
partition->system_id == 0x0F; // LBA addressing.
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mbr_is_partition_used(const struct mbr_partition* partition)
|
||||||
|
{
|
||||||
|
if ( memiszero(partition, sizeof(*partition)) )
|
||||||
|
return false;
|
||||||
|
if ( !partition->system_id ||
|
||||||
|
!partition->total_sectors )
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum partition_error
|
||||||
|
blockdevice_get_partition_table_mbr(struct partition_table** pt_ptr,
|
||||||
|
struct blockdevice* bdev)
|
||||||
|
{
|
||||||
|
*pt_ptr = NULL;
|
||||||
|
blksize_t logical_block_size = blockdevice_logical_block_size(bdev);
|
||||||
|
if ( !blockdevice_check_reasonable_block_size(logical_block_size) )
|
||||||
|
return errno = EINVAL, PARTITION_ERROR_ERRNO;
|
||||||
|
off_t device_size = blockdevice_size(bdev);
|
||||||
|
const char* device_path = bdev->p ? bdev->p->path : bdev->hd->path;
|
||||||
|
|
||||||
|
struct mbr mbr;
|
||||||
|
if ( blockdevice_preadall(bdev, &mbr, sizeof(mbr), 0) != sizeof(mbr) )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
|
||||||
|
if ( mbr.signature[0] != 0x55 && mbr.signature[1] != 0xAA )
|
||||||
|
return errno = EINVAL, PARTITION_ERROR_ERRNO;
|
||||||
|
|
||||||
|
struct partition_table* pt = CALLOC_TYPE(struct partition_table);
|
||||||
|
if ( !pt )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
*pt_ptr = pt;
|
||||||
|
pt->type = PARTITION_TABLE_TYPE_MBR;
|
||||||
|
size_t pt__partitions_length = 0;
|
||||||
|
pt->usable_start = logical_block_size;
|
||||||
|
off_t last_sector = device_size / logical_block_size;
|
||||||
|
if ( UINT32_MAX + 1LL < last_sector )
|
||||||
|
last_sector = UINT32_MAX + 1LL;
|
||||||
|
pt->usable_end = last_sector * logical_block_size;
|
||||||
|
|
||||||
|
struct mbr_partition_table* mbrpt = CALLOC_TYPE(struct mbr_partition_table);
|
||||||
|
if ( !mbrpt )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
pt->raw_partition_table = mbrpt;
|
||||||
|
memcpy(&mbrpt->mbr, &mbr, sizeof(mbr));
|
||||||
|
|
||||||
|
unsigned int extended_partition_count = 0;
|
||||||
|
for ( unsigned int i = 0; i < 4; i++ )
|
||||||
|
{
|
||||||
|
struct mbr_partition pmbr;
|
||||||
|
memcpy(&pmbr, mbr.partitions[i], sizeof(pmbr));
|
||||||
|
mbr_partition_decode(&pmbr);
|
||||||
|
if ( mbr_is_partition_used(&pmbr) && mbr_is_extended_partition(&pmbr) )
|
||||||
|
extended_partition_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( 2 <= extended_partition_count ) // Violates assumptions.
|
||||||
|
return PARTITION_ERROR_TOO_EXTENDED;
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < 4; i++ )
|
||||||
|
{
|
||||||
|
struct mbr_partition pmbr;
|
||||||
|
memcpy(&pmbr, mbr.partitions[i], sizeof(pmbr));
|
||||||
|
mbr_partition_decode(&pmbr);
|
||||||
|
if ( !mbr_is_partition_used(&pmbr) )
|
||||||
|
continue;
|
||||||
|
// TODO: Potential overflow.
|
||||||
|
if ( pmbr.start_sector == 0 )
|
||||||
|
return PARTITION_ERROR_BEFORE_USABLE;
|
||||||
|
off_t start = (off_t) pmbr.start_sector * (off_t) logical_block_size;
|
||||||
|
off_t length = (off_t) pmbr.total_sectors * (off_t) logical_block_size;
|
||||||
|
if ( device_size < start || device_size - start < length )
|
||||||
|
return PARTITION_ERROR_BEYOND_DEVICE;
|
||||||
|
for ( size_t j = 0; j < pt->partitions_count; j++ )
|
||||||
|
if ( partition_check_overlap(pt->partitions[j], start, length) )
|
||||||
|
return PARTITION_ERROR_OVERLAP;
|
||||||
|
struct partition* p = CALLOC_TYPE(struct partition);
|
||||||
|
if ( !p )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
memset(&p->bdev, 0, sizeof(p->bdev));
|
||||||
|
p->bdev.p = p;
|
||||||
|
p->parent_bdev = bdev;
|
||||||
|
p->index = 1 + i;
|
||||||
|
p->start = start;
|
||||||
|
p->length = length;
|
||||||
|
p->type = PARTITION_TYPE_PRIMARY;
|
||||||
|
if ( mbr_is_extended_partition(&pmbr) )
|
||||||
|
{
|
||||||
|
p->extended_start = start;
|
||||||
|
p->extended_length = length;
|
||||||
|
p->type = PARTITION_TYPE_EXTENDED;
|
||||||
|
}
|
||||||
|
p->table_type = PARTITION_TABLE_TYPE_MBR;
|
||||||
|
p->mbr_system_id = pmbr.system_id;
|
||||||
|
if ( !array_add((void***) &pt->partitions,
|
||||||
|
&pt->partitions_count,
|
||||||
|
&pt__partitions_length,
|
||||||
|
p) )
|
||||||
|
return free(p), PARTITION_ERROR_ERRNO;
|
||||||
|
if ( device_path &&
|
||||||
|
asprintf(&p->path, "%sp%u", device_path, p->index) < 0 )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; i < 4; i++ )
|
||||||
|
{
|
||||||
|
struct mbr_partition pextmbr;
|
||||||
|
memcpy(&pextmbr, mbr.partitions[i], sizeof(pextmbr));
|
||||||
|
mbr_partition_decode(&pextmbr);
|
||||||
|
if ( !mbr_is_partition_used(&pextmbr) )
|
||||||
|
continue;
|
||||||
|
if ( !mbr_is_extended_partition(&pextmbr) )
|
||||||
|
continue;
|
||||||
|
// TODO: Potential overflow.
|
||||||
|
off_t pext_start = (off_t) pextmbr.start_sector * (off_t) logical_block_size;
|
||||||
|
off_t pext_length = (off_t) pextmbr.total_sectors * (off_t) logical_block_size;
|
||||||
|
off_t ebr_rel = 0;
|
||||||
|
unsigned int j = 0;
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
struct mbr ebr;
|
||||||
|
if ( pext_length <= ebr_rel )
|
||||||
|
return PARTITION_ERROR_BEYOND_EXTENDED;
|
||||||
|
off_t ebr_off = pext_start + ebr_rel;
|
||||||
|
if ( blockdevice_preadall(bdev, &ebr, sizeof(ebr), ebr_off) != sizeof(ebr) )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
if ( ebr.signature[0] != 0x55 && ebr.signature[1] != 0xAA )
|
||||||
|
return PARTITION_ERROR_BAD_EXTENDED;
|
||||||
|
size_t new_chain_count = mbrpt->ebr_chain_count + 1;
|
||||||
|
size_t chain_size = sizeof(struct mbr_ebr_link) * new_chain_count;
|
||||||
|
struct mbr_ebr_link* new_chain =
|
||||||
|
(struct mbr_ebr_link*) realloc(mbrpt->ebr_chain, chain_size);
|
||||||
|
if ( !new_chain )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
mbrpt->ebr_chain = new_chain;
|
||||||
|
mbrpt->ebr_chain_count = new_chain_count;
|
||||||
|
memcpy(&mbrpt->ebr_chain[j].ebr, &ebr, sizeof(ebr));
|
||||||
|
mbrpt->ebr_chain[j].offset = ebr_off;
|
||||||
|
struct mbr_partition pmbr;
|
||||||
|
memcpy(&pmbr, ebr.partitions[0], sizeof(pmbr));
|
||||||
|
mbr_partition_decode(&pmbr);
|
||||||
|
if ( mbr_is_partition_used(&pmbr) )
|
||||||
|
{
|
||||||
|
// TODO: Potential overflow.
|
||||||
|
off_t start = (off_t) pmbr.start_sector * (off_t) logical_block_size;
|
||||||
|
off_t length = (off_t) pmbr.total_sectors * (off_t) logical_block_size;
|
||||||
|
if ( pext_length - ebr_rel < start )
|
||||||
|
return PARTITION_ERROR_BEYOND_EXTENDED;
|
||||||
|
off_t max_length = (pext_length - ebr_rel) - start;
|
||||||
|
if ( max_length < length )
|
||||||
|
return PARTITION_ERROR_BEYOND_EXTENDED;
|
||||||
|
struct partition* p = CALLOC_TYPE(struct partition);
|
||||||
|
if ( !p )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
memset(&p->bdev, 0, sizeof(p->bdev));
|
||||||
|
p->bdev.p = p;
|
||||||
|
p->parent_bdev = bdev;
|
||||||
|
p->index = 5 + j;
|
||||||
|
p->start = ebr_off + start;
|
||||||
|
p->length = length;
|
||||||
|
p->type = PARTITION_TYPE_LOGICAL;
|
||||||
|
p->table_type = PARTITION_TABLE_TYPE_MBR;
|
||||||
|
p->mbr_system_id = pmbr.system_id;
|
||||||
|
if ( !array_add((void***) &pt->partitions,
|
||||||
|
&pt->partitions_count,
|
||||||
|
&pt__partitions_length,
|
||||||
|
p) )
|
||||||
|
return free(p), PARTITION_ERROR_ERRNO;
|
||||||
|
if ( device_path &&
|
||||||
|
asprintf(&p->path, "%sp%u", device_path, p->index) < 0 )
|
||||||
|
return PARTITION_ERROR_ERRNO;
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
struct mbr_partition next;
|
||||||
|
memcpy(&next, ebr.partitions[1], sizeof(next));
|
||||||
|
mbr_partition_decode(&next);
|
||||||
|
// TODO: Potential overflow.
|
||||||
|
off_t next_rel = (off_t) next.start_sector * (off_t) logical_block_size;
|
||||||
|
if ( !next_rel )
|
||||||
|
break;
|
||||||
|
if ( next_rel <= ebr_rel ) // Violates assumptions.
|
||||||
|
return PARTITION_ERROR_NONLINEAR_EXTENDED;
|
||||||
|
if ( pext_length <= next_rel )
|
||||||
|
return PARTITION_ERROR_BEYOND_EXTENDED;
|
||||||
|
ebr_rel = next_rel;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PARTITION_ERROR_NONE;
|
||||||
|
}
|
|
@ -0,0 +1,238 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
partition.c
|
||||||
|
Partition abstraction.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <endian.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <mount/blockdevice.h>
|
||||||
|
#include <mount/gpt.h>
|
||||||
|
#include <mount/mbr.h>
|
||||||
|
#include <mount/partition.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int partition_compare_index(const struct partition* a, const struct partition* b)
|
||||||
|
{
|
||||||
|
if ( a->index < b->index )
|
||||||
|
return -1;
|
||||||
|
if ( b->index < a->index )
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int partition_compare_index_indirect(const void* a_ptr, const void* b_ptr)
|
||||||
|
{
|
||||||
|
const struct partition* a = *(const struct partition* const*) a_ptr;
|
||||||
|
const struct partition* b = *(const struct partition* const*) b_ptr;
|
||||||
|
return partition_compare_index(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
int partition_compare_start(const struct partition* a, const struct partition* b)
|
||||||
|
{
|
||||||
|
if ( a->start < b->start )
|
||||||
|
return -1;
|
||||||
|
if ( b->start < a->start )
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int partition_compare_start_indirect(const void* a_ptr, const void* b_ptr)
|
||||||
|
{
|
||||||
|
const struct partition* a = *(const struct partition* const*) a_ptr;
|
||||||
|
const struct partition* b = *(const struct partition* const*) b_ptr;
|
||||||
|
return partition_compare_index(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* partition_error_string(enum partition_error error)
|
||||||
|
{
|
||||||
|
switch ( error )
|
||||||
|
{
|
||||||
|
case PARTITION_ERROR_NONE:
|
||||||
|
break;
|
||||||
|
case PARTITION_ERROR_ABSENT:
|
||||||
|
return "No partition table found";
|
||||||
|
case PARTITION_ERROR_UNRECOGNIZED:
|
||||||
|
return "Unrecognized partitioning scheme";
|
||||||
|
case PARTITION_ERROR_ERRNO:
|
||||||
|
return (const char*) strerror(errno);
|
||||||
|
case PARTITION_ERROR_INVALID:
|
||||||
|
return "Invalid partition table";
|
||||||
|
case PARTITION_ERROR_HEADER_TOO_LARGE:
|
||||||
|
return "Partition table header larger than logical sector size";
|
||||||
|
case PARTITION_ERROR_CHECKSUM:
|
||||||
|
return "Partition table does not match its checksum";
|
||||||
|
case PARTITION_ERROR_OVERLAP:
|
||||||
|
return "Partition table contains overlapping partitions";
|
||||||
|
case PARTITION_ERROR_END_BEFORE_START:
|
||||||
|
return "Invalid partition ends before its start";
|
||||||
|
case PARTITION_ERROR_BEFORE_USABLE:
|
||||||
|
return "Invalid partition begins before the usable region";
|
||||||
|
case PARTITION_ERROR_BEYOND_DEVICE:
|
||||||
|
return "Invalid partition exceeds device";
|
||||||
|
case PARTITION_ERROR_BEYOND_EXTENDED:
|
||||||
|
return "Invalid logical partition exceeds its extended partition";
|
||||||
|
case PARTITION_ERROR_BEYOND_USABLE:
|
||||||
|
return "Invalid partition ends after the usable region";
|
||||||
|
case PARTITION_ERROR_TOO_EXTENDED:
|
||||||
|
return "Bad partition table (more than one extended partition)";
|
||||||
|
case PARTITION_ERROR_BAD_EXTENDED:
|
||||||
|
return "Bad extended partition";
|
||||||
|
case PARTITION_ERROR_NONLINEAR_EXTENDED:
|
||||||
|
return "Extended partition is not linearly linked together";
|
||||||
|
}
|
||||||
|
return "Unknown error condition";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool partition_check_overlap(const struct partition* partition,
|
||||||
|
off_t start,
|
||||||
|
off_t length)
|
||||||
|
{
|
||||||
|
assert(0 <= start);
|
||||||
|
assert(0 <= length);
|
||||||
|
assert(0 <= partition->start);
|
||||||
|
assert(0 <= partition->length);
|
||||||
|
if ( start <= partition->start )
|
||||||
|
{
|
||||||
|
off_t max_length = partition->start - start;
|
||||||
|
return max_length < length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
off_t max_length = start - partition->start;
|
||||||
|
return max_length < partition->length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blockdevice_probe_partition_table_type(enum partition_table_type* result_out,
|
||||||
|
struct blockdevice* bdev)
|
||||||
|
{
|
||||||
|
blksize_t logical_block_size = blockdevice_logical_block_size(bdev);
|
||||||
|
if ( !blockdevice_check_reasonable_block_size(logical_block_size) )
|
||||||
|
return errno = EINVAL, false;
|
||||||
|
|
||||||
|
// TODO: Overflow checks for truncation, and the multiplication.
|
||||||
|
size_t block_size = logical_block_size;
|
||||||
|
size_t leading_size = 2 * block_size;
|
||||||
|
unsigned char* leading = (unsigned char*) malloc(leading_size);
|
||||||
|
if ( !leading )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t amount = blockdevice_preadall(bdev, leading, leading_size, 0);
|
||||||
|
if ( amount < leading_size && errno != EEOF )
|
||||||
|
return free(leading), false;
|
||||||
|
|
||||||
|
enum partition_table_type result = PARTITION_TABLE_TYPE_NONE;
|
||||||
|
|
||||||
|
do if ( 2*block_size <= amount )
|
||||||
|
{
|
||||||
|
struct gpt gpt;
|
||||||
|
memcpy(&gpt, leading + 1 * block_size, sizeof(gpt));
|
||||||
|
gpt_decode(&gpt);
|
||||||
|
if ( memcmp(gpt.signature, "EFI PART", 8) != 0 )
|
||||||
|
break;
|
||||||
|
result = PARTITION_TABLE_TYPE_GPT;
|
||||||
|
goto out;
|
||||||
|
} while ( 0 );
|
||||||
|
|
||||||
|
do if ( sizeof(struct mbr) <= amount )
|
||||||
|
{
|
||||||
|
struct mbr mbr;
|
||||||
|
memcpy(&mbr, leading, sizeof(mbr));
|
||||||
|
if ( mbr.signature[0] != 0x55 && mbr.signature[1] != 0xAA )
|
||||||
|
break;
|
||||||
|
result = PARTITION_TABLE_TYPE_MBR;
|
||||||
|
goto out;
|
||||||
|
} while ( 0 );
|
||||||
|
|
||||||
|
for ( size_t i = 0; i < leading_size; i++ )
|
||||||
|
{
|
||||||
|
if ( leading[i] == 0x00 )
|
||||||
|
continue;
|
||||||
|
result = PARTITION_TABLE_TYPE_UNKNOWN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(leading);
|
||||||
|
return *result_out = result, true;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum partition_error
|
||||||
|
blockdevice_get_partition_table(struct partition_table** pt_ptr,
|
||||||
|
struct blockdevice* bdev)
|
||||||
|
{
|
||||||
|
enum partition_table_type pt_type;
|
||||||
|
if ( !blockdevice_probe_partition_table_type(&pt_type, bdev) )
|
||||||
|
return *pt_ptr = NULL, PARTITION_ERROR_ERRNO;
|
||||||
|
switch ( pt_type )
|
||||||
|
{
|
||||||
|
case PARTITION_TABLE_TYPE_NONE:
|
||||||
|
return *pt_ptr = NULL, PARTITION_ERROR_ABSENT;
|
||||||
|
case PARTITION_TABLE_TYPE_UNKNOWN:
|
||||||
|
break;
|
||||||
|
case PARTITION_TABLE_TYPE_MBR:
|
||||||
|
return blockdevice_get_partition_table_mbr(pt_ptr, bdev);
|
||||||
|
case PARTITION_TABLE_TYPE_GPT:
|
||||||
|
return blockdevice_get_partition_table_gpt(pt_ptr, bdev);
|
||||||
|
}
|
||||||
|
return *pt_ptr = NULL, PARTITION_ERROR_UNRECOGNIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void partition_release(struct partition* p)
|
||||||
|
{
|
||||||
|
if ( !p )
|
||||||
|
return;
|
||||||
|
free(p->gpt_name);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void partition_table_release(struct partition_table* pt)
|
||||||
|
{
|
||||||
|
if ( !pt )
|
||||||
|
return;
|
||||||
|
switch ( pt->type )
|
||||||
|
{
|
||||||
|
case PARTITION_TABLE_TYPE_NONE: break;
|
||||||
|
case PARTITION_TABLE_TYPE_UNKNOWN: break;
|
||||||
|
case PARTITION_TABLE_TYPE_MBR:
|
||||||
|
mbr_partition_table_release(
|
||||||
|
(struct mbr_partition_table*) pt->raw_partition_table);
|
||||||
|
break;
|
||||||
|
case PARTITION_TABLE_TYPE_GPT:
|
||||||
|
gpt_partition_table_release(
|
||||||
|
(struct gpt_partition_table*) pt->raw_partition_table);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for ( size_t i = 0; i < pt->partitions_count; i++ )
|
||||||
|
partition_release(pt->partitions[i]);
|
||||||
|
free(pt->partitions);
|
||||||
|
free(pt);
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
util.h
|
||||||
|
Utility functions.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef UTIL_H
|
||||||
|
#define UTIL_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define MALLOC_TYPE(type) (type*) malloc(sizeof(type))
|
||||||
|
#define CALLOC_TYPE(type) (type*) calloc(1, sizeof(type))
|
||||||
|
|
||||||
|
__attribute__((unused))
|
||||||
|
static bool memiszero(const void* mem, size_t size)
|
||||||
|
{
|
||||||
|
const unsigned char* buf = (const unsigned char*) mem;
|
||||||
|
for ( size_t i = 0; i < size; i++ )
|
||||||
|
if ( buf[i] )
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((unused))
|
||||||
|
static bool array_add(void*** array_ptr,
|
||||||
|
size_t* used_ptr,
|
||||||
|
size_t* length_ptr,
|
||||||
|
void* value)
|
||||||
|
{
|
||||||
|
void** array;
|
||||||
|
memcpy(&array, array_ptr, sizeof(array)); // Strict aliasing.
|
||||||
|
|
||||||
|
if ( *used_ptr == *length_ptr )
|
||||||
|
{
|
||||||
|
// TODO: Avoid overflow.
|
||||||
|
size_t new_length = 2 * *length_ptr;
|
||||||
|
if ( !new_length )
|
||||||
|
new_length = 16;
|
||||||
|
// TODO: Avoid overflow and use reallocarray.
|
||||||
|
size_t new_size = new_length * sizeof(void*);
|
||||||
|
void** new_array = (void**) realloc(array, new_size);
|
||||||
|
if ( !new_array )
|
||||||
|
return false;
|
||||||
|
array = new_array;
|
||||||
|
memcpy(array_ptr, &array, sizeof(array)); // Strict aliasing.
|
||||||
|
*length_ptr = new_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(array + (*used_ptr)++, &value, sizeof(value)); // Strict aliasing.
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2015.
|
||||||
|
|
||||||
|
This file is part of Sortix libmount.
|
||||||
|
|
||||||
|
Sortix libmount is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
Sortix libmount 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 Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with Sortix libmount. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
uuid.c
|
||||||
|
Universally unique identifier.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <mount/uuid.h>
|
||||||
|
|
||||||
|
static bool is_hex_digit(char c)
|
||||||
|
{
|
||||||
|
return ('0' <= c && c <= '9') ||
|
||||||
|
('a' <= c && c <= 'f') ||
|
||||||
|
('A' <= c && c <= 'F');
|
||||||
|
}
|
||||||
|
|
||||||
|
static char base(unsigned char bit4)
|
||||||
|
{
|
||||||
|
return "0123456789abcdef"[bit4];
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char debase(char c)
|
||||||
|
{
|
||||||
|
if ( '0' <= c && c <= '9' )
|
||||||
|
return (unsigned char) (c - '0');
|
||||||
|
if ( 'a' <= c && c <= 'f' )
|
||||||
|
return (unsigned char) (c - 'a' + 10);
|
||||||
|
if ( 'A' <= c && c <= 'F' )
|
||||||
|
return (unsigned char) (c - 'A' + 10);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uuid_validate(const char* uuid)
|
||||||
|
{
|
||||||
|
// Format: 01234567-0123-0123-0123-0123456789AB
|
||||||
|
if ( strlen(uuid) != 36 )
|
||||||
|
return false;
|
||||||
|
for ( size_t i = 0; i < 36; i++ )
|
||||||
|
{
|
||||||
|
if ( i == 8 || i == 13 || i == 18 || i == 23 )
|
||||||
|
{
|
||||||
|
if ( uuid[i] != '-' )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( !is_hex_digit(uuid[i]) )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uuid_from_string(unsigned char uuid[16], const char* string)
|
||||||
|
{
|
||||||
|
size_t output_index = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
while ( i < 36 )
|
||||||
|
{
|
||||||
|
assert(string[i + 0] != '\0');
|
||||||
|
if ( i == 8 || i == 13 || i == 18 || i == 23 )
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uuid[output_index++] = debase(string[i + 0]) << 4 |
|
||||||
|
debase(string[i + 1]) << 0;
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uuid_to_string(const unsigned char uuid[16], char* string)
|
||||||
|
{
|
||||||
|
for ( size_t i = 0; i < 4; i++ )
|
||||||
|
{
|
||||||
|
*string++ = base((uuid[i] >> 4) & 0xF);
|
||||||
|
*string++ = base((uuid[i] >> 0) & 0xF);
|
||||||
|
}
|
||||||
|
*string++ = '-';
|
||||||
|
for ( size_t i = 4; i < 6; i++ )
|
||||||
|
{
|
||||||
|
*string++ = base((uuid[i] >> 4) & 0xF);
|
||||||
|
*string++ = base((uuid[i] >> 0) & 0xF);
|
||||||
|
}
|
||||||
|
*string++ = '-';
|
||||||
|
for ( size_t i = 6; i < 8; i++ )
|
||||||
|
{
|
||||||
|
*string++ = base((uuid[i] >> 4) & 0xF);
|
||||||
|
*string++ = base((uuid[i] >> 0) & 0xF);
|
||||||
|
}
|
||||||
|
*string++ = '-';
|
||||||
|
for ( size_t i = 8; i < 10; i++ )
|
||||||
|
{
|
||||||
|
*string++ = base((uuid[i] >> 4) & 0xF);
|
||||||
|
*string++ = base((uuid[i] >> 0) & 0xF);
|
||||||
|
}
|
||||||
|
*string++ = '-';
|
||||||
|
for ( size_t i = 10; i < 16; i++ )
|
||||||
|
{
|
||||||
|
*string++ = base((uuid[i] >> 4) & 0xF);
|
||||||
|
*string++ = base((uuid[i] >> 0) & 0xF);
|
||||||
|
}
|
||||||
|
*string = '\0';
|
||||||
|
}
|
Loading…
Reference in New Issue