-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathatfile.c
265 lines (238 loc) · 8.21 KB
/
atfile.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
#define EXTUNIX_WANT_ATFILE
#include "config.h"
#if defined(EXTUNIX_HAVE_ATFILE)
/* otherlibs/unix/cst2constr.h */
#if OCAML_VERSION_MAJOR >= 5
# if OCAML_VERSION_MAJOR >= 2
extern value caml_unix_cst_to_constr(int n, const int * tbl, int size, int deflt);
# else
extern value caml_unix_cst_to_constr(int n, int * tbl, int size, int deflt);
# endif
#else
extern value cst_to_constr(int n, int * tbl, int size, int deflt);
#define caml_unix_cst_to_constr cst_to_constr
#endif
static const int file_kind_table[] = {
S_IFREG, S_IFDIR, S_IFCHR, S_IFBLK, S_IFLNK, S_IFIFO, S_IFSOCK
};
#ifndef AT_EACCESS
#define AT_EACCESS 0
#endif
#ifndef AT_SYMLINK_NOFOLLOW
#define AT_SYMLINK_NOFOLLOW 0
#endif
#ifndef AT_SYMLINK_FOLLOW
#define AT_SYMLINK_FOLLOW 0
#endif
#ifndef AT_NO_AUTOMOUNT
#define AT_NO_AUTOMOUNT 0
#endif
static const int at_flags_table[] = {
AT_EACCESS, AT_SYMLINK_NOFOLLOW, AT_REMOVEDIR, AT_SYMLINK_FOLLOW, AT_NO_AUTOMOUNT,
};
static value stat_aux(/*int use_64,*/ struct stat *buf)
{
CAMLparam0();
CAMLlocal5(atime, mtime, ctime, offset, v);
atime = caml_copy_double((double) buf->st_atime);
mtime = caml_copy_double((double) buf->st_mtime);
ctime = caml_copy_double((double) buf->st_ctime);
offset = /*use_64 ? Val_file_offset(buf->st_size) :*/ Val_int (buf->st_size);
v = caml_alloc_small(12, 0);
Field (v, 0) = Val_int (buf->st_dev);
Field (v, 1) = Val_int (buf->st_ino);
Field (v, 2) =
caml_unix_cst_to_constr(buf->st_mode & S_IFMT, file_kind_table,
sizeof(file_kind_table) / sizeof(int), 0);
Field (v, 3) = Val_int (buf->st_mode & 07777);
Field (v, 4) = Val_int (buf->st_nlink);
Field (v, 5) = Val_int (buf->st_uid);
Field (v, 6) = Val_int (buf->st_gid);
Field (v, 7) = Val_int (buf->st_rdev);
Field (v, 8) = offset;
Field (v, 9) = atime;
Field (v, 10) = mtime;
Field (v, 11) = ctime;
CAMLreturn(v);
}
CAMLprim value caml_extunix_fstatat(value v_dirfd, value v_name, value v_flags)
{
CAMLparam3(v_dirfd, v_name, v_flags);
int ret;
int dirfd = Int_val(v_dirfd);
struct stat buf;
char* p = caml_stat_strdup(String_val(v_name));
int flags = caml_convert_flag_list(v_flags, at_flags_table);
flags &= (AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT); /* only allowed flags here */
caml_enter_blocking_section();
ret = fstatat(dirfd, p, &buf, flags);
caml_leave_blocking_section();
caml_stat_free(p);
if (ret != 0) uerror("fstatat", v_name);
if (buf.st_size > Max_long && (buf.st_mode & S_IFMT) == S_IFREG)
unix_error(EOVERFLOW, "fstatat", v_name);
CAMLreturn(stat_aux(/*0,*/ &buf));
}
CAMLprim value caml_extunix_unlinkat(value v_dirfd, value v_name, value v_flags)
{
CAMLparam3(v_dirfd, v_name, v_flags);
int dirfd = Int_val(dirfd);
char* p = caml_stat_strdup(String_val(v_name));
int ret = 0;
int flags = caml_convert_flag_list(v_flags, at_flags_table);
flags &= AT_REMOVEDIR; /* only allowed flag here */
caml_enter_blocking_section();
ret = unlinkat(dirfd, p, flags);
caml_leave_blocking_section();
caml_stat_free(p);
if (ret != 0) uerror("unlinkat", v_name);
CAMLreturn(Val_unit);
}
CAMLprim value caml_extunix_renameat(value v_oldfd, value v_oldname, value v_newfd, value v_newname)
{
CAMLparam4(v_oldfd, v_oldname, v_newfd, v_newname);
int oldfd = Int_val(v_oldfd), newfd = Int_val(newfd);
char *oldname = caml_stat_strdup(String_val(v_oldname)),
*newname = caml_stat_strdup(String_val(v_newname));
caml_enter_blocking_section();
int ret = renameat(oldfd, oldname, newfd, newname);
caml_leave_blocking_section();
caml_stat_free(newname);
caml_stat_free(oldname);
if (ret != 0) uerror("renameat", v_oldname);
CAMLreturn(Val_unit);
}
CAMLprim value caml_extunix_mkdirat(value v_dirfd, value v_name, value v_mode)
{
CAMLparam3(v_dirfd, v_name, v_mode);
int dirfd = Int_val(v_dirfd), mode = Int_val(v_mode);
char *name = caml_stat_strdup(String_val(v_name));
caml_enter_blocking_section();
int ret = mkdirat(dirfd, name, mode);
caml_leave_blocking_section();
caml_stat_free(name);
if (ret != 0) uerror("mkdirat", v_name);
CAMLreturn(Val_unit);
}
CAMLprim value caml_extunix_linkat(value v_olddirfd, value v_oldname, value v_newdirfd, value v_newname, value v_flags)
{
CAMLparam5(v_olddirfd, v_oldname, v_newdirfd, v_newname, v_flags);
int olddirfd = Int_val(v_olddirfd), newdirfd = Int_val(v_newdirfd);
char *oldname = caml_stat_strdup(String_val(v_oldname)),
*newname = caml_stat_strdup(String_val(v_newname));
int ret = 0;
int flags = caml_convert_flag_list(v_flags, at_flags_table);
flags &= AT_SYMLINK_FOLLOW; /* only allowed flag here */
caml_enter_blocking_section();
ret = linkat(olddirfd, oldname, newdirfd, newname, flags);
caml_leave_blocking_section();
caml_stat_free(newname);
caml_stat_free(oldname);
if (ret != 0) uerror("linkat", v_oldname);
CAMLreturn(Val_unit);
}
CAMLprim value caml_extunix_fchownat(value v_dirfd, value v_name, value v_owner, value v_group, value v_flags)
{
CAMLparam5(v_dirfd, v_name, v_owner, v_group, v_flags);
int dirfd = Int_val(v_dirfd), owner = Int_val(v_owner), group = Int_val(v_group);
char *name = caml_stat_strdup(String_val(v_name));
int ret = 0;
int flags = caml_convert_flag_list(v_flags, at_flags_table);
flags &= (AT_SYMLINK_NOFOLLOW /* | AT_EMPTY_PATH */); /* only allowed flag here */
caml_enter_blocking_section();
ret = fchownat(dirfd, name, owner, group, flags);
caml_leave_blocking_section();
caml_stat_free(name);
if (ret != 0) uerror("fchownat", v_name);
CAMLreturn(Val_unit);
}
CAMLprim value caml_extunix_fchmodat(value v_dirfd, value v_name, value v_mode, value v_flags)
{
CAMLparam4(v_dirfd, v_name, v_mode, v_flags);
int dirfd = Int_val(v_dirfd), mode = Int_val(v_mode);
char *name = caml_stat_strdup(String_val(v_name));
int ret = 0;
int flags = caml_convert_flag_list(v_flags, at_flags_table);
flags &= AT_SYMLINK_NOFOLLOW; /* only allowed flag here */
caml_enter_blocking_section();
ret = fchmodat(dirfd, name, mode, flags);
caml_leave_blocking_section();
caml_stat_free(name);
if (ret != 0) uerror("fchmodat", v_name);
CAMLreturn(Val_unit);
}
CAMLprim value caml_extunix_symlinkat(value v_path, value v_newdirfd, value v_newname)
{
CAMLparam3(v_path, v_newdirfd, v_newname);
char *path = caml_stat_strdup(String_val(v_path)),
*newname = caml_stat_strdup(String_val(v_newname));
int newdirfd = Int_val(v_newdirfd);
caml_enter_blocking_section();
int ret = symlinkat(path, newdirfd, newname);
caml_leave_blocking_section();
caml_stat_free(newname);
caml_stat_free(path);
if (ret != 0) uerror("symlinkat", v_path);
CAMLreturn(Val_unit);
}
CAMLprim value caml_extunix_openat(value v_dirfd, value v_path, value flags, value v_perm)
{
CAMLparam4(v_dirfd, v_path, flags, v_perm);
int dirfd = Int_val(v_dirfd), perm = Int_val(v_perm);
int ret, cv_flags;
char *path = caml_stat_strdup(String_val(v_path));;
cv_flags = extunix_open_flags(flags);
/* open on a named FIFO can block (PR#1533) */
caml_enter_blocking_section();
ret = openat(dirfd, path, cv_flags, perm);
caml_leave_blocking_section();
caml_stat_free(path);
if (ret == -1) uerror("openat", v_path);
CAMLreturn (Val_int(ret));
}
char *readlinkat_malloc (int dirfd, const char *filename)
{
int size = 100;
int nchars;
char *buffer = NULL;
char *tmp;
while (1)
{
tmp = caml_stat_resize_noexc (buffer, size);
if (tmp == NULL)
{
caml_stat_free (buffer); /* if failed, dealloc is not performed */
return NULL;
}
buffer = tmp;
nchars = readlinkat (dirfd, filename, buffer, size);
if (nchars < 0)
{
caml_stat_free (buffer);
return NULL;
}
if (nchars < size)
{
buffer[nchars] = '\0';
return buffer;
}
size *= 2;
}
}
CAMLprim value caml_extunix_readlinkat(value v_dirfd, value v_name)
{
CAMLparam2(v_dirfd, v_name);
CAMLlocal1(v_link);
int dirfd = Int_val(v_dirfd);
char* res;
char* name = caml_stat_strdup(String_val(v_name));
caml_enter_blocking_section();
res = readlinkat_malloc(dirfd, name);
caml_leave_blocking_section();
caml_stat_free(name);
if (res == NULL) uerror("readlinkat", v_name);
v_link = caml_copy_string(res);
caml_stat_free(res);
CAMLreturn(v_link);
}
#endif