-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsimplefs_apis.c
277 lines (258 loc) · 10.5 KB
/
simplefs_apis.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
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
#include "simplefs.h"
#include "simplefs_apis.h"
// checks the permission to authorize the function call
//root user has access to EVERYTHING
int check_permissions(uint8_t required, FileControlBlock fcb, int current_user, int usr_in_grp) {
if (fcb.permissions.user_uid == current_user || current_user == ROOT) {
//check if the owner has requested permission on the directory
if (fcb.permissions.user & required || current_user == ROOT) {
return SUCCESS;
}
} else {
//check if the current user is in the owner's group
if (usr_in_grp == SUCCESS) {
//checking if the group permissions include requested permission
if (fcb.permissions.group & required) {
return SUCCESS;
}
} else {
//check if the other permissions include requested permission
if (fcb.permissions.others & required) {
return SUCCESS;
}
}
}
return FAILED;
}
// initializes a file system on an already made disk
// returns a handle to the top level directory stored in the first block
DirectoryHandle *init(SimpleFS *fs, DiskDriver *disk, int current_user, int user_primary_group) {
DirectoryHandle *dh;
if (current_user == ROOT) {
dh = SimpleFS_init(fs, disk);
//we set the default permissions (755)
dh->dcb->fcb.permissions.user_uid = current_user;
dh->dcb->fcb.permissions.group_uid = user_primary_group;
dh->dcb->fcb.permissions.user = READ | WRITE | EXECUTE;
dh->dcb->fcb.permissions.group = READ | EXECUTE;
dh->dcb->fcb.permissions.others = READ | EXECUTE;
//saving the updated Directory
DiskDriver_writeBlock(disk, dh->dcb, sizeof(FirstDirectoryBlock));
return dh;
}
return NULL;
}
// creates the initial structures, the top level directory
// has name "/" and its control block is in the first position
// it also clears the bitmap of occupied blocks on the disk
// the current_directory_block is cached in the SimpleFS struct
// and set to the top level directory
int formatDisk(SimpleFS *fs, int current_user) {
if (current_user == ROOT) {
SimpleFS_format(fs);
return SUCCESS;
}
return PERM_ERR;
}
//loads an already initialized disk
int loadDisk(DiskDriver *disk, const char *filename) {
return DiskDriver_load(disk, filename);
}
void shutdownDisk(DiskDriver *disk) {
DiskDriver_shutdown(disk);
}
// creates an empty file in the directory d
// returns null on error (file existing, no free blocks)
// an empty file consists only of a block of type FirstBlock
// it requires WRITE permission on the DirectoryHandle
FileHandle *
createFile(DirectoryHandle *d, const char *filename, int current_user, int user_primary_group, int usr_in_grp) {
FileHandle *f = NULL;
int res;
//check if the current user has permissions to perform the operation
if (check_permissions(WRITE, d->dcb->fcb, current_user, usr_in_grp) == SUCCESS) {
f = SimpleFS_createFile(d, filename);
if (f == NULL) {
return f;
}
//we set the owner and owner group of the newly created file
f->fcb->fcb.permissions.user_uid = current_user;
f->fcb->fcb.permissions.group_uid = user_primary_group;
//now we set the default permission on this file (644)
f->fcb->fcb.permissions.user = READ | WRITE;
f->fcb->fcb.permissions.group = READ;
f->fcb->fcb.permissions.others = READ;
//we write the permissions on disk
res = DiskDriver_writeBlock(f->sfs->disk, f->fcb, f->fcb->header.block_in_disk);
CHECK_ERR(res == FAILED, "can't update permission on the new file")
}
return f;
}
// reads in the (preallocated) blocks array, the name of all files in a directory
// it requires READ permission
int readDir(char **names, DirectoryHandle *d, int current_user, int usr_in_grp) {
int res = PERM_ERR;
//check if the current user has permissions to perform the operation
if (check_permissions(READ, d->dcb->fcb, current_user, usr_in_grp) == SUCCESS) {
res = SimpleFS_readDir(names, d);
}
return res;
}
// opens a file in the directory d. The file should be existing
// it requires WRITE | READ permission on the file and READ permission on the directory
FileHandle *openFile(DirectoryHandle *d, const char *filename, int current_user, int usr_in_grp) {
FileHandle *f = NULL;
//check if the current user has permissions to read the directory
if (check_permissions(READ, d->dcb->fcb, current_user, usr_in_grp) == SUCCESS) {
f = SimpleFS_openFile(d, filename);
if (f != NULL) {
//check if the current user can read or write the opened file
if (check_permissions(READ, f->fcb->fcb, current_user, usr_in_grp) != SUCCESS &&
check_permissions(WRITE, f->fcb->fcb, current_user, usr_in_grp) != SUCCESS) {
//if not close the file
SimpleFS_close(f);
f = NULL;
}
}
}
return f;
}
// closes a file handle (destroyes it)
// it requires WRITE | READ permission
void closeFile(FileHandle *f) {
SimpleFS_close(f);
}
// writes in the file, at current position for size bytes stored in data
// overwriting and allocating new space if necessary
// returns the number of bytes written
// it requires WRITE permission
int writeFile(FileHandle *f, void *data, int size, int current_user, int usr_in_grp) {
//checking if the user has WRITE permission on the file
if (check_permissions(WRITE, f->fcb->fcb, current_user, usr_in_grp) == SUCCESS) {
return SimpleFS_write(f, data, size);
}
return PERM_ERR;
}
// reads in the file, at current position size bytes stored in data
// overwriting and allocating new space if necessary
// returns the number of bytes read
// it requires READ permission
int readFile(FileHandle *f, void *data, int size, int current_user, int usr_in_grp) {
//check if the user has READ permission on the file
if (check_permissions(READ, f->fcb->fcb, current_user, usr_in_grp) == SUCCESS) {
return SimpleFS_read(f, data, size);
}
return PERM_ERR;
}
// returns the number of bytes read (moving the current pointer to pos)
// returns pos on success -1 on error (file too short)
// it requires WRITE | READ permission
int seekFile(FileHandle *f, int pos, int current_user, int usr_in_grp) {
//check if the user has the read or write permissions
if (check_permissions(READ, f->fcb->fcb, current_user, usr_in_grp) == SUCCESS ||
check_permissions(WRITE, f->fcb->fcb, current_user, usr_in_grp) == SUCCESS) {
return SimpleFS_seek(f, pos);
}
return PERM_ERR;
}
// seeks for a directory in d. If dirname is equal to ".." it goes one level up
// 0 on success, negative value on error
// it does side effect on the provided handle
// it requires EXECUTE permission
int changeDir(DirectoryHandle *d, const char *dirname, int current_user, int usr_in_grp) {
//checking EXECUTE permission on the directory
if (check_permissions(EXECUTE, d->dcb->fcb, current_user, usr_in_grp) == SUCCESS) {
return SimpleFS_changeDir(d, dirname);
}
return PERM_ERR;
}
// creates a new directory in the current one (stored in fs->current_directory_block)
// 0 on success -1 on error
// it requires WRITE permission
int mkDir(DirectoryHandle *d, const char *dirname, int current_user, int user_primary_group, int usr_in_grp) {
int res, res_disk;
//we check if the user has write permission on the current directory
if (check_permissions(WRITE, d->dcb->fcb, current_user, usr_in_grp) == SUCCESS) {
res = SimpleFS_mkDir(d, dirname);
//we get the DirectoryHandle of the current directory
SimpleFS_changeDir(d, dirname);
//we set default permission for the current user in this directory
//we set owner and owner group
d->dcb->fcb.permissions.user_uid = current_user;
d->dcb->fcb.permissions.group_uid = user_primary_group;
// we set the directory default permissions (755)
d->dcb->fcb.permissions.user = READ | WRITE | EXECUTE;
d->dcb->fcb.permissions.group = READ | EXECUTE;
d->dcb->fcb.permissions.others = READ | EXECUTE;
//we write the permission on disk
res_disk = DiskDriver_writeBlock(d->sfs->disk, d->dcb, d->dcb->header.block_in_disk);
CHECK_ERR(res_disk == FAILED, "can't write directory permission on disk")
//we go back to the parent directory
SimpleFS_changeDir(d, "..");
return res;
}
return PERM_ERR;
}
// removes the file in the current directory
// returns -1 on failure 0 on success
// if a directory, it removes recursively all contained files
// it requires WRITE permission on the directory which contains the element to remove
int removeFile(DirectoryHandle *d, const char *filename, int current_user, int usr_in_grp) {
//we check if the user has write permission on the current directory
if (check_permissions(WRITE, d->dcb->fcb, current_user, usr_in_grp) == SUCCESS) {
return SimpleFS_remove(d, filename);
}
return PERM_ERR;
}
/* setting the permissions on a file/directory according to the values of each set
it can be called by the root user or the owner of the file
if one permission is FAILED then the function leaves that permission unmodified
this function can takes a DirectoryHandle or a FileHandle and modifies the permissions,
you cant modify permission for a file and a directory simultaneously, so one of them MUST be NULL*/
int SimpleFS_chmod(FileHandle *f, int user, int group, int others, int current_user) {
//chmod can only be execute by root user
if (current_user != ROOT) {
return PERM_ERR;
}
int res;
//we check if we are operating on a file o directory
if (f != NULL) {
//now we change permissions only for the specified fields
if (user != MISSING) {
f->fcb->fcb.permissions.user = (uint8_t) user;
}
if (group != MISSING) {
f->fcb->fcb.permissions.group = (uint8_t) group;
}
if (others != MISSING) {
f->fcb->fcb.permissions.others = (uint8_t) others;
}
// we write the file with the new permissions on disk
res = DiskDriver_writeBlock(f->sfs->disk, f->fcb, f->fcb->header.block_in_disk);
CHECK_ERR(res == FAILED, "can't save new file permissions")
return SUCCESS;
}
return FAILED;
}
/*change a file/directory owner
it can be called by the root user or by the owner of the file
this function can takes a DirectoryHandle or a FileHandle
you can't modify ownership of a file and a directory simultaneously, so one of them MUST be NULL*/
int SimpleFS_chown(FileHandle *f, int new_owner, int new_owner_primary_group, int current_user) {
// if we have a file we change its ownership
int res;
if (f != NULL) {
// we check that we are authorized to change the ownership
if (f->fcb->fcb.permissions.user_uid != current_user && current_user != ROOT) {
return PERM_ERR;
}
//we change the ownership
f->fcb->fcb.permissions.user_uid = new_owner;
f->fcb->fcb.permissions.group_uid = new_owner_primary_group;
// we save the changes on disk
res = DiskDriver_writeBlock(f->sfs->disk, f->fcb, f->fcb->header.block_in_disk);
CHECK_ERR(res == FAILED, "can't save new ownership of the file")
return SUCCESS;
}
return FAILED;
}