LuPPC/src/c/blkdev.c

155 lines
3.9 KiB
C

#include "lupi.h"
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <linux/hdreg.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
struct blkdev {
int fd;
int secsize;
int platters;
size_t size;
char * buffer;
};
int blk_open(lua_State * L) {
char * path = luaL_checkstring(L, 1);
char rpath[255];
sprintf(rpath, "/dev/%s", path);
int fd = open(rpath, O_RDWR | O_DSYNC);
if (fd == -1) {
luaL_error(L, "Failed to open %s: %s", rpath, strerror(errno));
}
struct blkdev * dev = lua_newuserdata(L, sizeof(struct blkdev));
dev->fd = fd;
struct hd_driveid driveid;
if (ioctl(fd, HDIO_GET_IDENTITY, &driveid) < 0) {
//luaL_error("Failed to get identity for %s", rpath);
dev->platters = 3;
// Use another ioctl call to get sector size.
if (!ioctl(fd, BLKSSZGET, &dev->secsize)) {
// Fuck it, i guess it's 512 bytes.
dev->secsize = 512;
// Maybe a warning here?
}
dev->size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
} else {
dev->size = driveid.lba_capacity_2*driveid.sector_bytes;
dev->platters = driveid.cur_heads/2;
dev->secsize = driveid.sector_bytes;
if (dev->size == 0) {
dev->size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
}
if (dev->platters == 0) {
dev->platters = 3;
}
if (dev->secsize == 0) {
if (!ioctl(fd, BLKSSZGET, &dev->secsize)) {
// Fuck it, i guess it's 512 bytes.
dev->secsize = 512;
// Maybe a warning here too?
}
}
}
dev->buffer = malloc(dev->secsize);
return 1;
}
int blk_readbyte(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
off_t offset = luaL_checkinteger(L, 2);
lseek(dev->fd, offset-1, SEEK_SET);
uint8_t c = 0;
size_t ioc = 0;
if ((ioc = read(dev->fd, &c, 1)) != 1) {
luaL_error(L, "io error! %llu != %llu", ioc, 1);
}
lua_pushinteger(L, c);
return 1;
}
int blk_writebyte(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
off_t offset = luaL_checkinteger(L, 2);
long byte = luaL_checkinteger(L, 3);
if (byte > 255 || byte < 0)
luaL_error(L, "%lld is out of range (should be between 0 and 255)", byte);
uint8_t i = byte & 0xFF;
lseek(dev->fd, offset-1, SEEK_SET);
size_t ioc = 0;
if ((ioc = write(dev->fd, &i, 1)) != 1) {
luaL_error(L, "io error! %llu != %llu", ioc, 1);
}
return 0;
}
int blk_readsector(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
off_t offset = luaL_checkinteger(L, 2);
lseek(dev->fd, (offset-1)*dev->secsize, SEEK_SET);
size_t ioc = 0;
if ((ioc = read(dev->fd, dev->buffer, dev->secsize)) != dev->secsize) {
luaL_error(L, "io error! %llu != %llu", ioc, dev->secsize);
}
lua_pushlstring(L, dev->buffer, dev->secsize);
return 1;
}
int blk_writesector(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
off_t offset = luaL_checkinteger(L, 2);
size_t len = 0;
char * sec = luaL_checklstring(L, 3, &len);
lseek(dev->fd, (offset-1)*dev->secsize, SEEK_SET);
if (len > dev->secsize) {
len = dev->secsize;
}
size_t ioc = 0;
if ((ioc = write(dev->fd, sec, len)) != len) {
luaL_error(L, "io error! %llu != %llu", ioc, dev->secsize);
}
return 0;
}
int blk_getsecsize(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
lua_pushinteger(L, dev->secsize);
return 1;
}
int blk_getsize(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
lua_pushinteger(L, dev->size);
return 1;
}
int blk_getplatcount(lua_State * L) {
struct blkdev * dev = lua_touserdata(L, 1);
lua_pushinteger(L, dev->platters);
return 1;
}
void blk_start(lua_State * L) {
struct luaL_Reg blklib[] = {
{"open", blk_open},
{"readbyte", blk_readbyte},
{"writebyte", blk_writebyte},
{"readsector", blk_readsector},
{"writesector", blk_writesector},
{"secsize", blk_getsecsize},
{"size", blk_getsize},
{"platcount", blk_getplatcount},
{NULL, NULL}
};
luaL_openlib(L, "blk", blklib, 0);
}