-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFS.cpp
More file actions
404 lines (337 loc) · 12.7 KB
/
FS.cpp
File metadata and controls
404 lines (337 loc) · 12.7 KB
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
/** @file FS.cpp
*
* File System implementation
*
* @author Copyright Aniesh Chawla, Sept 2015
**/
#include "FS.h"
#include "Directory.h"
#include <iostream>
FS::FS()
{ }
FS::~FS()
{ }
int FS::open(Volume& volume, const char *path, const char *name)
{
int fd = 0;
//TODO("Implement FS::open()");
// Check if file was already opened (has entry in open file table):
// Check all open file entries for count > 0.
// If the volume, path, and file name match, then ++count and return fd.
// Otherwise, set fd to a free entry in the open file table with count == 0
// and set the open_file.name to the open() name argument.
// If no entries are available then report error and return DISK_ERROR.
while((fd < MAX_OPEN_FILES)){
if(strcmp(open_file_table[fd].name.cstr() , name)==0){
break;
}
fd++;
}
if (fd==MAX_OPEN_FILES){
fd = 0;
while(open_file_table[fd].count!=0 && fd<MAX_OPEN_FILES){
fd++;
}
if(fd == MAX_OPEN_FILES) fd=DISK_ERROR;
else {
assert(open_file_table[fd].count == 0);
open_file_table[fd].name = name;
}
}
OpenFile& open_file = open_file_table[fd];//we used & symbol because if we change open_file we want corresponding
//change to happend in open_file_table entry also
// Create a Directory object for the volume's FAT and use Directory::chdir()
// to move to the path location of the file.
// The dir should now point to the directory of the file.
// If the dir does not exist, then report and return DISK_ERROR.
Directory dir(volume.get_fat());
dir.chdir(path);
//if(!dir.exists(open_file.name)) return DISK_ERROR;
// Get the FCB of the file via the dir object.
const FCB *fcb_file = dir.get_fcb(open_file.name);
// If there is no FCB, then this is a new file so we create a new FCB with
// size = 0, type = FILE_TYPE, created = time(NULL), and we allocate a new
// start_block from the FAT of the volume.
if(fcb_file == NULL) {
FCB fcb;
fcb.size = 0;
fcb.type = FILE_TYPE;
fcb.created = time(NULL);
fcb.start_block = volume.get_fat().alloc();
open_file.start_block = fcb.start_block;
dir.set_fcb(open_file.name, fcb);
}
// Otherwise, if there is an FCB, then set the open_file.size and
// open_file.start_block from the FCB attributes.
else{
open_file.size = fcb_file->size;
open_file.start_block = fcb_file->start_block;
}
// Set the other open_file attributes:
open_file.pos = 0;
open_file.volume= &volume;
open_file.current_block = open_file.start_block;
open_file.current_block_pos = 0;
open_file.updated = false;
// Increment the open_file.count.
open_file.count++;
//fd = DISK_ERROR;
return fd;
}
void FS::close(int fd)
{
OpenFile& open_file = open_file_table[fd];
assert(open_file.count > 0);
//TODO("Implement FS::close()");
// If the file was updated, update its FCB in the directory:
if (open_file.updated)
{
// Create a Directory object for the volume's FAT and use Directory::chdir()
// to move to the path location of the file.
// The dir should now point to the directory of the file.
// If the dir does not exist, then report and return DISK_ERROR.
Directory dir(open_file.volume->get_fat());
dir.chdir(open_file.path);
if(!dir.exists(open_file.name)) exit DISK_ERROR;
// Get the FCB object of the file, update it with the open_file attributes
// such as size, and set the FCB of the file
const FCB *fcb_file = dir.get_fcb(open_file.name);
if(fcb_file==NULL){
}
open_file.count--;
/* if(open_file.count==0){
open_file.size = 0;
open_file.start_block = 0;
FCB fcb;
fcb.size = 0;
fcb.start_block = 0;
dir.set_fcb(open_file.name, fcb);
}*/
// What to do if the FCB was not found? This could happen when the file is
// deleted before closed. So rm() must check if the file is not open!
}
// Decrement the open_file.count
}
int FS::read(int fd, char *buf, int len)
{
OpenFile& open_file = open_file_table[fd];
assert(open_file.count > 0);
//TODO("Implement FS::read()");
int block_num = open_file.current_block;
int byte_to_read = len;
Volume &vol = *open_file.volume;
FAT &file_table = vol.get_fat();
Disk &read_fm_disk = file_table.get_disk();
int block_size = read_fm_disk.block_size();
char blk[block_size];
// We need to copy data of at most len bytes from disk to the buf argument.
//std::cout<<"we are reading the file with length "<<len<<std::endl;
while(len>0){
open_file.current_block = block_num;
size_t read_len = std::min(len,block_size);
read_fm_disk.read(block_num,blk);
int read_length = open_file.current_block_pos + read_len;
//std::cout<<"read length= "<<read_length<<" current_block_pos= "<<open_file.current_block_pos<<std::endl;
//std::cout<<"block_size= "<<read_fm_disk.block_size()<<" block_num "<<block_num<<std::endl;
open_file.pos +=read_len;
if(read_length > block_size ){
memcpy(buf,blk+open_file.current_block_pos,block_size-open_file.current_block_pos);
block_num = file_table.find_next(block_num);
open_file.current_block = block_num;
read_fm_disk.read(block_num,blk);
//std::cout<<"value copied till now is "<< buf<<std::endl;
//std::cout<<"value to be copied "<< blk<<std::endl;
read_len -= (block_size - open_file.current_block_pos);
buf+= (block_size - open_file.current_block_pos);
len-= (block_size - open_file.current_block_pos);
open_file.current_block_pos = 0;
}
//if(block_num==24) std::cout<<"value should be "<<blk+open_file.current_block_pos<<std::endl;
memcpy(buf,blk+open_file.current_block_pos,read_len);
buf+=read_len;
if(read_len<block_size) {
open_file.current_block_pos += read_len;
if(open_file.current_block_pos > block_size) open_file.current_block_pos-=block_size;
}
else{
block_num = file_table.find_next(block_num);
}
len-=read_len;
}
// To do so, use a loop to copy the data in chunks.
// Within the loop, update the open_file.pos position in the file,
// the open_file.current_block, and open_file.current_block_pos offset into
// the current block being read.
// You need to get the FAT of the volume of the open file and use find_next()
// to find the blocks.
// Return the number of bytes copied, or DISK_ERROR when an error occurred.
return byte_to_read;
}
int FS::write(int fd, char *buf, int len)
{
OpenFile& open_file = open_file_table[fd];
assert(open_file.count > 0);
open_file.updated = true;
//TODO("Implement FS::write()");
// We need to copy data from buf of length len to disk.
// To do so, use a loop to copy the data in chunks.
// Within the loop, update the open_file.size, open_file.pos,
// the open_file.current_block, and open_file.current_block_pos offset into
// the current block being written.
Volume &vol = *open_file.volume;
FAT &file_table = vol.get_fat();
Disk &fm_disk = file_table.get_disk();
Directory dir(file_table);
FCB fcb_of_file;
int block_size = fm_disk.block_size();
char blk[block_size];
const FCB *old_fcb_file = dir.get_fcb(open_file.name);
int block_num = open_file.current_block;
// We need to copy data of at most len bytes from disk to the buf argument.
while(len>0){
size_t read_len = std::min(len,block_size);
char buf_disk[block_size];
//std::cout<<"the block number is "<<block_num<<std::endl;
if(open_file.current_block_pos == block_size){
//std::cout<<"we are inside this block num "<<block_num<<std::endl;
block_num = file_table.alloc_next(block_num);
open_file.current_block = block_num;
open_file.current_block_pos = 0;
fm_disk.read(block_num,buf_disk);
}
fm_disk.read(block_num,buf_disk);
char write_buf[block_size];
memcpy(write_buf,buf_disk,open_file.current_block_pos);
int read_length = open_file.current_block_pos+read_len;
open_file.pos +=read_len;
open_file.size+=read_len;
if(read_length > block_size){
memcpy(write_buf+open_file.current_block_pos,buf,block_size- open_file.current_block_pos);
fm_disk.write(block_num,write_buf);
block_num = file_table.alloc_next(block_num);
open_file.current_block = block_num;
buf+=block_size-open_file.current_block_pos;
read_len -= block_size - open_file.current_block_pos;
len-= block_size - open_file.current_block_pos;
open_file.current_block_pos = 0;
fm_disk.read(block_num,buf_disk);
read_length = read_len;
}
memcpy(write_buf+open_file.current_block_pos,buf,read_len);
memcpy(write_buf+read_length, buf_disk + read_length,block_size- read_length);
if(read_len<block_size){
open_file.current_block_pos+=read_len;
if(open_file.current_block_pos>block_size){
open_file.current_block_pos-=block_size;
}
}
fm_disk.write(block_num,write_buf);
buf+=read_len;
len-=read_len;
}
fcb_of_file.type = old_fcb_file->type;
fcb_of_file.size = open_file.size;
fcb_of_file.created = old_fcb_file->created;
fcb_of_file.start_block = old_fcb_file->start_block;
dir.set_fcb(open_file.name,fcb_of_file);
// You need to get the FAT of the volume of the open file and use
// alloc_next() to find or get new blocks.
// Note that writing data inside blocks may require reading blocks first.
// Return DISK_OK or DISK_ERROR.
return DISK_OK;
}
int FS::seek(int fd, int pos)
{
OpenFile& open_file = open_file_table[fd];
assert(open_file.count > 0);
FAT &fat_file = (open_file.volume->get_fat());
int block_size = fat_file.get_disk().block_size();
//TODO("Implement FS::seek()");
//std::cout<<"the file position= "<<open_file.pos<<" requested pos= "<<pos<<std::endl;
int block_shifts = (pos - open_file.pos);
int offset = pos%block_size;
//std::cout<<"block shifts "<<block_shifts<<" offset "<<offset<<std::endl;
if(open_file.size < pos) return DISK_ERROR;
else{
if(block_shifts < 0) {
block_shifts = (int)(pos/block_size) - (int)(open_file.pos/block_size);
if(open_file.pos == ((int)(open_file.pos/block_size))*block_size) block_shifts++;
//std::cout<<"block shifts negative is "<<block_shifts<<std::endl;
block_shifts = open_file.current_block - open_file.start_block + block_shifts;
//std::cout<<"the block shifts from start are "<<block_shifts<<std::endl;
open_file.current_block = open_file.start_block;
}
open_file.pos = pos;
while(block_shifts > 0 ){
open_file.current_block = fat_file.find_next(open_file.current_block);
block_shifts--;
}
open_file.current_block_pos = offset;
return DISK_OK;
}
// Change the open_file.pos, open_file.current_block, and
// open_file.current_block_pos within the allowable range of the file
// where the range is 0 to size-1.
// Return DISK_OK or DISK_ERROR when an error occurred
return DISK_ERROR;
}
int FS::ls(Volume& volume, const char *path)
{
Directory dir(volume.get_fat());
dir.chdir(path);
printf("Volume %s:%s (%d blocks, %d free)\n", volume.get_name(), path, volume.get_fat().num_blocks(), volume.get_fat().num_free_blocks());
dir.list();
return DISK_OK;
}
int FS::rm(Volume& volume, const char *path, const char *name)
{
//TODO("Implement FS::rm()");
int fd = -1;
Directory dir(volume.get_fat());
dir.chdir(path);
FileName file_name(name);
const FCB* file_fcb = dir.get_fcb(file_name);
// Check if this is a regular file.
if(file_fcb->type !=FILE_TYPE) return DISK_ERROR;
// Check if the file is not open.
while((fd < MAX_OPEN_FILES)){
if(strcmp(open_file_table[fd].name.cstr() , name)==0){
break;
}
fd++;
}
// Create a Directory object for the volume's FAT and use Directory::chdir()
// to move to the path location of the file.
// The dir should now point to the directory of the file.
// If the dir does not exist, then report and return DISK_ERROR.
// Use Directory::erase() to remove the file.
if(fd != MAX_OPEN_FILES){
assert(open_file_table[fd].count ==0);
dir.erase(file_name);
return DISK_OK;
}
// Return DISK_OK or DISK_ERROR.
return DISK_ERROR;
}
int FS::mkdir(Volume& volume, const char *path, const char *name)
{
Directory dir(volume.get_fat());
dir.chdir(path);
FileName dir_name(name);
return dir.mkdir(dir_name);
}
int FS::rmdir(Volume& volume, const char *path, const char *name)
{
Directory dir(volume.get_fat());
dir.chdir(path);
FileName dir_name(name);
const FCB* file_fcb = dir.get_fcb(dir_name);
//TODO("Complete FS::rmdir()");
// Check if this is a directory.
if(file_fcb->type !=DIR_TYPE) return DISK_ERROR;
if(!dir.exists(dir_name)) return DISK_ERROR;
// Check if the directory is empty.
//if(!dir.empty()) return DISK_ERROR;
dir.erase(dir_name);
return DISK_OK;
}