Last active
October 10, 2016 18:31
-
-
Save spacelatte/f8a99486e5027a86f7efe75d48593fc3 to your computer and use it in GitHub Desktop.
disk managament/partitioning program in C (you can use arbitary files as disk images also)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <ctype.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <stdarg.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <locale.h> | |
#include <time.h> | |
#include <fcntl.h> | |
#define BS 65536 | |
#define OUT stderr | |
#define MAXPARTS 12 | |
#define LBLSIZE 256 | |
#define HEXWIDTH 32 | |
#define CLR_DEFAULT "\033[0m" | |
#define CLR_BLACK "\033[30m" | |
#define CLR_RED "\033[31m" | |
#define CLR_GREEN "\033[32m" | |
#define CLR_YELLOW "\033[33m" | |
#define MAX(a,b) ( (a>b)?(a):(b) ) | |
#define MIN(a,b) ( (a<b)?(a):(b) ) | |
// typedef enum { false, true } bool; | |
typedef enum part_flags { | |
UNALLOCATED = 0, | |
STANDARD = 1<<0, | |
HIDDEN = 1<<1, | |
BOOT = 1<<2, | |
READONLY = 1<<3, | |
SWAP = 1<<4, | |
_PR1 = 1<<5, | |
_PR2 = 1<<6, | |
_PR3 = 1<<7, | |
_PR4 = 1<<8, | |
} part_flags_t; | |
typedef enum disk_flags { | |
UNINITIALIZED = 0, | |
INITIALIZED = 1<<0, | |
GHOST = 1<<1, | |
BACKUP = 1<<2, | |
RAID = 1<<3, | |
TEMP = 1<<4, | |
_DR1 = 1<<5, | |
_DR2 = 1<<6, | |
_DR3 = 1<<7, | |
_DR4 = 1<<8, | |
} disk_flags_t; | |
typedef struct part { | |
unsigned long id; | |
unsigned long start; | |
unsigned long end; | |
unsigned short type; | |
unsigned char flags; | |
char label[LBLSIZE]; | |
} part_t; | |
typedef struct disk { | |
unsigned long id; | |
unsigned long size; | |
unsigned char flags; | |
char label[LBLSIZE]; | |
part_t parts[MAXPARTS]; | |
} disk_t; | |
const char magic[] = {'t', 'e', 's', 't', '\0'}; | |
char mode = 0; | |
void print(FILE *output, const char *function, const char *format, ...) { | |
va_list args; | |
va_start(args,format); | |
char data[strlen(function)+strlen(format)+32]; | |
sprintf(data,"[%ld] [%s]: %s\n",time(NULL),function,format); | |
vfprintf(output,data,args); | |
va_end(args); | |
return; | |
} | |
void hexdump(void *object, size_t length) { | |
for(int i=0;i<length;i++) { | |
if(i%HEXWIDTH == 0) | |
printf("\n% 8d |",i); | |
printf(" %2hhx",*(char*)(object+i)); | |
} | |
printf("\n%8zu\n",length); | |
return; | |
} | |
void error(FILE *out, unsigned short code, const char *err, ...) { | |
va_list args; | |
va_start(args,err); | |
char data[strlen(err)+32]; | |
sprintf(data,"\033[31mERR (%hd): %s\033[0m\n",code,err); | |
vfprintf(out,data,args); | |
va_end(args); | |
return; | |
} | |
disk_t *disk_create(void) { | |
disk_t *disk = malloc(sizeof(disk_t)); | |
return disk; | |
} | |
void disk_edit(disk_t *disk, unsigned long id, unsigned char flags, const char *label, long size) { | |
if(!disk) { | |
error(OUT,1,"valid disk pointer necessary to edit drive"); | |
return; | |
} | |
disk->id = id; | |
disk->flags = flags; | |
if(size) | |
disk->size = size; | |
if(label) | |
strncpy(disk->label,label,LBLSIZE); | |
return; | |
} | |
part_t *part_create(void) { | |
part_t *part = malloc(sizeof(part_t)); | |
return part; | |
} | |
void part_edit(part_t *part, unsigned long id, unsigned long start, unsigned long end, unsigned short type, unsigned char flags, const char *label) { | |
// do sanity checks | |
if(!part || start < 2048 || start <= sizeof(disk_t)/*+sizeof(magic)*/ || end <= start) { | |
error(OUT,2,"part edit param check failed"); | |
return; | |
} | |
part->id = id; | |
part->start = start; | |
part->end = end; | |
part->type = type; | |
part->flags = flags; | |
if(label) | |
strncpy(part->label,label,LBLSIZE); | |
return; | |
} | |
void disk_initialize(disk_t *disk, long size) { | |
if(disk) { | |
memset(disk,0,sizeof(disk_t)); // just zero main table | |
disk_edit(disk,time(NULL),INITIALIZED,NULL,size); | |
} | |
return; | |
if(disk) { | |
free(disk); // remove old reference | |
disk = disk_create(); // and create new | |
} | |
return; | |
} | |
void part_create_handler(disk_t *disk) { | |
char label[LBLSIZE]; | |
short part, type; | |
long start, end; | |
printf("enter partition number to create (%d-%d): ",1,MAXPARTS); | |
scanf(" %hd",&part); | |
printf("enter start (%lu-%lu): ",(MAX(2048,sizeof(disk_t)))/(1<<mode),(disk->size-1)/(1<<mode)); | |
scanf(" %ld",&start); | |
printf("enter end (%lu-%lu): ",start+1,(disk->size-1)/(1<<mode)); | |
scanf(" %ld",&end); | |
printf("enter type (%04x-%04x): ",0x0001,0xffff); | |
scanf(" %hx",&type); | |
printf("enter label: "); | |
scanf(" %[^\n]",label); | |
start *= (1<<mode); | |
end *= (1<<mode); | |
if(start <= MAX(2048,sizeof(disk_t))) | |
start = MAX(2048,sizeof(disk_t))+1; | |
if(end >= disk->size-1 || end <= start) | |
end = disk->size-1; | |
if(disk->parts[part].id && disk->parts[part].flags) { | |
error(OUT,31,"error, this space is allocated already"); | |
return; | |
} | |
for(int i=0;i<MAXPARTS;i++) { | |
if(start >= disk->parts[i].start && start <= disk->parts[i].end) { | |
error(OUT,32,"error, this space is allocated already"); | |
return; | |
} | |
if(end <= disk->parts[i].end && start >= disk->parts[i].start) { | |
error(OUT,33,"error, this space is allocated already"); | |
return; | |
} | |
continue; | |
} | |
// print(OUT,__func__,"part; s: %ld, e: %ld",start,end); | |
part_edit(&(disk->parts[part-1]),time(NULL),start,end,type,STANDARD,label); | |
return; | |
} | |
void part_delete(disk_t *disk, unsigned part) { | |
memset(disk->parts+part,0,sizeof(part_t)); | |
return; | |
} | |
void pretty_print(disk_t *disk) { | |
printf( | |
"disk id: %ld\n" | |
"disk size: %ld\n" | |
"disk flags: %02x\n" | |
"disk label: %s\n" | |
,disk->id | |
,disk->size/(1<<mode) | |
,disk->flags | |
,disk->label | |
); | |
for(int i=0;i<MAXPARTS;i++) | |
if(disk->parts[i].id && disk->parts[i].flags) | |
printf( | |
"\t> partition: %d\n" | |
"\tpart id: %ld\n" | |
"\tpart size: %ld\n" | |
"\tpart start: %ld\n" | |
"\tpart end: %ld\n" | |
"\tpart type: %04x\n" | |
"\tpart flags: %02x\n" | |
"\tpart label: %s\n" | |
"\n",i+1 | |
,disk->parts[i].id | |
,((disk->parts[i].end)-(disk->parts[i].start))/(1<<mode) | |
,disk->parts[i].start | |
,disk->parts[i].end | |
,disk->parts[i].type | |
,disk->parts[i].flags | |
,disk->parts[i].label | |
); | |
return; | |
} | |
void write_to(int fd, disk_t *disk) { | |
lseek(fd,0,SEEK_SET); | |
write(fd,magic,sizeof(magic)); | |
write(fd,disk,sizeof(disk_t)); | |
return; | |
} | |
bool menu(const char *file, disk_t *disk) { | |
int fd = open(file, O_RDWR|O_CREAT|O_SYMLINK); | |
char *bytes = malloc(sizeof(magic)); | |
long size = lseek(fd,0L,SEEK_END); | |
lseek(fd,0L,SEEK_SET); | |
read(fd,bytes,sizeof(magic)); | |
if(!disk->id && !disk->size) { | |
read(fd,disk,sizeof(disk_t)); | |
for(int i=0;i<sizeof(magic);i++) | |
if(magic[i] != bytes[i]) { | |
disk_initialize(disk,size); | |
error(OUT,4,"partition table not found, creating new one"); | |
write_to(fd,disk); | |
break; | |
} | |
disk->size = size; | |
} | |
free(bytes); // free mem | |
// menu | |
printf( | |
"o) new partition table\n" | |
"n) new partition\n" | |
"d) delete partition\n" | |
"m) change coefficient (k/m/g)\n" | |
"p) show table\n" | |
"x) hexdump current\n" | |
"w) write to disk\n" | |
"e) exit (switches to next)\n" | |
"q) quit application\n" | |
"#) wipe drive\n" | |
"selection: (mode: 2^%hhd) > ",mode | |
); | |
char sel; | |
scanf(" %c",&sel); | |
if(sel > 127 || sel < 32) | |
return false; | |
char *block = malloc(sizeof(char)*BS); | |
switch(tolower(sel)) { | |
case 'o': | |
disk_initialize(disk,size); | |
break; | |
case 'n': | |
part_create_handler(disk); | |
break; | |
case 'd': | |
printf("enter partition number to delete (%d-%d): ",1,MAXPARTS); | |
scanf(" %hhd",&sel); | |
if(sel > 0 && sel < MAXPARTS) | |
part_delete(disk,sel-1); | |
else | |
error(OUT,6,"invalid input"); | |
break; | |
case 'x': | |
hexdump(disk,sizeof(disk_t)); | |
break; | |
case 'p': | |
pretty_print(disk); | |
break; | |
case 'w': | |
write_to(fd,disk); | |
break; | |
case 'e': | |
return false; | |
break; | |
case 'm': | |
printf("enter desired mode (n/k/m/g): "); | |
scanf(" %c",&sel); | |
switch(tolower(sel)) { | |
case 'n': | |
mode = 0; | |
break; | |
case 'k': | |
mode = 10; | |
break; | |
case 'm': | |
mode = 20; | |
break; | |
case 'g': | |
mode = 30; | |
break; | |
default: | |
error(stdout,7,"not implemented"); | |
} | |
break; | |
case 'q': | |
exit(0); | |
break; | |
case '#': | |
lseek(fd,0L,SEEK_SET); | |
printf("Wipe sequence initialized to sector %ld\n",size); | |
for(long i=0;i<size;i+=BS) { | |
printf("> from %ld, to %ld, current %ld \n",sizeof(disk_t),size,i); | |
write(fd,block,sizeof(char)*BS); | |
} | |
break; | |
default: | |
error(stdout,0,"not implemented"); | |
} | |
close(fd); | |
return true; | |
} | |
int main(int argc, char **argv) { | |
if(argc < 2) { | |
error(OUT,0,"At least 1 argument required!"); | |
return 1; | |
} | |
disk_t *cdisk = malloc(sizeof(disk_t)); | |
// print(OUT,__func__,"test %d",1); | |
for(int i=1;i<argc;i++) { | |
while(menu(argv[i],cdisk)); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment