-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathentry.c
executable file
·494 lines (395 loc) · 15.7 KB
/
entry.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
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
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
#include <linux/string.h>
#include <linux/kernel.h>
#include "fat.h"
#include "entry.h"
#include "file.h"
#ifdef __KERNEL__
#define printf printk
#endif
BOOL get_dir_path(ps16_t file_path, ps16_t dir_path)
{
ps16_t last_seperator = strrchr(file_path, L'/');
printf("get_dir_path last_seperator : %s\n", last_seperator);
if(last_seperator == NULL)
return FALSE;
strncpy(dir_path, file_path, last_seperator - file_path);
return TRUE;
}
BOOL get_file_name(ps16_t file_path, ps16_t file_name)
{
ps16_t last_seperator = strrchr(file_path, L'/');
printf("get_file_name last_seperator : %s\n", last_seperator);
if(last_seperator == NULL)
return FALSE;
strcpy(file_name, last_seperator + 1);
return TRUE;
}
/*
함수명 : search_fileDirectoryEntryInDirCluster
하는일 : 디렉토리 클러스터 안에 파일 디렉토리 엔트리를 찾는다.
디렉토리가 가지고 있는 모든 클러스터를 순환하여
파일 이름과 같은 엔트리를 찾는다.
인자 : fVolume : 루프백이미지/파일 볼륨의 포인터
nDirClusterNumber : 디렉토리 클러스터 번호
pFileName : 파일이름의 문자열 포인터
pSearchedDirEntry : 검색된 디렉토리 엔트리의 포인터
리턴 값 : BOOL
*/
BOOL get_dentry(struct mfs_volume* volume, u128 dir_cluster_number,
ps16_t file_name, struct mfs_dirent* searched_dir_entry)
{
u8_t cluster[CLUSTER_SIZE] = {0, };
const u32_t entry_per_data_cluster = CLUSTER_SIZE / sizeof(struct mfs_dirent);
s16_t composited_file_name[128] = {0, };
BOOL has_long_file_name_next_entry = FALSE;
u128 read_position = 0;
u128 current_cluster_number = dir_cluster_number;
u32_t current_entry_number = 0;
struct mfs_dirent* current_dir_entry = NULL;
u128 end_cluster = get_end_cluster(volume);
printf("get_dentry: %s\n", file_name);
// 디렉토리의 모든 클러스터를 검사한다.
while(current_cluster_number != end_cluster)
{
printf("current_cluster_number: %d\n", current_cluster_number);
read_position = read_cluster(volume, current_cluster_number);
#ifdef __KERNEL__
seek_volume(volume, read_position);
#else
seek_volume(volume, read_position, SEEK_SET);
#endif
read_volume(volume, cluster, sizeof(u8_t), CLUSTER_SIZE);
current_dir_entry = get_first_entry(cluster, ¤t_entry_number, has_long_file_name_next_entry);
while(current_entry_number != entry_per_data_cluster)
{
printf("current entry number after : %d\n", current_entry_number);
if(is_normal_file(current_dir_entry->attribute) == TRUE)
{
// 얻은 엔트리가 LongFileName인지 여부 검사
if(is_long_file_name(current_dir_entry->attribute) == TRUE)
{
// LongFileName일 경우 LongFileName을 조합한다.
composite_long_file_name(volume, current_cluster_number, current_entry_number, composited_file_name);
}
else
{
// 일반 FileName일 경우 복사
strcpy(composited_file_name, current_dir_entry->name);
}
// Name 비교
if(!strcmp(file_name, composited_file_name))
{
memcpy(searched_dir_entry, current_dir_entry, sizeof(struct mfs_dirent));
return TRUE;
}
}
// 다음 엔트리를 얻는다.
current_dir_entry = get_next_entry(cluster, ¤t_entry_number, &has_long_file_name_next_entry);
}
current_cluster_number = read_fat_index(volume, current_cluster_number);
printf("read fat index : %d\n", current_cluster_number);
}
printf("file not exist\n");
return FALSE;
}
/*
함수명 : search_routeCluster
하는일 : 경로 끝의 클러스터 수치를 구한다.
pRoute를 strtok '/' 로 자르고 NULL이 나올때까지 디렉토리를
참조해 들어간다.
ex) 한번 자르고 NULL이 아니라면 자른 값이 현재 디렉토리안에 엔트리가 있는지
여부를 검사, 존재한다면 그곳으로 또 잘라서 참조해 들어간다.
인자 : fVolume : 루프백이미지/파일 볼륨의 포인터
pRoute : 경로의 문자열 포인터
리턴 값 : BOOL
*/
u32_t get_cluster_number(struct mfs_volume* volume, ps16_t path)
{
u8_t current_cluster[CLUSTER_SIZE] = {0, };
ps16_t seperated_path = strtok(path, "/");
const u32_t entry_per_data_cluster = CLUSTER_SIZE / sizeof(struct mfs_dirent);
struct mfs_dirent* current_dir_entry = NULL;
s16_t composited_file_name[128] = {0, };
u128 current_cluster_number = 2; // Root Directory의 클러스터 값
u32_t current_entry_number = 0;
BOOL is_dir_changed = FALSE;
BOOL has_long_file_name_next_entry = FALSE;
u128 end_cluster = get_end_cluster(volume);
u128 read_position = read_cluster(volume, current_cluster_number);
#ifdef __KERNEL__
seek_volume(volume, read_position);
#else
seek_volume(volume, read_position, SEEK_SET);
#endif
read_volume(volume, current_cluster, sizeof(u8_t), CLUSTER_SIZE);
while(seperated_path != NULL)
{
is_dir_changed = FALSE;
// 클러스터의 첫 엔트리를 얻는다.
current_dir_entry = get_first_entry(current_cluster, ¤t_entry_number, has_long_file_name_next_entry);
// 클러스터의 모든 엔트리를 검사한다.
while(current_entry_number != entry_per_data_cluster)
{
// 얻은 엔트리가 폴더일 경우
if(is_normal_dir(current_dir_entry->attribute) == TRUE)
{
// 얻은 엔트리가 LongFileName인지 여부 검사
if(is_long_file_name(current_dir_entry->attribute) == TRUE)
{
// LongFileName일 경우 LongFileName을 조합한다.
composite_long_file_name(volume, current_cluster_number, current_entry_number, composited_file_name);
}
else
{
// 일반 FileName일 경우 복사
strcpy(composited_file_name, current_dir_entry->name);
}
// Name 비교
if(!strcmp(seperated_path, composited_file_name))
{
// 일치한다면 다음 route 경로 명을 얻는다.
seperated_path = strtok(NULL, "/");
current_cluster_number = current_dir_entry->head_cluster_number;
is_dir_changed = TRUE;
break;
}
}
// 다음 엔트리를 얻는다.
current_dir_entry = get_next_entry(current_cluster, ¤t_entry_number, &has_long_file_name_next_entry);
}
// 현재 탐색 디렉토리가 변경되지 않았다면 현재 디렉토리의 다음 클러스터를 얻는다.
if (is_dir_changed == FALSE)
{
current_cluster_number = read_fat_index(volume, current_cluster_number);
// route 경로가 잘못되었다.
if(current_cluster_number == end_cluster)
{
printf("wrong route\n");
return 0;
}
}
// 지정된 번호의 클러스터를 읽는다.
read_position = read_cluster(volume, current_cluster_number);
#ifdef __KERNEL__
seek_volume(volume, read_position);
#else
seek_volume(volume, read_position, SEEK_SET);
#endif
read_volume(volume, current_cluster, sizeof(u8_t), CLUSTER_SIZE);
}
return current_cluster_number;
}
/*
함수명 : writeDirEntryInDirCluster
하는일 : 디렉토리 클러스터안에 디렉토리 엔트리를 추가한다.
디렉토리의 모든 클러스터를 검사하여, 빈 엔트리를 찾고 그 위치에 디렉토리 엔트리를 추가한다.
인자 : fVolume : 루프백이미지/파일 볼륨의 포인터
nDirClusterNumber : 디렉토리 클러스터 번호
pDirectoryEntry : 디렉토리 엔트리의 포인터
pFileName : 파일 이름의 문자열 포인터
리턴 값 : BOOL
*/
BOOL alloc_new_dirent(struct mfs_volume* volume, u128 dir_cluster_number, struct mfs_dirent* dirent, ps16_t file_name)
{
u8_t cluster[CLUSTER_SIZE] = {0, };
const u32_t entry_per_data_cluster = CLUSTER_SIZE / sizeof(struct mfs_dirent);
BOOL has_long_file_name_next_entry = FALSE;
u128 read_position = 0;
u128 wirte_position = 0;
u128 current_cluster_number = dir_cluster_number;
u128 before_cluster_number = 0;
u32_t current_entry_number = 0;
struct mfs_dirent* current_dirent = NULL;
u128 end_cluster = get_end_cluster(volume);
// 디렉토리의 모든 클러스터를 검사한다.
while(current_cluster_number != end_cluster)
{
read_position = read_cluster(volume, current_cluster_number);
#ifdef __KERNEL__
seek_volume(volume, read_position);
#else
seek_volume(volume, read_position, SEEK_SET);
#endif
read_volume(volume, cluster, sizeof(u8_t), CLUSTER_SIZE);
current_dirent = get_first_entry(cluster, ¤t_entry_number, has_long_file_name_next_entry);
while(current_entry_number != entry_per_data_cluster)
{
// if (current_dirent->size == 0)
if( is_deleted_file(current_dirent->attribute) || is_deleted_dir(current_dirent->attribute) )
{
wirte_position = read_position + (current_entry_number * sizeof(struct mfs_dirent));
#ifdef __KERNEL__
seek_volume(volume, wirte_position);
#else
seek_volume(volume, wirte_position, SEEK_SET);
#endif
write_volume(volume, dirent, sizeof(struct mfs_dirent), 1);
printf("alloc_new_dirent %d %d\n", current_cluster_number, wirte_position);
return TRUE;
}
// 다음 엔트리를 얻는다.
current_dirent = get_next_entry(cluster, ¤t_entry_number, &has_long_file_name_next_entry);
}
before_cluster_number = current_cluster_number;
current_cluster_number = read_fat_index(volume, current_cluster_number);
}
// 디렉토리 클러스터에 빈 공간이 없다, 클러스터 추가
current_cluster_number = find_empty_fat_index(volume);
write_in_fat_index(volume, before_cluster_number, current_cluster_number);
write_in_fat_index(volume, current_cluster_number, end_cluster);
wirte_position = read_cluster(volume, current_cluster_number);
#ifdef __KERNEL__
seek_volume(volume, wirte_position);
#else
seek_volume(volume, wirte_position, SEEK_SET);
#endif
write_volume(volume, dirent, sizeof(struct mfs_dirent), 1);
printf("alloc_new_dirent %d %d\n", current_cluster_number, wirte_position);
return TRUE;
}
/*
함수명 : getFirstEntry
하는일 : 클러스터의 처음 엔트리를 얻는다.
이전 클러스터에서 LongFileName Entry가 계속되고 있는지 여부를 bLongFileNameContinueToNextCluster로
알아낸다.
nCurEntryNumber에는 현재 Entry의 수치를 넣어준다.
인자 : pCluster : 클러스터의 포인터
nCurEntryNumber : 현재 엔트리의 번호
bLongFileNameContinueToNextCluster : LongFileName이 다음 클러스터까지 연속되어졌는지 여부
리턴 값 : struct mfs_dirent*
*/
struct mfs_dirent* get_first_entry(pu8_t cluster, u32_t* current_entry_number, BOOL has_long_file_name_next_entry)
{
struct mfs_LFN_entry* current_long_file_name_entry = NULL;
(*current_entry_number) = 0;
if(has_long_file_name_next_entry == TRUE)
{
do {
++(*current_entry_number);
} while(current_long_file_name_entry->id != 0x40);
}
return (struct mfs_dirent *)&cluster[(*current_entry_number) * sizeof(struct mfs_dirent)];
}
/*
함수명 : getNextEntry
하는일 : 클러스터의 다음 엔트리를 얻는다.
nCurEntryNumber를 토대로 다음 엔트리를 구한다.
LongFileName일시 LongFileName이 끝날때까지 Cluster를 검색한다.
인자 : pCluster : 클러스터의 포인터
nCurEntryNumber : 현재 엔트리의 번호
bLongFileNameContinueToNextCluster : LongFileName이 다음 클러스터까지 연속되어졌는지 여부
리턴 값 : struct mfs_dirent*
*/
struct mfs_dirent* get_next_entry(pu8_t cluster, u32_t* current_entry_number, BOOL* has_long_file_name_next_entry)
{
const u32_t entry_per_data_cluster = CLUSTER_SIZE / sizeof(struct mfs_dirent);
struct mfs_dirent* current_dir_entry = (struct mfs_dirent *)&cluster[(*current_entry_number) * sizeof(struct mfs_dirent)];
struct mfs_LFN_entry* current_long_file_name_entry = NULL;
if(is_long_file_name(current_dir_entry->attribute) == TRUE)
{
do {
++(*current_entry_number);
// LongFileName이 다음 클러스터로 넘어갈 경우를 대비
if((*current_entry_number) >= entry_per_data_cluster)
{
(*has_long_file_name_next_entry) = TRUE;
return NULL;
}
current_long_file_name_entry = (struct mfs_LFN_entry *)&cluster[(*current_entry_number) * sizeof(struct mfs_LFN_entry)];
} while(current_long_file_name_entry->id != 0x40);
}
++(*current_entry_number);
// EntryNumber가 클러스터안의 한계 Entry 수치를 넘었을 경우
if((*current_entry_number) >= entry_per_data_cluster)
{
has_long_file_name_next_entry = FALSE;
return NULL;
}
current_dir_entry = (struct mfs_dirent *)&cluster[(*current_entry_number) * sizeof(struct mfs_dirent)];
return current_dir_entry;
}
/*
함수명 : write_fileDirectoryEntryInDirCluster
하는일 : 디렉토리 클러스터 안에 파일 디렉토리 엔트리를 찾는다.
디렉토리가 가지고 있는 모든 클러스터를 순환하여
파일 이름과 같은 엔트리를 찾는다.
인자 : fVolume : 루프백이미지/파일 볼륨의 포인터
nDirClusterNumber : 디렉토리 클러스터 번호
pFileName : 파일이름의 문자열 포인터
pSearchedDirEntry : 검색된 디렉토리 엔트리의 포인터
리턴 값 : BOOL
*/
BOOL alloc_new_entry(struct mfs_volume* volume, u128 dir_cluster_number,
ps16_t file_name, struct mfs_dirent* searched_dentry)
{
u8_t cluster[CLUSTER_SIZE] = {0, };
const u32_t entry_per_data_cluster = CLUSTER_SIZE / sizeof(struct mfs_dirent);
s16_t composited_file_name[128] = {0, };
BOOL has_long_file_name_next_entry = FALSE;
u128 read_position = 0;
u128 current_cluster_number = dir_cluster_number;
u32_t current_entry_number = 0;
struct mfs_dirent* current_dentry = NULL;
u128 end_cluster = get_end_cluster(volume);
// 디렉토리의 모든 클러스터를 검사한다.
while(current_cluster_number != end_cluster)
{
read_position = read_cluster(volume, current_cluster_number);
#ifdef __KERNEL__
seek_volume(volume, read_position);
#else
seek_volume(volume, read_position, SEEK_SET);
#endif
read_volume(volume, cluster, sizeof(u8_t), CLUSTER_SIZE);
current_dentry = get_first_entry(cluster, ¤t_entry_number, has_long_file_name_next_entry);
printf("alloc_new_entry current_cluster_number: %d\n", current_cluster_number);
while(current_entry_number != entry_per_data_cluster)
{
if(is_normal_file(current_dentry->attribute) == TRUE)
{
// 얻은 엔트리가 LongFileName인지 여부 검사
if(is_long_file_name(current_dentry->attribute) == TRUE)
{
// LongFileName일 경우 LongFileName을 조합한다.
composite_long_file_name(volume, current_cluster_number, current_entry_number, composited_file_name);
}
else
{
// 일반 FileName일 경우 복사
strcpy(composited_file_name, current_dentry->name);
}
// Name 비교
if(!strcmp(file_name, composited_file_name))
{
memcpy(current_dentry, searched_dentry, sizeof(struct mfs_dirent));
#ifdef __KERNEL__
seek_volume(volume, read_position);
#else
seek_volume(volume, read_position, SEEK_SET);
#endif
write_volume(volume, cluster, sizeof(u8_t), CLUSTER_SIZE);
printf("mfs inner dentry update\n");
return TRUE;
}
}
// 다음 엔트리를 얻는다.
current_dentry = get_next_entry(cluster, ¤t_entry_number, &has_long_file_name_next_entry);
}
current_cluster_number = read_fat_index(volume, current_cluster_number);
}
return FALSE;
}
/*
함수명 : getVolumeReadPos
하는일 : Volume에서 nClusterNum 즉 클러스터 번호의 실제 위치를 읽는다.
인자 : fVolume : 루프백 이미지/파일 볼륨의 포인터
nClusterNum : 클러스터 번호
리턴 값 : u32
*/
u128 read_cluster(struct mfs_volume* volume, u128 cluster_number)
{
struct mfs_sb_info sb;
read_sb(volume, &sb);
// Volume에서 읽을 위치를 계산한다. DataCluster Begin Address + 건내져온 클러스터 수치까지의 크기(nCurClusterNumber - 2는 Index 0,1은 쓰이지 않기 때문이다. 시작이 2부터이다.)
return ((sb.data_cluster_sector * sb.bytes_per_sector) + ((cluster_number - 2) * CLUSTER_SIZE));
}