/* * Copyright 1996-2002 Hans Reiser */ /* for stat64() */ #define _FILE_OFFSET_BITS 64 /* for getline() proto and _LARGEFILE64_SOURCE */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include //#include //#include #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 */ #include /* 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 #include #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; }