-
Notifications
You must be signed in to change notification settings - Fork 0
/
softwaredisk.c
155 lines (134 loc) · 3.71 KB
/
softwaredisk.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
//
// Software disk implementation for LSU 4103 filesystem assignment.
// Written by Golden G. Richard III (@nolaforensix), 10/2017.
//
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include "softwaredisk.h"
#define NUM_BLOCKS 5000
#define BACKING_STORE "sdprivate.sd"
// internals of software disk implementation
typedef struct SoftwareDiskInternals {
FILE *fp;
} SoftwareDiskInternals;
//
// GLOBALS
//
static SoftwareDiskInternals sd;
// software disk error code set (set by each software disk function).
SDError sderror;
// initializes the software disk to all zeros, destroying any existing
// data. Returns 1 on success, otherwise 0. Always sets global 'sderror'.
int init_software_disk() {
int i;
char block[SOFTWARE_DISK_BLOCK_SIZE];
sderror=SD_NONE;
sd.fp=fopen(BACKING_STORE, "w+");
if (! sd.fp) {
sderror=SD_INTERNAL_ERROR;
return 0;
}
bzero(block, SOFTWARE_DISK_BLOCK_SIZE);
for (i=0; i < NUM_BLOCKS; i++) {
if (fwrite(block, SOFTWARE_DISK_BLOCK_SIZE, 1, sd.fp) != 1) {
fclose(sd.fp);
sd.fp=NULL;
sderror=SD_INTERNAL_ERROR;
return 0;
}
}
return 1;
}
// returns the size of the SoftwareDisk in multiples of SOFTWARE_DISK_BLOCK_SIZE
unsigned long software_disk_size() {
return NUM_BLOCKS;
}
// writes a block of data from 'buf' at location 'blocknum'. Blocks are numbered
// from 0. The buffer 'buf' must be of size SOFTWARE_DISK_BLOCK_SIZE. Returns 1
// on success or 0 on failure. Always sets global 'sderror'.
int write_sd_block(void *buf, unsigned long blocknum) {
sderror=SD_NONE;
if (! sd.fp) {
sd.fp=fopen(BACKING_STORE, "r+");
if (! sd.fp) {
sderror=SD_INTERNAL_ERROR;
return 0;
}
else {
fseek(sd.fp, 0L, SEEK_END);
if (ftell(sd.fp) != NUM_BLOCKS * SOFTWARE_DISK_BLOCK_SIZE) {
fclose(sd.fp);
sd.fp=0;
sderror=SD_NOT_INIT;
return 0;
}
}
}
if (blocknum > NUM_BLOCKS-1) {
sderror=SD_ILLEGAL_BLOCK_NUMBER;
return 0;
}
fseek(sd.fp, blocknum * SOFTWARE_DISK_BLOCK_SIZE, SEEK_SET);
if (fwrite(buf, SOFTWARE_DISK_BLOCK_SIZE, 1, sd.fp) != 1) {
sderror=SD_INTERNAL_ERROR;
return 0;
}
fflush(sd.fp);
return 1;
}
// reads a block of data into 'buf' from location 'blocknum'. Blocks are numbered
// from 0. The buffer 'buf' must be of size SOFTWARE_DISK_BLOCK_SIZE. Returns 1
// on success or 0 on failure. Always sets global 'sderror'.
int read_sd_block(void *buf, unsigned long blocknum) {
sderror=SD_NONE;
if (! sd.fp) {
sd.fp=fopen(BACKING_STORE, "r+");
if (! sd.fp) {
sderror=SD_INTERNAL_ERROR;
return 0;
}
else {
fseek(sd.fp, 0L, SEEK_END);
if (ftell(sd.fp) != NUM_BLOCKS * SOFTWARE_DISK_BLOCK_SIZE) {
fclose(sd.fp);
sd.fp=0;
sderror=SD_NOT_INIT;
return 0;
}
}
}
if (blocknum > NUM_BLOCKS-1) {
sderror=SD_ILLEGAL_BLOCK_NUMBER;
return 0;
}
fseek(sd.fp, blocknum * SOFTWARE_DISK_BLOCK_SIZE, SEEK_SET);
if (fread(buf, SOFTWARE_DISK_BLOCK_SIZE, 1, sd.fp) != 1) {
sderror=SD_INTERNAL_ERROR;
return 0;
}
fflush(sd.fp);
return 1;
}
// describe current software disk error code by printing a descriptive message to
// standard error.
void sd_print_error(void) {
switch (sderror) {
case SD_NONE:
printf("SD: No error.\n");
break;
case SD_NOT_INIT:
printf("SD: Software disk not initialized.\n");
break;
case SD_ILLEGAL_BLOCK_NUMBER:
printf("SD: Illegal block number.\n");
break;
case SD_INTERNAL_ERROR:
printf("SD: Internal error, software disk unusuable.\n");
break;
default:
printf("SD: Unknown error code %d.\n", sderror);
}
}
// software disk error code set (set by each software disk function).
SDError sderror;