Skip to content
This repository was archived by the owner on Feb 8, 2021. It is now read-only.

Commit 686708b

Browse files
authored
Merge pull request #274 from bergwolf/symlink_mkdir
Symlink mkdir for file volume path
2 parents b4d4741 + fa120fe commit 686708b

File tree

3 files changed

+96
-104
lines changed

3 files changed

+96
-104
lines changed

src/container.c

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ static int container_setup_volume(struct hyper_container *container)
102102
for (i = 0; i < container->vols_num; i++) {
103103
char volume[512];
104104
char mountpoint[512];
105-
char *expath;
106105
char *options = NULL;
107106
const char *filevolume = NULL;
108107
vol = &container->vols[i];
@@ -145,14 +144,9 @@ static int container_setup_volume(struct hyper_container *container)
145144
return -1;
146145

147146
if (filevolume == NULL) {
148-
expath = hyper_mkdir_at(".", mountpoint, 0755);
149-
if (expath == NULL) {
150-
perror("create volume dir failed");
147+
if (hyper_mkdir_at(".", mountpoint, sizeof(mountpoint)) < 0) {
148+
perror("create map dir failed");
151149
return -1;
152-
} else {
153-
/* ensure mountpoint is reachable */
154-
sprintf(mountpoint, "%s", expath);
155-
free(expath);
156150
}
157151
if (vol->docker) {
158152
if (container->initialize &&
@@ -166,8 +160,7 @@ static int container_setup_volume(struct hyper_container *container)
166160
return -1;
167161
}
168162
} else {
169-
hyper_filize(mountpoint);
170-
if (hyper_create_file(mountpoint) < 0) {
163+
if (hyper_create_file_at(".", mountpoint, sizeof(mountpoint)) < 0) {
171164
perror("create volume file failed");
172165
return -1;
173166
}
@@ -195,7 +188,7 @@ static int container_setup_volume(struct hyper_container *container)
195188

196189
for (i = 0; i < container->maps_num; i++) {
197190
struct stat st;
198-
char *src, *expath, path[512], volume[512];
191+
char *src, path[512], volume[512];
199192
struct fsmap *map = &container->maps[i];
200193
char mountpoint[512];
201194

@@ -207,14 +200,9 @@ static int container_setup_volume(struct hyper_container *container)
207200
stat(src, &st);
208201

209202
if (st.st_mode & S_IFDIR) {
210-
expath = hyper_mkdir_at(".", mountpoint, 0755);
211-
if (expath == NULL) {
203+
if (hyper_mkdir_at(".", mountpoint, sizeof(mountpoint)) < 0) {
212204
perror("create map dir failed");
213205
return -1;
214-
} else {
215-
/* ensure mountpoint is reachable */
216-
sprintf(mountpoint, "%s", expath);
217-
free(expath);
218206
}
219207
if (map->docker) {
220208
/* converted from volume */
@@ -227,12 +215,10 @@ static int container_setup_volume(struct hyper_container *container)
227215
}
228216
}
229217
} else {
230-
int fd = open(mountpoint, O_CREAT|O_WRONLY, 0755);
231-
if (fd < 0) {
232-
perror("create map file failed");
218+
if (hyper_create_file_at(".", mountpoint, sizeof(mountpoint)) < 0) {
219+
perror("create volume file failed");
233220
return -1;
234221
}
235-
close(fd);
236222
}
237223

238224
if (mount(src, mountpoint, NULL, MS_BIND, NULL) < 0) {

src/util.c

Lines changed: 87 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -268,47 +268,6 @@ void hyper_filize(char *hyper_path)
268268
}
269269
}
270270

271-
static int hyper_create_parent_dir(const char *hyper_path)
272-
{
273-
char *p, *path = strdup(hyper_path);
274-
int ret = 0;
275-
276-
if (path == NULL)
277-
return -1;
278-
p = strrchr(path, '/');
279-
if (p != NULL && p != path) {
280-
*p = '\0';
281-
ret = hyper_mkdir(path, 0777);
282-
}
283-
free(path);
284-
285-
return ret;
286-
}
287-
288-
/* hyper_path must point to a file rather than a directory, e.g., having trailing '/' */
289-
int hyper_create_file(const char *hyper_path)
290-
{
291-
int fd;
292-
struct stat stbuf;
293-
294-
if (stat(hyper_path, &stbuf) >= 0) {
295-
if (S_ISREG(stbuf.st_mode))
296-
return 0;
297-
errno = S_ISDIR(stbuf.st_mode) ? EISDIR : EINVAL;
298-
return -1;
299-
}
300-
301-
if (hyper_create_parent_dir(hyper_path) < 0)
302-
return -1;
303-
304-
fd = open(hyper_path, O_CREAT|O_WRONLY, 0666);
305-
if (fd < 0)
306-
return -1;
307-
close(fd);
308-
fprintf(stdout, "created file %s\n", hyper_path);
309-
return 0;
310-
}
311-
312271
static char *hyper_resolve_link(char *path)
313272
{
314273
char buf[512];
@@ -333,19 +292,24 @@ static char *hyper_resolve_link(char *path)
333292
* as if we were in a chroot jail.
334293
*
335294
* @root: chroot jail path.
336-
* @parent: what's already created to the target directory.
337295
* @path: target directory. It is always relative to @root even if it starts with /.
338-
* @mode: directory mode.
296+
* @parent: what's already created to the target directory.
339297
* @link_max: max number of symlinks to follow.
340-
* @depth: number of components resolved.
298+
* @create_file: create last component of @path as a normal file
341299
*
342300
* Upon success, @parent is changed to point to resolved path name.
343301
*/
344-
static int hyper_mkdir_follow_link(char *root, char *parent, char *path,
345-
mode_t mode, int *link_max, int *depth)
302+
static int hyper_mkdir_follow_link(const char *root, const char *path, char *parent,
303+
int *link_max, bool create_file)
346304
{
347-
char *comp, *prev, *link, *dummy, *npath, *delim = "/";
305+
char *comp, *next, *prev, *last, *link, *dummy, *npath, *delim = "/";
348306
struct stat st;
307+
int fd;
308+
309+
if (strncmp(root, parent, strlen(root)) != 0) {
310+
errno = EINVAL;
311+
return -1;
312+
}
349313

350314
npath = strdup(path);
351315
if (npath == NULL)
@@ -356,30 +320,40 @@ static int hyper_mkdir_follow_link(char *root, char *parent, char *path,
356320
goto out;
357321

358322
do {
323+
last = comp;
324+
next = strtok_r(NULL, delim, &dummy);
325+
359326
if (!strcmp(comp, "."))
360327
continue;
361328

329+
if (!strcmp(comp, "..")) {
330+
/* *NOTE* this works iff:
331+
* 1. parent is initialized as root when entering for the first time.
332+
* 2. comp is never appended to parent with trailing '/'.
333+
* 3. comp is always appended to parent with *one* prefix '/'.
334+
*/
335+
char *p = strrchr(parent, '/');
336+
if (p == NULL) {
337+
/* no comp appended, do nothing */
338+
} else if (p - parent >= strlen(root)) {
339+
/* go back one level */
340+
*p = '\0';
341+
}
342+
/* no need to check parent directory */
343+
continue;
344+
}
345+
362346
if (strlen(parent) + strlen(comp) + 1 >= 512) {
363347
errno = ENAMETOOLONG;
364348
goto out;
365349
}
366350
prev = &parent[strlen(parent)];
367351
strcat(parent, "/");
368352
strcat(parent, comp);
369-
if (!strcmp(comp, "..")) {
370-
if (--(*depth) <= 0) {
371-
/* points to root */
372-
sprintf(parent, "%s", root);
373-
*depth = 0;
374-
}
375-
/* no need to check parent directory */
376-
continue;
377-
} else {
378-
(*depth)++;
379-
}
380353

381354
if (lstat(parent, &st) >= 0) {
382-
if (S_ISDIR(st.st_mode)) {
355+
if ((S_ISDIR(st.st_mode) && (next != NULL || !create_file)) ||
356+
(S_ISREG(st.st_mode) && next == NULL && create_file)) {
383357
continue;
384358
} else if (S_ISLNK(st.st_mode)) {
385359
if (--(*link_max) <= 0) {
@@ -391,12 +365,10 @@ static int hyper_mkdir_follow_link(char *root, char *parent, char *path,
391365
goto out;
392366
if (link[0] == '/') {
393367
sprintf(parent, "%s", root);
394-
*depth = 0;
395368
} else {
396369
*prev = '\0'; /* drop current comp */
397-
(*depth)--;
398370
}
399-
if (hyper_mkdir_follow_link(root, parent, link, mode, link_max, depth) < 0) {
371+
if (hyper_mkdir_follow_link(root, link, parent, link_max, next == NULL && create_file) < 0) {
400372
free(link);
401373
goto out;
402374
}
@@ -408,39 +380,73 @@ static int hyper_mkdir_follow_link(char *root, char *parent, char *path,
408380
}
409381
}
410382

411-
fprintf(stdout, "create directory %s\n", parent);
412-
if (mkdir(parent, mode) < 0 && errno != EEXIST) {
413-
perror("failed to create directory");
414-
goto out;
383+
if (next == NULL && create_file) {
384+
fprintf(stdout, "create file %s\n", parent);
385+
fd = open(parent, O_CREAT|O_WRONLY, 0666);
386+
if (fd < 0)
387+
goto out;
388+
close(fd);
389+
} else {
390+
fprintf(stdout, "create directory %s\n", parent);
391+
if (mkdir(parent, 0755) < 0 && errno != EEXIST) {
392+
perror("failed to create directory");
393+
goto out;
394+
}
415395
}
416-
} while((comp = strtok_r(NULL, delim, &dummy)) != NULL);
396+
} while((comp = next) != NULL);
417397

418-
/* reset errno to mark success */
419-
errno = 0;
398+
if (create_file && (!strcmp(last, ".") || !strcmp(last, "..")))
399+
errno = ENOTDIR;
400+
else
401+
/* reset errno to mark success */
402+
errno = 0;
420403
out:
421404
free(npath);
422-
printf("parent is %s errno %d\n", parent, errno);
423405
return errno ? -1 : 0;
424406
}
425407

408+
static int hyper_create_target_at(const char *root, char *hyper_path, int size, bool create_file)
409+
{
410+
char result[512];
411+
int max_link = 40;
412+
413+
sprintf(result, "%s", root);
414+
if (hyper_mkdir_follow_link(root, hyper_path, result, &max_link, create_file) < 0)
415+
return -1;
416+
417+
if (strlen(result) + 1 > size) {
418+
errno = ENAMETOOLONG;
419+
return -1;
420+
}
421+
sprintf(hyper_path, "%s", result);
422+
return 0;
423+
}
424+
426425
/*
427426
* hyper_mkdir_at() is similar to hyper_mkdir() with the exception that
428427
* when there are symlinks in the path components, it acts as if we created
429-
* directories in a chroot jail. @path is always considered relative to root
430-
* even if it starts with a leading stash ('/').
428+
* directories in a chroot jail. @hyper_path is always considered relative
429+
* to root even if it starts with a leading stash ('/').
431430
*
432-
* Upon success, return symlink expanded result.
431+
* Upon success, @hyper_path is modified to save resolved path in chroot jail.
433432
*/
434-
char *hyper_mkdir_at(char *root, char *path, mode_t mode)
433+
int hyper_mkdir_at(const char *root, char *hyper_path, int size)
435434
{
436-
char result[512];
437-
int depth = 0, max_link = 40;
438-
439-
sprintf(result, "%s", root);
440-
if (hyper_mkdir_follow_link(root, result, path, mode, &max_link, &depth) < 0)
441-
return NULL;
435+
return hyper_create_target_at(root, hyper_path, size, false);
436+
}
442437

443-
return strdup(result);
438+
/**
439+
* hyper_create_file_at - create a file in @root chroot jail.
440+
*
441+
* @root: chroot jail path.
442+
* @hyper_path: must point to a file rather than a directory, e.g., having trailing '/'
443+
* @size: size of @hyper_path storage.
444+
*
445+
* Upon success, @hyper_path is modified to point to the path resolved in chroot jail.
446+
*/
447+
int hyper_create_file_at(const char* root, char *hyper_path, int size)
448+
{
449+
return hyper_create_target_at(root, hyper_path, size, true);
444450
}
445451

446452
int hyper_mkdir(char *path, mode_t mode)

src/util.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ void hyper_sync_time_hctosys();
2626
void online_cpu(void);
2727
void online_memory(void);
2828
int hyper_cmd(char *cmd);
29-
int hyper_create_file(const char *hyper_path);
29+
int hyper_create_file_at(const char *root, char *hyper_path, int size);
3030
void hyper_filize(char *hyper_path);
3131
int hyper_mkdir(char *path, mode_t mode);
32-
char *hyper_mkdir_at(char *root, char *path, mode_t mode);
32+
int hyper_mkdir_at(const char *root, char *path, int size);
3333
int hyper_write_file(const char *path, const char *value, size_t len);
3434
int hyper_open_channel(char *channel, int mode);
3535
int hyper_setfd_cloexec(int fd);

0 commit comments

Comments
 (0)