forked from embox/embox
-
Notifications
You must be signed in to change notification settings - Fork 0
/
open.c
137 lines (112 loc) · 2.57 KB
/
open.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
/**
* @file
* @brief
*
* @author Anton Kozlov
* @date 04.10.2012
*/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <libgen.h>
#include <util/array.h>
#include <fs/vfs.h>
#include <fs/kfile.h>
#include <kernel/task/idesc_table.h>
#include <kernel/task/resource/idesc_table.h>
#include <dirent_impl.h>
#include "getumask.h"
struct node *find_node(DIR *dir, char * node_name) {
struct dirent * dent;
while (NULL != (dent = readdir(dir))) {
if (0 == strcmp(dent->d_name, node_name)) {
return (struct node *)dent->d_ino;
}
}
return NULL;
}
extern int kcreat(struct path *dir, const char *path, mode_t mode, struct path *child);
int open(const char *path, int __oflag, ...) {
char path_buf[PATH_MAX];
char name[NAME_MAX];
struct file_desc *kfile;
va_list args;
mode_t mode;
int rc;
char *parent_path;
char *bname;
DIR *dir;
struct node *node;
struct path node_path;
struct idesc_table*it;
assert(~__oflag & O_DIRECTORY);
if (strlen(path) >= PATH_MAX) {
return SET_ERRNO(ENAMETOOLONG);
}
va_start(args, __oflag);
mode = va_arg(args, mode_t);
mode = umask_modify(mode);
va_end(args);
strncpy(path_buf, path, PATH_MAX);
bname = basename(path_buf);
if (strlen(bname) >= NAME_MAX)
return SET_ERRNO(ENAMETOOLONG);
strncpy(name, bname, NAME_MAX);
if (0 == strcmp(name, "/")) {
return SET_ERRNO(EISDIR);
}
parent_path = dirname(strcpy(path_buf, path));
if (NULL == (dir = opendir(parent_path))) {
return SET_ERRNO(errno);
}
node = find_node(dir, name);
node_path.node = node;
if_mounted_follow_down(&dir->path);
node_path.mnt_desc = dir->path.mnt_desc;
if (node == NULL) {
if (__oflag & O_CREAT) {
if(0 > kcreat(&dir->path, name, mode, &node_path)) {
rc = -errno;
goto out;
}
} else {
rc = -ENOENT;
goto out;
}
} else {
/* When used with O_CREAT, if the file already exists it is an error
* and the open() will fail. */
if (__oflag & O_EXCL && __oflag & O_CREAT) {
rc = -EEXIST;
goto out;
}
if (node_is_directory(node)) {
rc = -EISDIR;
goto out;
}
else if (path[strlen(path) - 1] == '/') {
rc = -ENOTDIR;
goto out;
}
if (__oflag & O_TRUNC) {
if (-1 == ktruncate(node, 0)){
//errno already setup
return -1;
}
}
}
__oflag &= ~(O_CREAT | O_EXCL);
kfile = kopen(node_path.node, __oflag);
if (NULL == kfile) {
rc = -errno;
goto out;
}
it = task_resource_idesc_table(task_self());
rc = idesc_table_add(it, (struct idesc *)kfile, 0);
out:
closedir(dir);
return rc >= 0 ? rc : SET_ERRNO(-rc);
}