Skip to content

Commit 2e7342c

Browse files
committed
Initial commit.
0 parents  commit 2e7342c

11 files changed

Lines changed: 1223 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TODO

blockdev.c

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#define _FILE_OFFSET_BITS 64
2+
#include <stdbool.h>
3+
#include <stdio.h>
4+
#include <string.h>
5+
#include <errno.h>
6+
#include <fcntl.h> // open()...
7+
#include <linux/fs.h> // BLKGETSIZE64...
8+
#include <sys/ioctl.h> // ioctl()...
9+
#include <sys/stat.h> // S_IRUSR, S_IWUSR...
10+
#include <unistd.h> // write(), close()...
11+
#include "types.h"
12+
13+
14+
// Create files with rw-rw---- permissions.
15+
#define DEFAULT_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
16+
17+
18+
static int g_fd = -1;
19+
static bool g_isRegularFile = false;
20+
static u64 g_diskSectors = 0;
21+
22+
23+
24+
int blkdevOpen(const char *const path)
25+
{
26+
// Always block access to /dev/sdaX because in 99% of cases this is the system drive.
27+
// TODO: There may be edge cases where this is not true.
28+
// Find a more reliable way to detect system drives.
29+
// This won't work for example on devices with NVMe SSD.
30+
if(strncmp(path, "/dev/sda", 8) == 0)
31+
{
32+
fprintf(stderr, "Blocked access to '%s'. Don't mess with your system drive!\n", path);
33+
return EACCES;
34+
}
35+
36+
int res = 0;
37+
int fd;
38+
do
39+
{
40+
// Note: There is no reliable way of locking block device files so we don't and hope nothing explodes.
41+
// flock() only works between processes using it.
42+
fd = open(path, O_RDWR | O_CREAT, DEFAULT_PERM);
43+
if(fd == (-1))
44+
{
45+
res = errno;
46+
break;
47+
}
48+
49+
u64 diskSize;
50+
struct stat fileStat;
51+
if(fstat(fd, &fileStat) != 0)
52+
{
53+
res = errno;
54+
break;
55+
}
56+
57+
// Test if regular file or block device.
58+
if(!S_ISBLK(fileStat.st_mode))
59+
{
60+
g_isRegularFile = true;
61+
diskSize = fileStat.st_size;
62+
}
63+
else
64+
{
65+
if(ioctl(fd, BLKGETSIZE64, &diskSize) != 0)
66+
{
67+
res = errno;
68+
break;
69+
}
70+
}
71+
72+
g_fd = fd;
73+
g_diskSectors = diskSize / 512;
74+
} while(0);
75+
76+
if(res != 0)
77+
{
78+
perror("Failed to open block device");
79+
if(fd != (-1)) close(fd);
80+
}
81+
return res;
82+
}
83+
84+
u64 blkdevGetSectors(void)
85+
{
86+
return g_diskSectors;
87+
}
88+
89+
int blkdevReadSectors(void *buf, const u64 sector, const u64 count)
90+
{
91+
int res = 0;
92+
const int fd = g_fd;
93+
if(lseek(fd, sector * 512, SEEK_SET) != (-1))
94+
{
95+
u64 totSize = count * 512;
96+
while(totSize > 0)
97+
{
98+
// Limit of 1 GiB chunks.
99+
const size_t blkSize = (totSize > 0x40000000 ? 0x40000000 : totSize);
100+
const ssize_t _read = read(fd, buf, blkSize);
101+
if(_read == (-1))
102+
{
103+
res = errno;
104+
break;;
105+
}
106+
107+
buf += _read; // TODO: void pointer math is ub.
108+
totSize -= _read;
109+
}
110+
}
111+
else res = errno;
112+
113+
if(res != 0) perror("Failed to read from block device");
114+
return res;
115+
}
116+
117+
int blkdevWriteSectors(const void *buf, const u64 sector, const u64 count)
118+
{
119+
int res = 0;
120+
const int fd = g_fd;
121+
if(lseek(fd, sector * 512, SEEK_SET) != (-1))
122+
{
123+
u64 totSize = count * 512;
124+
while(totSize > 0)
125+
{
126+
// Limit of 1 GiB chunks.
127+
const size_t blkSize = (totSize > 0x40000000 ? 0x40000000 : totSize);
128+
const ssize_t written = write(fd, buf, blkSize);
129+
if(written == (-1))
130+
{
131+
res = errno;
132+
break;;
133+
}
134+
135+
buf += written; // TODO: void pointer math is ub.
136+
totSize -= written;
137+
}
138+
}
139+
else res = errno;
140+
141+
if(res != 0) perror("Failed to write to block device");
142+
return res;
143+
}
144+
145+
// Note: This is only valid for image files.
146+
int blkdevTruncate(const u64 sectors)
147+
{
148+
int res = 0;
149+
const int fd = g_fd;
150+
if(g_isRegularFile == true)
151+
{
152+
while((res = ftruncate(fd, 512 * sectors)) == (-1) && errno == EINTR);
153+
}
154+
else res = ENOTBLK;
155+
156+
if(res == 0) g_diskSectors = sectors;
157+
else if(res != 0) perror("Failed to truncate file");
158+
return res;
159+
}
160+
161+
// TODO: Should we return any error that is not EINTR?
162+
void blkdevClose(void)
163+
{
164+
const int fd = g_fd;
165+
fsync(fd);
166+
while(close(fd) == (-1) && errno == EINTR);
167+
168+
g_fd = -1;
169+
g_isRegularFile = false;
170+
g_diskSectors = 0;
171+
}

blockdev.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#pragma once
2+
3+
#include "types.h"
4+
5+
6+
7+
int blkdevOpen(const char *const path);
8+
u64 blkdevGetSectors(void);
9+
int blkdevReadSectors(void *buf, const u64 sector, const u64 count);
10+
int blkdevWriteSectors(const void *buf, const u64 sector, const u64 count);
11+
int blkdevTruncate(const u64 sectors);
12+
void blkdevClose(void);

compile.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
rm ./sdFormatLinux
3+
gcc -std=c17 -s -flto -O2 -fstrict-aliasing -ffunction-sections -fdata-sections -Wall -Wextra -Wl,--gc-sections ./sdFormatLinux.c ./fs_printer.c ./format.c ./blockdev.c -lm -o ./sdFormatLinux

0 commit comments

Comments
 (0)