-
Notifications
You must be signed in to change notification settings - Fork 3
/
ext2_ln.c
138 lines (116 loc) · 3.85 KB
/
ext2_ln.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
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>
#include "ext2.h"
#include "utilities.h"
unsigned char *disk;
struct ext2_inode *inodeTable;
int main(int argc, char **argv) {
char pathTo[EXT2_NAME_LEN];
char pathFrom[EXT2_NAME_LEN];
char pathToCopy[EXT2_NAME_LEN];
char pathFromCopy[EXT2_NAME_LEN];
char parentOfPathFrom[EXT2_NAME_LEN];
char linkName[EXT2_NAME_LEN];
int flagged = FALSE;
int inodeNum, parentInodeNum, childInodeNum;
struct ext2_inode *targetInode, *parentInode, *childInode;
if(argc!=4 && argc!=5) {
fprintf(stderr, "Usage: ext2_ln <image file name> <optional flag -s> <absolute path> <absolute path>\n");
exit(1);
}
// read disk and get inode table
int fd = open(argv[1], O_RDWR);
disk = mmap(NULL, 128 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(disk == MAP_FAILED) {
perror("mmap");
exit(1);
}
inodeTable = getInodeTable();
// read other arguments
if(argc == 4) {
strcpy(pathTo, argv[2]);
strcpy(pathFrom, argv[3]);
} else {
if (strcmp(argv[2], "-s") != 0) {
fprintf(stderr, "Invalid Flag\n");
exit(1);
}
flagged = TRUE;
strcpy(pathTo, argv[3]);
strcpy(pathFrom, argv[4]);
}
// get the inode from pathTo
strcpy(pathToCopy, pathTo);
if (pathToCopy[0]!='/') {
perror("Invalid path argument");
fprintf(stderr, "No such file or directory\n");
return ENOENT;
} else {
inodeNum = getInodeFromPath(pathToCopy);
}
if (inodeNum == 0) {
fprintf(stderr, "No such file or directory\n");
return ENOENT;
}
targetInode = &inodeTable[inodeNum-1];
if (targetInode->i_mode & EXT2_S_IFDIR){
fprintf(stderr, "No link to a directory\n");
return EISDIR;
}
// get the upper level inode from pathFrom
strcpy(pathFromCopy, pathFrom);
strcpy(parentOfPathFrom, pathFrom);
if (parentOfPathFrom[0]!='/') {
perror("Invalid parentDirPath");
fprintf(stderr, "No such file or directory\n");
return ENOENT;
} else if (parentOfPathFrom[1]=='\0'){
fprintf(stderr, "No link from a directory\n");
return EISDIR;
} else {
getParentDirPath(parentOfPathFrom);
}
parentInodeNum = getInodeFromPath(parentOfPathFrom);
if (parentInodeNum == 0) {
perror("parentDirPath not exist");
fprintf(stderr, "No such file or directory\n");
return ENOENT;
}
parentInode = &inodeTable[parentInodeNum-1];
// check whether the link has already existed
getFileNameFromPath(linkName, pathFromCopy);
childInodeNum = searchFileInDir(parentInode, linkName);
if (childInodeNum != 0) {
fprintf(stderr, "File or directory already exist\n");
return EEXIST;
}
if (!flagged){
// implementation for the hard link
initNewDirent(parentInode, inodeNum, EXT2_FT_REG_FILE, linkName);
// increment the link count of the target inode
targetInode->i_links_count++;
}else{
// implementation for the symbolic link
childInodeNum = initInode(EXT2_S_IFLNK);
childInode = &inodeTable[childInodeNum-1];
childInode->i_size = strlen(pathFromCopy);
childInode->i_blocks = 0;
initNewDirent(parentInode, childInodeNum, EXT2_FT_SYMLINK, linkName);
if (childInode->i_size <= 60){
strncpy((char *)childInode->i_block, pathTo, 60);
}else{
// append path to the inode block
int block_num = allocateNewBlock();
strcpy((char *)getBlock(block_num), pathTo);
childInode->i_block[0] = block_num;
}
}
return 0;
}