forked from MelodiaDev/ftpfs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinode.c
133 lines (119 loc) · 4.29 KB
/
inode.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
#include "ftpfs.h"
#include "ftp.h"
#include "inode.h"
#include "super.h"
#include "file.h"
#include <linux/mount.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
#define d_alias d_u.d_alias
#endif
const struct inode_operations ftp_fs_file_inode_operations = {
.setattr = simple_setattr,
.getattr = simple_getattr,
};
const struct inode_operations ftp_fs_dir_inode_operations = {
.create = ftp_fs_create,
.lookup = ftp_fs_lookup,
.mknod = ftp_fs_mknod,
.link = simple_link,
.unlink = simple_unlink,
};
struct inode* ftp_fs_get_inode(struct super_block *sb, const struct inode* dir, umode_t mode, dev_t dev) {
/* allocate a inode */
struct inode* inode = new_inode(sb);
if (inode) {
inode->i_ino = get_next_ino();
/* initialize the owener */
inode_init_owner(inode, dir, mode);
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
case S_IFREG:
pr_debug("got a regular inode\n");
/* the operations of this inode as the file operations */
inode->i_op = &ftp_fs_file_inode_operations;
inode->i_fop = &ftp_fs_file_operations;
break;
case S_IFDIR:
pr_debug("got a dir inode\n");
/* the operations of this inode as the dir operations */
inode->i_op = &ftp_fs_dir_inode_operations;
inode->i_fop = &ftp_fs_dir_operations;
break;
default:
pr_debug("got a special inode\n");
init_special_inode(inode, mode, dev);
break;
}
}
return inode;
}
int ftp_fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) {
return ftp_fs_mknod(dir, dentry, mode | S_IFREG, 0);
}
int ftp_fs_mknod(struct inode* dir, struct dentry* dentry, umode_t mode, dev_t dev) {
/* get the inode */
struct inode* inode = ftp_fs_get_inode(dir->i_sb, dir, mode, dev);
int error = -ENOSPC;
if (inode) {
/* instantiate the dentry with this inode */
d_instantiate(dentry, inode);
dget(dentry);
error = 0;
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
}
return error;
}
struct dentry* ftp_fs_lookup(struct inode* inode, struct dentry* dentry, unsigned int flags) {
struct inode *target = NULL;
struct dentry *d;
char *filename;
char *filebuf;
char *file_path;
int result = -1;
unsigned long file_num;
struct ftp_file_info *files;
int i;
pr_debug("process lookup %s\n", dentry->d_name.name);
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
if (!dentry->d_sb->s_d_op)
d_set_d_op(dentry, &simple_dentry_operations);
/* got the full path from inode */
d = list_entry(inode->i_dentry.first, struct dentry, d_alias);
filename = (char*) dentry->d_name.name;
filebuf = (char*) kmalloc(MAX_PATH_LEN, GFP_KERNEL);
if (filebuf == NULL) {
pr_debug("allocate filebuf failed\n");
goto out;
}
file_path = dentry_path_raw(d, filebuf, MAX_PATH_LEN);
if (file_path == NULL) {
pr_debug("calculate file path failed\n");
goto error;
}
pr_debug("@lookup full path name %s\n", filename);
/* fetch the dir content from the server and the look up the file in the content. If it exists, then allocate a dentry cache for it
* if not, the target is set as NULL and d_add it */
if ((result = ftp_read_dir((struct ftp_info*) inode->i_sb->s_fs_info, file_path, &file_num, &files)) == 0) {
pr_debug("got %lu file\n", file_num);
for (i = 2; i < file_num; i++) if (strcmp(filename, files[i].name) == 0) {
pr_debug("got this file\n");
if ((target = ftp_fs_get_inode(inode->i_sb, inode, files[i].mode, 0)) == NULL) {
pr_debug("can not allocate a inode\n");
goto error;
}
/* missing m_time (need format converting) */
if (target) target->i_size = files[i].size;
pr_debug("new inode done\n");
break;
}
}
error:
if (filebuf) kfree(filebuf);
pr_debug("freed filebuf\n");
out:
d_add(dentry, target);
pr_debug("add dentry\n");
return NULL;
}