-
Notifications
You must be signed in to change notification settings - Fork 0
/
device.c
191 lines (177 loc) · 4.89 KB
/
device.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
* device.c
*
* Modified on: 24/03/2023
* Author: Robert Sheehan
*
* N.B. You are not allowed to modify this file, except as mentioned below.
*/
#include "device.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define NUMBLOCKS 16 // you are allowed to change this value for further testing
#define EBADBLOCK 1
#define EOPENINGDEVICE 2
#define ECREATINGMMAP 3
#define EINSTALLATEXIT 4
/* The device is really just an array of blocks. */
block *deviceBlocks;
/* The device error number. */
int dev_errno = 0;
/*
* Prints the message and then information about the most recent error.
*/
void printDevError(char *message) {
fprintf(stderr, "%s ERROR: %i ", message, BLOCK_SIZE);
switch (dev_errno) {
case EBADBLOCK:
fprintf(stderr, "bad block number\n");
break;
case EOPENINGDEVICE:
fprintf(stderr, "unable to open device\n");
break;
case ECREATINGMMAP:
fprintf(stderr, "unable to memory map device\n");
break;
case EINSTALLATEXIT:
fprintf(stderr, "unable to install atexit handler\n");
break;
default:
fprintf(stderr, "unknown error\n");
}
}
/*
* Ensures the data is flushed back to disk when the program exits.
*/
void removeDevice() {
if (munmap(deviceBlocks, NUMBLOCKS * BLOCK_SIZE) == -1) {
perror("ERROR removing mmap");
}
}
/*
* Connects an area of memory with the file representing the device.
* Only called once each time the program is run.
*/
int connectDevice() {
int dev_fd;
struct stat fileStatus;
if ((dev_fd = open("device_file", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) == -1) {
dev_errno = EOPENINGDEVICE;
return -1;
}
if (fstat(dev_fd, &fileStatus)) {
dev_errno = EOPENINGDEVICE;
return -1;
}
int size = fileStatus.st_size;
unsigned char data[BLOCK_SIZE]; // could be garbage until formatted
while (size < NUMBLOCKS * BLOCK_SIZE) {
if (write(dev_fd, data, BLOCK_SIZE) == -1) {
dev_errno = EOPENINGDEVICE;
return -1;
}
size += BLOCK_SIZE;
}
deviceBlocks = (block *)mmap(NULL, NUMBLOCKS * BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0);
if ((long)deviceBlocks == -1) {
dev_errno = ECREATINGMMAP;
return -1;
}
if (atexit(removeDevice)) {
dev_errno = EINSTALLATEXIT;
return -1;
}
return 0;
}
/*
* Checks to see if the device is attached.
* If not it tries to connect it.
* Returns -1 if there is a problem, 0 otherwise.
*/
int badDevice() {
static int unconnected = 1;
if (unconnected) {
if (connectDevice()) {
return -1;
}
unconnected = 0;
}
return 0;
}
/*
* Read a block of data from the device.
* blockNumber - the number of the block to read
* data - the address of the position to put the block data
* The data must be exactly BLOCK_SIZE long.
* Returns 0 if successful, -1 if an error occurred.
*/
int blockRead(int blockNumber, unsigned char *data) {
if (badDevice())
return -1;
if (blockNumber < 0 || blockNumber > NUMBLOCKS - 1) {
dev_errno = EBADBLOCK;
return -1;
}
memcpy(data, deviceBlocks[blockNumber], BLOCK_SIZE);
return 0;
}
/*
* Write a block of data to the device.
* blockNumber - the number of the block to write
* data - the address of the position to get the block data
* The data must be exactly BLOCK_SIZE long.
* Returns 0 if successful, -1 if an error occurred.
*/
int blockWrite(int blockNumber, unsigned char *data) {
if (badDevice())
return -1;
if (blockNumber < 0 || blockNumber > NUMBLOCKS - 1) {
dev_errno = EBADBLOCK;
return -1;
}
memcpy(deviceBlocks[blockNumber], data, BLOCK_SIZE);
return 0;
}
/*
* Reports the number of blocks in the device.
*/
int numBlocks() {
return NUMBLOCKS;
}
/*
* Displays the contents of a block on stdout.
* Not really a device function, just for debugging and marking.
*/
void displayBlock(int blockNumber) {
block b;
if (blockRead(blockNumber, b)) {
printDevError("-- displayBlock --");
} else {
printf("\nBlock %d\n", blockNumber);
printf("==========\n");
int row;
int col;
const int number_per_row = 16;
unsigned char *byte = b;
for (row = 0; row < BLOCK_SIZE / number_per_row; ++row) {
unsigned char *byte2 = byte;
for (col = 0; col < number_per_row; ++col) {
printf("%02x ", *byte++);
}
printf("\t");
for (col = 0; col < number_per_row; ++col) {
unsigned char c = *byte2++;
if (c < 32 || c > 126)
c = '-';
printf("%c", c);
}
printf("\n");
}
}
}