src/server/webdav/operation.c

branch
webdav
changeset 221
ff5826fc6a6c
parent 220
2915b6c11aec
child 222
5f05e56cb8e2
equal deleted inserted replaced
220:2915b6c11aec 221:ff5826fc6a6c
54 return op; 54 return op;
55 } 55 }
56 56
57 int webdav_op_propfind_begin( 57 int webdav_op_propfind_begin(
58 WebdavOperation *op, 58 WebdavOperation *op,
59 const char *path, 59 const char *href,
60 VFS_DIR parent, 60 VFS_DIR parent,
61 struct stat *s) 61 struct stat *s)
62 { 62 {
63 // create WebdavResource object for requested resource 63 // create WebdavResource object for requested resource
64 WebdavResource *resource = op->response->addresource(op->response, path); 64 WebdavResource *resource = op->response->addresource(op->response, href);
65 if(!resource) { 65 if(!resource) {
66 return REQ_ABORTED; 66 return REQ_ABORTED;
67 } 67 }
68 68
69 // store data that we need when the resource will be closed 69 // store data that we need when the resource will be closed
87 } 87 }
88 88
89 return ret; 89 return ret;
90 } 90 }
91 91
92 typedef struct PathSearchElm {
93 char *href;
94 char *path;
95 size_t hreflen;
96 size_t pathlen;
97 } PathSearchElm;
98
99 /*
100 * concats base + / + elm
101 * if baseinit is true, only elm is copied
102 */
103 static int path_buf_concat(
104 pool_handle_t *pool,
105 char **buf,
106 size_t * restrict len,
107 WSBool * restrict baseinit,
108 const char *base,
109 size_t baselen,
110 const char *elm,
111 size_t elmlen)
112 {
113 if(base[baselen-1] == '/') {
114 baselen--;
115 }
116
117 size_t newlen = baselen + elmlen + 1;
118 if(newlen > WEBDAV_PATH_MAX) {
119 log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded");
120 return 1;
121 }
122
123 // check if new path + terminator fits in the buffer
124 if(newlen + 1 > *len) {
125 *len = newlen + 128;
126 char *newbuf = pool_realloc(pool, *buf, newlen);
127 if(newbuf) {
128 log_ereport(LOG_FAILURE, "webdav: path memory allocation failed");
129 return 1;
130 }
131 *baseinit = FALSE;
132
133 *buf = newbuf;
134 }
135
136 // if baseinit is true, the parent is already in the buffer
137 // and we don't need to memcpy it again
138 if(!(*baseinit)) {
139 memcpy(*buf, base, baselen);
140 (*buf)[baselen] = '/';
141 *baseinit = TRUE;
142 }
143 // copy child and terminate string
144 memcpy((*buf) + baselen + 1, elm, elmlen);
145 (*buf)[newlen] = '\0';
146
147 return 0;
148 }
149
92 int webdav_op_propfind_children( 150 int webdav_op_propfind_children(
93 WebdavOperation *op, 151 WebdavOperation *op,
94 VFSContext *vfs, 152 VFSContext *vfs,
95 char *path) 153 const char *href,
154 const char *path)
96 { 155 {
97 WebdavPropfindRequest *request = op->requests->data; 156 WebdavPropfindRequest *request = op->requests->data;
98 157
99 UcxAllocator *a = session_get_allocator(request->sn); 158 UcxAllocator *a = session_get_allocator(request->sn);
100 pool_handle_t *pool = request->sn->pool; 159 pool_handle_t *pool = request->sn->pool;
101 UcxList *stack = ucx_list_prepend_a(a, NULL, path); 160
161 PathSearchElm *start_elm = pool_malloc(pool, sizeof(PathSearchElm));
162 start_elm->href = pool_strdup(pool, href);
163 start_elm->path = pool_strdup(pool, path);
164 start_elm->hreflen = strlen(href);
165 start_elm->pathlen = strlen(path);
166
167 UcxList *stack = ucx_list_prepend_a(a, NULL, start_elm);
102 UcxList *stack_end = stack; 168 UcxList *stack_end = stack;
103 if(!stack) { 169 if(!stack) {
104 return 1; 170 return 1;
105 } 171 }
106 172
107 // reusable buffer for full child path 173 // reusable buffer for full child path and href
108 char *newpath = NULL; 174 char *newpath = pool_malloc(pool, 256);
109 size_t newpathlen = 0; 175 size_t newpathlen = 256;
176
177 char *newhref = pool_malloc(pool, 256);
178 size_t newhreflen = 256;
110 179
111 int err = 0; 180 int err = 0;
112 while(stack && !err) { 181 while(stack && !err) {
113 char *cur_path = stack->data; 182 PathSearchElm *cur_elm = stack->data;
114 size_t parent_len = strlen(cur_path);
115 if(parent_len > WEBDAV_PATH_MAX) {
116 log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded");
117 err = 1;
118 break;
119 }
120 if(cur_path[parent_len-1] == '/') {
121 parent_len--;
122 }
123 size_t max_child_len = WEBDAV_PATH_MAX - parent_len;
124 183
125 // when newpath is initialized with the parent path 184 // when newpath is initialized with the parent path
126 // set path_buf_init to TRUE 185 // set path_buf_init to TRUE
186 WSBool href_buf_init = FALSE;
127 WSBool path_buf_init = FALSE; 187 WSBool path_buf_init = FALSE;
128 188
129 VFS_DIR dir = vfs_opendir(vfs, path); 189 VFS_DIR dir = vfs_opendir(vfs, cur_elm->path);
130 if(!dir) { 190 if(!dir) {
131 log_ereport( 191 log_ereport(
132 LOG_FAILURE, 192 LOG_FAILURE,
133 "webdav: propfind: cannot open directory %d", 193 "webdav: propfind: cannot open directory %d",
134 vfs->vfs_errno); 194 vfs->vfs_errno);
141 if(f.stat_errno != 0) { 201 if(f.stat_errno != 0) {
142 continue; 202 continue;
143 } 203 }
144 204
145 size_t child_len = strlen(f.name); 205 size_t child_len = strlen(f.name);
146 if(child_len > max_child_len) { 206
147 log_ereport(LOG_FAILURE, "webdav: maximal path length exceeded"); 207 // create new path and href for the child
208 if(path_buf_concat(
209 pool,
210 &newhref,
211 &newhreflen,
212 &href_buf_init,
213 cur_elm->href,
214 cur_elm->hreflen,
215 f.name,
216 child_len))
217 {
148 err = 1; 218 err = 1;
149 break; 219 break;
150 } 220 }
151 size_t childpathlen = parent_len + child_len + 1; // +1 '/' 221 if(path_buf_concat(
152 if(childpathlen > newpathlen) { 222 pool,
153 // we're gonna need a bigger boa^H^H^Hbuffer 223 &newpath,
154 if(newpath) { 224 &newpathlen,
155 pool_free(pool, newpath); 225 &path_buf_init,
156 } 226 cur_elm->path,
157 newpath = pool_malloc(pool, childpathlen + 1); 227 cur_elm->pathlen,
158 if(!newpath) { 228 f.name,
159 err = 1; 229 child_len))
160 break; 230 {
161 } 231 err = 1;
162 newpathlen = childpathlen; 232 break;
163 path_buf_init = FALSE; 233 }
164 } 234 size_t childhreflen = cur_elm->hreflen + 1 + child_len;
165 // create full path string for this child 235 size_t childpathlen = cur_elm->pathlen + 1 + child_len;
166 if(!path_buf_init) {
167 memcpy(newpath, cur_path, parent_len);
168 newpath[parent_len] = '/';
169 }
170 memcpy(newpath+parent_len+1, f.name, child_len);
171 newpath[childpathlen] = 0;
172 236
173 // propfind for this child 237 // propfind for this child
174 if(webdav_op_propfind_begin(op, newpath, dir, &f.stat)) { 238 if(webdav_op_propfind_begin(op, newpath, dir, &f.stat)) {
175 err = 1; 239 err = 1;
176 break; 240 break;
177 } 241 }
178 242
179 // depth of -1 means infinity 243 // depth of -1 means infinity
180 if(request->depth == -1 && S_ISDIR(f.stat.st_mode)) { 244 if(request->depth == -1 && S_ISDIR(f.stat.st_mode)) {
245 char *hrefcp = pool_malloc(pool, childhreflen + 1);
246 memcpy(hrefcp, newhref, childhreflen + 1);
247 hrefcp[childhreflen] = '\0';
248
181 char *pathcp = pool_malloc(pool, childpathlen + 1); 249 char *pathcp = pool_malloc(pool, childpathlen + 1);
182 memcpy(pathcp, newpath, childpathlen + 1); 250 memcpy(pathcp, newpath, childpathlen + 1);
251 pathcp[childpathlen] = '\0';
183 252
184 // add the newpath copy to the stack 253 PathSearchElm *new_elm = pool_malloc(pool,
254 sizeof(PathSearchElm));
255 new_elm->href = hrefcp;
256 new_elm->path = pathcp;
257 new_elm->hreflen = childhreflen;
258 new_elm->pathlen = childpathlen;
259
260 // add the new_elm to the stack
185 // stack_end is always not NULL here, because we remove 261 // stack_end is always not NULL here, because we remove
186 // the first stack element at the end of the loop 262 // the first stack element at the end of the loop
187 UcxList *newlistelm = ucx_list_append_a(a, stack_end, pathcp); 263 UcxList *newlistelm = ucx_list_append_a(a, stack_end, new_elm);
188 if(!newlistelm) { 264 if(!newlistelm) {
189 err = 1; 265 err = 1;
190 break; 266 break;
191 } 267 }
192 stack_end = newlistelm; 268 stack_end = newlistelm;
193 } 269 }
194 } 270 }
195 271
196 vfs_closedir(dir); 272 vfs_closedir(dir);
197 273
198 if(cur_path != path) { 274 pool_free(pool, cur_elm->path);
199 pool_free(pool, cur_path); 275 pool_free(pool, cur_elm->href);
200 } 276 pool_free(pool, cur_elm);
277
201 stack = ucx_list_remove_a(a, stack, stack); 278 stack = ucx_list_remove_a(a, stack, stack);
202 } 279 }
203 280
204 // in case of an error, we have to free all remaining stack elements 281 // in case of an error, we have to free all remaining stack elements
205 UCX_FOREACH(elm, stack) { 282 UCX_FOREACH(elm, stack) {

mercurial