about summary refs log tree commit diff
path: root/sternenblog/entry.h
blob: 66e76bb8d24eb422420cd1d7d664d84ed2c4746a (plain) (blame)
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
/*!
 * @file entry.h
 * @brief Construction and destruction of entries
 */

#ifndef STERNENBLOG_ENTRY_H
#define STERNENBLOG_ENTRY_H

#include "core.h"

/*!
 * @brief Construct an entry for a given `PATH_INFO`
 *
 * `make_entry()` first does a sanity check of the provided `path_info`:
 *
 * * It must start with a slash
 * * It may not contain any path segments which start with a dot
 *   (i. e. no dotfiles and no `.` and `..`)
 * * It may not contain any double slashes
 *
 * `make_entry()` currently has no support for any kind of escaped `PATH_INFO`.
 * This might need some work in the future, but seems unnecessary at the moment
 * RFC3875 doesn't specify any escaping mechanism for `PATH_INFO` and leaves it
 * to the webserver to deal with cases like `foo%2dbar` which is indistinguishable
 * from `foo/bar` in its decoded form.
 *
 * Note that accessing subdirectories is possible and allowed, i. e. a `path_info` of
 * `"/foo/bar"` will result in an entry being constructed for `<blog_dir>/foo/bar`.
 * This behavior is sometimes useful (entries in subdirectories are not included in
 * any indices), but may also be confusing. In the future an option to disable this
 * may be added.
 *
 * Before constructing the entry, `make_entry()` calls `stat()` to check if the given
 * entry a) exists b) is a regular file and c) is owned by the current processes user
 * or group. The last check ensures that the file is not only readable for the webserver,
 * but also owned by either its group or its user. This lessens the likelyhood of
 * something accidentially being processed by `make_entry()`, since usually a
 * `chown http:http` or similar will be necessary to satisfy the check.
 *
 * After that the `entry` structure is populated:
 *
 * * `path` is set to the constructed path to the entry file (dynamically allocated)
 * * `title` is set to `path_info` with the leading slash removed (dynamically allocated)
 * * `time` is set to the file's modification time
 * * `link` is set to `script_name` and `path_info` concatenated which is the absolute web
 *   server path corresponding to the entry
 * * `text_size` is set to `-1`
 * * `text` is set to `NULL`
 *
 * `make_entry()` may fail at any point with parts of the struct already containing
 * pointers to dynamically allocated memory. It is always safe to call `free_entry()`
 * after calling `make_entry()`, so you should make sure to do just that in case of
 * both error and success.
 *
 * @param blog_dir Directory blog entries are stored in, usually `BLOG_DIR`
 * @param path_info `PATH_INFO` CGI environment variable
 * @param script_name `SCRIPT_NAME` CGI environment variable
 * @param entry Uninitialized entry structure to update
 *
 * @return 200 on success, an appropriate HTTP status code on error
 *
 * @see struct entry
 * @see entry_get_text
 * @see free_entry
 * @see make_index
 */
int make_entry(const char *blog_dir, char *script_name, char *path_info, struct entry *entry);

/*!
 * @brief Populate an `entry`'s `text` field
 *
 * Reads the contents of `entry->path` into memory using `mmap()` and sets
 * `entry->text` and `entry->text_size` accordingly.
 *
 * Must be called on an already completely constructed entry.
 *
 * @return 0 on success, -1 on error, currently errno is not set correctly
 *
 * @see entry_unget_text
 * @see make_entry
 * @see free_entry
 */
int entry_get_text(struct entry *entry);

/*!
 * @brief Unmap the file referenced in a `struct entry`
 *
 * Tries to `munmap()` the file pointed to by `entry->text`
 * if present, and updates `entry->text_size` accordingly.
 *
 * The rest of the struct is left untouched.
 *
 * @see free_entry
 */
void entry_unget_text(struct entry *entry);

/*!
 * @brief Free dynamically allocated parts on an `entry`
 *
 * Frees any non `NULL` pointers in the given `entry` structure.
 * `make_entry()` initializes all pointers as `NULL` first thing
 * after being called, so you can always call `free_entry()` after
 * `make_entry()`.
 *
 * It also unmaps the mapped file in `text` if it is not `NULL`
 * using `entry_unget_text()`.
 *
 * Warning: It won't call `free()` on the entire entry structure.
 *
 * @see entry_unget_text
 */
void free_entry(struct entry *entry);

#endif