1 /*-*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 /* Monkey HTTP Server
4 * ==================
5 * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #define _GNU_SOURCE
21
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <errno.h>
28
29 #include "mk_core.h"
30
31 #ifdef _WIN32
32 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
33 #define S_ISLNK(m) (0)
34 #define O_NONBLOCK (0)
35 #define lstat stat
36 #endif
37
mk_file_get_info(const char * path,struct file_info * f_info,int mode)38 int mk_file_get_info(const char *path, struct file_info *f_info, int mode)
39 {
40 struct stat f, target;
41
42 f_info->exists = MK_FALSE;
43
44 /* Stat right resource */
45 if (lstat(path, &f) == -1) {
46 if (errno == EACCES) {
47 f_info->exists = MK_TRUE;
48 }
49 return -1;
50 }
51
52 f_info->exists = MK_TRUE;
53 f_info->is_file = MK_TRUE;
54 f_info->is_link = MK_FALSE;
55 f_info->is_directory = MK_FALSE;
56 f_info->exec_access = MK_FALSE;
57 f_info->read_access = MK_FALSE;
58
59 if (S_ISLNK(f.st_mode)) {
60 f_info->is_link = MK_TRUE;
61 f_info->is_file = MK_FALSE;
62 if (stat(path, &target) == -1) {
63 return -1;
64 }
65 }
66 else {
67 target = f;
68 }
69
70 f_info->size = target.st_size;
71 f_info->last_modification = target.st_mtime;
72
73 if (S_ISDIR(target.st_mode)) {
74 f_info->is_directory = MK_TRUE;
75 f_info->is_file = MK_FALSE;
76 }
77
78 #ifndef _WIN32
79 gid_t EGID = getegid();
80 gid_t EUID = geteuid();
81
82 /* Check read access */
83 if (mode & MK_FILE_READ) {
84 if (((target.st_mode & S_IRUSR) && target.st_uid == EUID) ||
85 ((target.st_mode & S_IRGRP) && target.st_gid == EGID) ||
86 (target.st_mode & S_IROTH)) {
87 f_info->read_access = MK_TRUE;
88 }
89 }
90
91 /* Checking execution */
92 if (mode & MK_FILE_EXEC) {
93 if ((target.st_mode & S_IXUSR && target.st_uid == EUID) ||
94 (target.st_mode & S_IXGRP && target.st_gid == EGID) ||
95 (target.st_mode & S_IXOTH)) {
96 f_info->exec_access = MK_TRUE;
97 }
98 }
99 #endif
100
101 /* Suggest open(2) flags */
102 f_info->flags_read_only = O_RDONLY | O_NONBLOCK;
103
104 #if defined(__linux__)
105 /*
106 * If the user is the owner of the file or the user is root, it
107 * can set the O_NOATIME flag for open(2) operations to avoid
108 * inode updates about last accessed time
109 */
110 if (target.st_uid == EUID || EUID == 0) {
111 f_info->flags_read_only |= O_NOATIME;
112 }
113 #endif
114
115 return 0;
116 }
117
118 /* Read file content to a memory buffer,
119 * Use this function just for really SMALL files
120 */
mk_file_to_buffer(const char * path)121 char *mk_file_to_buffer(const char *path)
122 {
123 FILE *fp;
124 char *buffer;
125 long bytes;
126 struct file_info finfo;
127
128 if (mk_file_get_info(path, &finfo, MK_FILE_READ) != 0) {
129 return NULL;
130 }
131
132 if (!(fp = fopen(path, "rb"))) {
133 return NULL;
134 }
135
136 buffer = mk_mem_alloc_z(finfo.size + 1);
137 if (!buffer) {
138 fclose(fp);
139 return NULL;
140 }
141
142 bytes = fread(buffer, finfo.size, 1, fp);
143
144 if (bytes < 1) {
145 mk_mem_free(buffer);
146 fclose(fp);
147 return NULL;
148 }
149
150 fclose(fp);
151 return (char *) buffer;
152
153 }
154