863 lines
18 KiB
C
863 lines
18 KiB
C
/*
|
|
* Copyright 1996-2002 Hans Reiser
|
|
*/
|
|
|
|
/* for stat64() */
|
|
#define _FILE_OFFSET_BITS 64
|
|
|
|
/* for getline() proto and _LARGEFILE64_SOURCE */
|
|
#define _GNU_SOURCE
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <asm/types.h>
|
|
#include <stdlib.h>
|
|
#include <mntent.h>
|
|
#include <sys/vfs.h>
|
|
#include <fcntl.h>
|
|
#include <time.h>
|
|
#include <utime.h>
|
|
#include <ctype.h>
|
|
|
|
#include <unistd.h>
|
|
//#include <linux/unistd.h>
|
|
//#include <sys/stat.h>
|
|
|
|
#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
|
|
# define BLKGETSIZE64 _IOR(0x12, 114, sizeof(__u64))
|
|
#endif
|
|
|
|
|
|
#include "swab.h"
|
|
|
|
#include "io.h"
|
|
#include "misc.h"
|
|
|
|
/* Debian modifications by Ed Boraas <ed@debian.org> */
|
|
#include <sys/mount.h>
|
|
/* End Debian mods */
|
|
|
|
|
|
void die (char * fmt, ...)
|
|
{
|
|
static char buf[1024];
|
|
va_list args;
|
|
|
|
va_start (args, fmt);
|
|
vsprintf (buf, fmt, args);
|
|
va_end (args);
|
|
|
|
fprintf (stderr, "\n%s\n\n\n", buf);
|
|
abort ();
|
|
}
|
|
|
|
|
|
#define MEM_BEGIN "_mem_begin_"
|
|
#define MEM_END "mem_end"
|
|
#define MEM_FREED "__free_"
|
|
#define CONTROL_SIZE (strlen (MEM_BEGIN) + 1 + sizeof (int) + strlen (MEM_END) + 1)
|
|
|
|
|
|
int get_mem_size (char * p)
|
|
{
|
|
char * begin;
|
|
|
|
begin = p - strlen (MEM_BEGIN) - 1 - sizeof (int);
|
|
return *(int *)(begin + strlen (MEM_BEGIN) + 1);
|
|
}
|
|
|
|
|
|
void checkmem (char * p, int size)
|
|
{
|
|
char * begin;
|
|
char * end;
|
|
|
|
begin = p - strlen (MEM_BEGIN) - 1 - sizeof (int);
|
|
if (strcmp (begin, MEM_BEGIN))
|
|
die ("checkmem: memory corrupted - invalid head sign");
|
|
|
|
if (*(int *)(begin + strlen (MEM_BEGIN) + 1) != size)
|
|
die ("checkmem: memory corrupted - invalid size");
|
|
|
|
end = begin + size + CONTROL_SIZE - strlen (MEM_END) - 1;
|
|
if (strcmp (end, MEM_END))
|
|
die ("checkmem: memory corrupted - invalid end sign");
|
|
}
|
|
|
|
|
|
void * getmem (int size)
|
|
{
|
|
char * p;
|
|
char * mem;
|
|
|
|
p = (char *)malloc (CONTROL_SIZE + size);
|
|
if (!p)
|
|
die ("getmem: no more memory (%d)", size);
|
|
|
|
strcpy (p, MEM_BEGIN);
|
|
p += strlen (MEM_BEGIN) + 1;
|
|
*(int *)p = size;
|
|
p += sizeof (int);
|
|
mem = p;
|
|
memset (mem, 0, size);
|
|
p += size;
|
|
strcpy (p, MEM_END);
|
|
|
|
// checkmem (mem, size);
|
|
|
|
return mem;
|
|
}
|
|
|
|
|
|
void * expandmem (void * vp, int size, int by)
|
|
{
|
|
int allocated;
|
|
char * mem, * p = vp;
|
|
int expand_by = by;
|
|
|
|
if (p) {
|
|
checkmem (p, size);
|
|
allocated = CONTROL_SIZE + size;
|
|
p -= (strlen (MEM_BEGIN) + 1 + sizeof (int));
|
|
} else {
|
|
allocated = 0;
|
|
/* add control bytes to the new allocated area */
|
|
expand_by += CONTROL_SIZE;
|
|
}
|
|
p = realloc (p, allocated + expand_by);
|
|
if (!p)
|
|
die ("expandmem: no more memory (%d)", size);
|
|
if (!vp) {
|
|
strcpy (p, MEM_BEGIN);
|
|
}
|
|
mem = p + strlen (MEM_BEGIN) + 1 + sizeof (int);
|
|
|
|
*(int *)(p + strlen (MEM_BEGIN) + 1) = size + by;
|
|
/* fill new allocated area by 0s */
|
|
if(by > 0)
|
|
memset (mem + size, 0, by);
|
|
strcpy (mem + size + by, MEM_END);
|
|
// checkmem (mem, size + by);
|
|
|
|
return mem;
|
|
}
|
|
|
|
|
|
void freemem (void * vp)
|
|
{
|
|
char * p = vp;
|
|
int size;
|
|
|
|
if (!p)
|
|
return;
|
|
size = get_mem_size (vp);
|
|
checkmem (p, size);
|
|
|
|
p -= (strlen (MEM_BEGIN) + 1 + sizeof (int));
|
|
strcpy (p, MEM_FREED);
|
|
strcpy (p + size + CONTROL_SIZE - strlen (MEM_END) - 1, MEM_FREED);
|
|
free (p);
|
|
}
|
|
|
|
|
|
typedef int (*func_t) (char *);
|
|
|
|
static int is_readonly_dir (char * dir)
|
|
{
|
|
/*
|
|
int fd;
|
|
char template [1024];
|
|
|
|
snprintf (template, 1024, "%s/testXXXXXX", dir);
|
|
fd = mkstemp (template);
|
|
if (fd >= 0) {
|
|
close (fd);
|
|
return 0;
|
|
}
|
|
*/
|
|
if (utime (dir, 0) != -1)
|
|
/* this is not ro mounted fs */
|
|
return 0;
|
|
return (errno == EROFS) ? 1 : 0;
|
|
}
|
|
|
|
|
|
#ifdef __i386__
|
|
|
|
#include <unistd.h>
|
|
#include <linux/unistd.h>
|
|
|
|
#define __NR_bad_stat64 195
|
|
_syscall2(long, bad_stat64, char *, filename, struct stat64 *, statbuf);
|
|
|
|
#else
|
|
|
|
#define bad_stat64 stat64
|
|
|
|
#endif
|
|
|
|
/* yes, I know how ugly it is */
|
|
#define return_stat_field(field) \
|
|
struct stat st;\
|
|
struct stat64 st64;\
|
|
\
|
|
if (bad_stat64 (file_name, &st64) == 0) {\
|
|
return st64.st_##field;\
|
|
} else if (stat (file_name, &st) == 0)\
|
|
return st.st_##field;\
|
|
\
|
|
perror ("stat failed");\
|
|
exit (1);\
|
|
|
|
|
|
mode_t get_st_mode (char * file_name)
|
|
{
|
|
return_stat_field (mode);
|
|
}
|
|
|
|
|
|
/* may I look at this undocumented (at least in the info of libc 2.3.1-58)
|
|
field? */
|
|
dev_t get_st_rdev (char * file_name)
|
|
{
|
|
return_stat_field (rdev);
|
|
}
|
|
|
|
|
|
off64_t get_st_size (char * file_name)
|
|
{
|
|
return_stat_field (size);
|
|
}
|
|
|
|
|
|
blkcnt64_t get_st_blocks (char * file_name)
|
|
{
|
|
return_stat_field (blocks);
|
|
}
|
|
|
|
|
|
|
|
static int _is_mounted (char * device_name, func_t f)
|
|
{
|
|
int retval;
|
|
FILE *fp;
|
|
struct mntent *mnt;
|
|
struct statfs stfs;
|
|
struct stat root_st;
|
|
mode_t mode;
|
|
|
|
if (stat ("/", &root_st) == -1)
|
|
die ("is_mounted: could not stat \"/\": %m\n");
|
|
|
|
|
|
mode = get_st_mode (device_name);
|
|
if (S_ISREG (mode))
|
|
/* regular file can not be mounted */
|
|
return 0;
|
|
|
|
if (!S_ISBLK (mode))
|
|
die ("is_mounted: %s is neither regular file nor block device", device_name);
|
|
|
|
if (root_st.st_dev == get_st_rdev (device_name)) {
|
|
/* device is mounted as root. Check whether it is mounted read-only */
|
|
return (f ? f ("/") : 1);
|
|
}
|
|
|
|
/* if proc filesystem is mounted */
|
|
if (statfs ("/proc", &stfs) == -1 || stfs.f_type != 0x9fa0/*procfs magic*/ ||
|
|
(fp = setmntent ("/proc/mounts", "r")) == NULL) {
|
|
/* proc filesystem is not mounted, or /proc/mounts does not
|
|
exist */
|
|
if (f)
|
|
return (user_confirmed (stderr, " (could not figure out) Is filesystem mounted read-only? (Yes)",
|
|
"Yes\n"));
|
|
else
|
|
return (user_confirmed (stderr, " (could not figure out) Is filesystem mounted? (Yes)",
|
|
"Yes\n"));
|
|
}
|
|
|
|
retval = 0;
|
|
while ((mnt = getmntent (fp)) != NULL)
|
|
if (strcmp (device_name, mnt->mnt_fsname) == 0) {
|
|
retval = (f ? f (mnt->mnt_dir) : 1/*mounted*/);
|
|
break;
|
|
}
|
|
endmntent (fp);
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
int is_mounted_read_only (char * device_name)
|
|
{
|
|
return _is_mounted (device_name, is_readonly_dir);
|
|
}
|
|
|
|
|
|
int is_mounted (char * device_name)
|
|
{
|
|
return _is_mounted (device_name, 0);
|
|
}
|
|
|
|
|
|
char buf1 [100];
|
|
char buf2 [100];
|
|
|
|
void print_how_fast (unsigned long passed, unsigned long total,
|
|
int cursor_pos, int reset_time)
|
|
{
|
|
static time_t t0 = 0, t1 = 0, t2 = 0;
|
|
int speed;
|
|
int indent;
|
|
|
|
if (reset_time)
|
|
time (&t0);
|
|
|
|
time (&t1);
|
|
if (t1 != t0) {
|
|
speed = passed / (t1 - t0);
|
|
if (total - passed) {
|
|
if (t1 - t2 < 1)
|
|
return;
|
|
t2 = t1;
|
|
}
|
|
} else
|
|
speed = 0;
|
|
|
|
/* what has to be written */
|
|
if (total)
|
|
sprintf (buf1, "left %lu, %d /sec", total - passed, speed);
|
|
else {
|
|
/*(*passed) ++;*/
|
|
sprintf (buf1, "done %lu, %d /sec", passed, speed);
|
|
}
|
|
|
|
/* make indent */
|
|
indent = 79 - cursor_pos - strlen (buf1);
|
|
memset (buf2, ' ', indent);
|
|
buf2[indent] = 0;
|
|
fprintf (stderr, "%s%s", buf2, buf1);
|
|
|
|
memset (buf2, '\b', indent + strlen (buf1));
|
|
buf2 [indent + strlen (buf1)] = 0;
|
|
fprintf (stderr, "%s", buf2);
|
|
fflush (stderr);
|
|
}
|
|
|
|
|
|
static char * strs[] =
|
|
{"0%",".",".",".",".","20%",".",".",".",".","40%",".",".",".",".","60%",".",".",".",".","80%",".",".",".",".","100%"};
|
|
|
|
static char progress_to_be[1024];
|
|
static char current_progress[1024];
|
|
|
|
static void str_to_be (char * buf, int prosents)
|
|
{
|
|
int i;
|
|
prosents -= prosents % 4;
|
|
buf[0] = 0;
|
|
for (i = 0; i <= prosents / 4; i ++)
|
|
strcat (buf, strs[i]);
|
|
}
|
|
|
|
|
|
void print_how_far (FILE * fp,
|
|
unsigned long * passed, unsigned long total,
|
|
int inc, int quiet)
|
|
{
|
|
int percent;
|
|
|
|
if (*passed == 0)
|
|
current_progress[0] = 0;
|
|
|
|
(*passed) += inc;
|
|
if (*passed > total) {
|
|
/* fprintf (fp, "\nprint_how_far: total %lu has been reached already. cur=%lu\n",
|
|
total, *passed);*/
|
|
return;
|
|
}
|
|
|
|
percent = ((*passed) * 100) / total;
|
|
|
|
str_to_be (progress_to_be, percent);
|
|
|
|
if (strlen (current_progress) != strlen (progress_to_be)) {
|
|
fprintf (fp, "%s", progress_to_be + strlen (current_progress));
|
|
}
|
|
|
|
strcat (current_progress, progress_to_be + strlen (current_progress));
|
|
|
|
if (!quiet)
|
|
print_how_fast (*passed/* - inc*/, total, strlen (progress_to_be),
|
|
(*passed == inc) ? 1 : 0);
|
|
|
|
fflush (fp);
|
|
}
|
|
|
|
|
|
|
|
|
|
/* calculates number of blocks in a file. Returns 0 for "sparse"
|
|
regular files and files other than regular files and block devices */
|
|
unsigned long count_blocks (char * filename, int blocksize)
|
|
{
|
|
loff_t high, low;
|
|
int fd;
|
|
|
|
if (!S_ISBLK (get_st_mode (filename)) && !S_ISREG (get_st_mode (filename)))
|
|
return 0;
|
|
|
|
fd = open (filename, O_RDONLY);
|
|
if (fd == -1)
|
|
die ("count_blocks: open failed (%s)", strerror (errno));
|
|
|
|
#ifdef BLKGETSIZE64
|
|
{
|
|
__u64 size;
|
|
unsigned long sz;
|
|
|
|
if (ioctl (fd, BLKGETSIZE64, &size) >= 0) {
|
|
size /= blocksize;
|
|
sz = size;
|
|
if ((__u64)sz != size)
|
|
die ("count_blocks: block device too large");
|
|
return sz;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef BLKGETSIZE
|
|
{
|
|
unsigned long size;
|
|
|
|
if (ioctl (fd, BLKGETSIZE, &size) >= 0) {
|
|
return size / (blocksize / 512);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
low = 0;
|
|
for( high = 1; valid_offset (fd, high); high *= 2 )
|
|
low = high;
|
|
while (low < high - 1) {
|
|
const loff_t mid = ( low + high ) / 2;
|
|
|
|
if (valid_offset (fd, mid))
|
|
low = mid;
|
|
else
|
|
high = mid;
|
|
}
|
|
valid_offset (fd, 0);
|
|
|
|
close (fd);
|
|
|
|
return (low + 1) / (blocksize);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* These have been stolen somewhere from linux
|
|
*/
|
|
int le_set_bit (int nr, void * addr)
|
|
{
|
|
__u8 * p, mask;
|
|
int retval;
|
|
|
|
p = (__u8 *)addr;
|
|
p += nr >> 3;
|
|
mask = 1 << (nr & 0x7);
|
|
/*cli();*/
|
|
retval = (mask & *p) != 0;
|
|
*p |= mask;
|
|
/*sti();*/
|
|
return retval;
|
|
}
|
|
|
|
|
|
int le_clear_bit (int nr, void * addr)
|
|
{
|
|
__u8 * p, mask;
|
|
int retval;
|
|
|
|
p = (__u8 *)addr;
|
|
p += nr >> 3;
|
|
mask = 1 << (nr & 0x7);
|
|
/*cli();*/
|
|
retval = (mask & *p) != 0;
|
|
*p &= ~mask;
|
|
/*sti();*/
|
|
return retval;
|
|
}
|
|
|
|
int le_test_bit(int nr, const void * addr)
|
|
{
|
|
__u8 * p, mask;
|
|
|
|
p = (__u8 *)addr;
|
|
p += nr >> 3;
|
|
mask = 1 << (nr & 0x7);
|
|
return ((mask & *p) != 0);
|
|
}
|
|
|
|
int le_find_first_zero_bit (const void *vaddr, unsigned size)
|
|
{
|
|
const __u8 *p = vaddr, *addr = vaddr;
|
|
int res;
|
|
|
|
if (!size)
|
|
return 0;
|
|
|
|
size = (size >> 3) + ((size & 0x7) > 0);
|
|
while (*p++ == 255) {
|
|
if (--size == 0)
|
|
return (p - addr) << 3;
|
|
}
|
|
|
|
--p;
|
|
for (res = 0; res < 8; res++)
|
|
if (!test_bit (res, p))
|
|
break;
|
|
return (p - addr) * 8 + res;
|
|
}
|
|
|
|
|
|
int le_find_next_zero_bit (const void *vaddr, unsigned size, unsigned offset)
|
|
{
|
|
const __u8 *addr = vaddr;
|
|
const __u8 *p = addr + (offset >> 3);
|
|
int bit = offset & 7, res;
|
|
|
|
if (offset >= size)
|
|
return size;
|
|
|
|
if (bit) {
|
|
/* Look for zero in first char */
|
|
for (res = bit; res < 8; res++)
|
|
if (!test_bit (res, p))
|
|
return (p - addr) * 8 + res;
|
|
p++;
|
|
}
|
|
/* No zero yet, search remaining full bytes for a zero */
|
|
res = find_first_zero_bit (p, size - 8 * (p - addr));
|
|
return (p - addr) * 8 + res;
|
|
}
|
|
|
|
int be_set_bit (int nr, void * addr)
|
|
{
|
|
__u8 mask = 1 << (nr & 0x7);
|
|
__u8 *p = (__u8 *) addr + (nr >> 3);
|
|
__u8 old = *p;
|
|
|
|
*p |= mask;
|
|
|
|
return (old & mask) != 0;
|
|
}
|
|
|
|
int be_clear_bit (int nr, void * addr)
|
|
{
|
|
__u8 mask = 1 << (nr & 0x07);
|
|
__u8 *p = (unsigned char *) addr + (nr >> 3);
|
|
__u8 old = *p;
|
|
|
|
*p = *p & ~mask;
|
|
return (old & mask) != 0;
|
|
}
|
|
|
|
int be_test_bit(int nr, const void * addr)
|
|
{
|
|
const __u8 *ADDR = (__const__ __u8 *) addr;
|
|
|
|
return ((ADDR[nr >> 3] >> (nr & 0x7)) & 1) != 0;
|
|
}
|
|
|
|
int be_find_first_zero_bit (const void *vaddr, unsigned size)
|
|
{
|
|
return find_next_zero_bit( vaddr, size, 0 );
|
|
}
|
|
|
|
static unsigned long ffz(unsigned long word)
|
|
{
|
|
unsigned long result = 0;
|
|
|
|
while(word & 1) {
|
|
result++;
|
|
word >>= 1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/* stolen from linux/include/asm-mips/bitops.h:ext2_find_next_zero_bit()
|
|
* the bitfield is assumed to be little endian, which is the case here,
|
|
* since we're reading/writing from the disk in LE order */
|
|
int be_find_next_zero_bit (const void *vaddr, unsigned size, unsigned offset)
|
|
{
|
|
__u32 *p = ((__u32 *) vaddr) + (offset >> 5);
|
|
__u32 result = offset & ~31UL;
|
|
__u32 tmp;
|
|
|
|
if (offset >= size)
|
|
return size;
|
|
size -= result;
|
|
offset &= 31UL;
|
|
if (offset) {
|
|
tmp = *(p++);
|
|
tmp |= swab32(~0UL >> (32-offset));
|
|
if (size < 32)
|
|
goto found_first;
|
|
if (~tmp)
|
|
goto found_middle;
|
|
size -= 32;
|
|
result += 32;
|
|
}
|
|
while (size & ~31UL) {
|
|
if (~(tmp = *(p++)))
|
|
goto found_middle;
|
|
result += 32;
|
|
size -= 32;
|
|
}
|
|
if (!size)
|
|
return result;
|
|
tmp = *p;
|
|
|
|
found_first:
|
|
return result + ffz(swab32(tmp) | (~0UL << size));
|
|
found_middle:
|
|
return result + ffz(swab32(tmp));
|
|
}
|
|
|
|
/* there are masks for certain bits */
|
|
__u16 mask16 (int from, int count)
|
|
{
|
|
__u16 mask;
|
|
|
|
|
|
mask = (0xffff >> from);
|
|
mask <<= from;
|
|
mask <<= (16 - from - count);
|
|
mask >>= (16 - from - count);
|
|
return mask;
|
|
}
|
|
|
|
|
|
__u32 mask32 (int from, int count)
|
|
{
|
|
__u32 mask;
|
|
|
|
|
|
mask = (0xffffffff >> from);
|
|
mask <<= from;
|
|
mask <<= (32 - from - count);
|
|
mask >>= (32 - from - count);
|
|
return mask;
|
|
}
|
|
|
|
|
|
__u64 mask64 (int from, int count)
|
|
{
|
|
__u64 mask;
|
|
|
|
|
|
mask = (0xffffffffffffffffLL >> from);
|
|
mask <<= from;
|
|
mask <<= (64 - from - count);
|
|
mask >>= (64 - from - count);
|
|
return mask;
|
|
}
|
|
|
|
|
|
__u32 get_random (void)
|
|
{
|
|
srandom (time (0));
|
|
return random ();
|
|
}
|
|
|
|
/* this implements binary search in the array 'base' among 'num' elements each
|
|
of those is 'width' bytes long. 'comp_func' is used to compare keys */
|
|
int reiserfs_bin_search (void * key, void * base, __u32 num, int width,
|
|
__u32 * ppos, comparison_fn_t comp_func)
|
|
{
|
|
__u32 rbound, lbound, j;
|
|
int ret;
|
|
|
|
if (num == 0 || base == NULL) {
|
|
/* objectid map may be 0 elements long */
|
|
*ppos = 0;
|
|
return POSITION_NOT_FOUND;
|
|
}
|
|
|
|
lbound = 0;
|
|
rbound = num - 1;
|
|
|
|
for (j = (rbound + lbound) / 2; lbound <= rbound; j = (rbound + lbound) / 2) {
|
|
ret = comp_func ((void *)((char *)base + j * width), key ) ;
|
|
if (ret < 0) { /* second is greater */
|
|
lbound = j + 1;
|
|
continue;
|
|
|
|
} else if (ret > 0) { /* first is greater */
|
|
if (j == 0)
|
|
break;
|
|
rbound = j - 1;
|
|
continue;
|
|
} else { /* equal */
|
|
*ppos = j;
|
|
return POSITION_FOUND;
|
|
}
|
|
}
|
|
|
|
*ppos = lbound;
|
|
return POSITION_NOT_FOUND;
|
|
}
|
|
|
|
|
|
#define BLOCKLIST__INCREASE_BLOCK_NUMBER 10
|
|
|
|
/*element is block number and device*/
|
|
int blockdev_list_compare (const void * block1, const void * block2) {
|
|
if (*(__u32 *)block1 < *(__u32 *)block2)
|
|
return -1;
|
|
if (*(__u32 *)block1 > *(__u32 *)block2)
|
|
return 1;
|
|
|
|
if (*((__u32 *)block1 + 1) < *((__u32 *)block2 + 1))
|
|
return -1;
|
|
if (*((__u32 *)block1 + 1) > *((__u32 *)block2 + 1))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* return -1 if smth found, otherwise return position which new item should be inserted into */
|
|
/*
|
|
int blocklist__is_block_saved (struct block_handler ** base, __u32 * count,
|
|
__u32 blocknr, dev_t device, __u32 * position) {
|
|
struct block_handler block_h;
|
|
|
|
*position = 0;
|
|
|
|
if (*base == NULL)
|
|
return 0;
|
|
|
|
block_h.blocknr = blocknr;
|
|
block_h.device = device;
|
|
|
|
if (reiserfs_bin_search (&block_h, *base, *count, sizeof (block_h),
|
|
position, blocklist_compare) == POSITION_FOUND)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
*/
|
|
void blocklist__insert_in_position (void ** base, __u32 * count, void * elem,
|
|
int elem_size, __u32 * position) {
|
|
if (elem_size == 0)
|
|
return;
|
|
|
|
if (*base == NULL)
|
|
*base = getmem (BLOCKLIST__INCREASE_BLOCK_NUMBER * elem_size);
|
|
|
|
if (*count == get_mem_size ((void *)*base) / elem_size)
|
|
*base = expandmem (*base, get_mem_size((void *)*base),
|
|
BLOCKLIST__INCREASE_BLOCK_NUMBER * elem_size);
|
|
|
|
if (*position < *count) {
|
|
memmove (*base + (*position + 1),
|
|
*base + (*position),
|
|
(*count - *position) * elem_size);
|
|
}
|
|
|
|
memcpy (*base + (char) *position * elem_size, elem, elem_size);
|
|
*count+=1;
|
|
}
|
|
|
|
static int get_random_bytes (void *out, int size) {
|
|
int fd;
|
|
|
|
if ((fd = open("/dev/urandom", O_RDONLY)) == -1)
|
|
return 1;
|
|
|
|
if (read(fd, out, size) <= 0) {
|
|
close (fd);
|
|
return 1;
|
|
}
|
|
|
|
close (fd);
|
|
return 0;
|
|
}
|
|
|
|
int generate_random_uuid (unsigned char * uuid)
|
|
{
|
|
if (get_random_bytes(uuid, 16)) {
|
|
return -1;
|
|
}
|
|
|
|
/* Set the UUID variant to DCE */
|
|
uuid[8] = (uuid[8] & 0x3F) | 0x80;
|
|
/* Set UUID version to 4 --- truely random generation */
|
|
uuid[6] = (uuid[6] & 0x0F) | 0x40;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int uuid_is_correct (unsigned char * uuid)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
if (uuid[i])
|
|
break;
|
|
|
|
if (i == 16)
|
|
return 0;
|
|
|
|
if (!test_bit(7, &uuid[8]) || test_bit(6, &uuid[8]))
|
|
return 0;
|
|
|
|
if (test_bit(7, &uuid[6]) || !test_bit(6, &uuid[6]) ||
|
|
test_bit(5, &uuid[6]) || test_bit(4, &uuid[6]))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int parse_uuid (const unsigned char * in, unsigned char * uuid)
|
|
{
|
|
int i, j = 0;
|
|
unsigned char frame[3];
|
|
|
|
if (strlen(in) != 36)
|
|
return -1;
|
|
|
|
for (i = 0; i < 36; i++) {
|
|
if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
|
|
if (in[i] != '-')
|
|
return 0;
|
|
} else if (!isxdigit(in[i])) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
frame[2] = 0;
|
|
for (i = 0; i < 36; i ++) {
|
|
if ((i == 8) || (i == 13) || (i == 18) || (i == 23))
|
|
continue;
|
|
|
|
frame[0] = in[i++];
|
|
frame[1] = in[i];
|
|
uuid[j++] = strtoul(frame, NULL, 16);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int set_uuid (const unsigned char * text, unsigned char * UUID)
|
|
{
|
|
if (parse_uuid (text, UUID) || !uuid_is_correct(UUID))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|