Line data Source code
1 : /*
2 : * Force a readahead of files by opening them and reading the first bytes
3 : *
4 : * Copyright (C) Volker Lendecke 2008
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 2 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, write to the Free Software
18 : * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 : */
20 :
21 : #include "includes.h"
22 : #include "system/filesys.h"
23 : #include "smbd/smbd.h"
24 : #include "lib/util/sys_rw.h"
25 : #include "lib/util/sys_rw_data.h"
26 : #include "lib/util/smb_strtox.h"
27 : #include "lib/util_matching.h"
28 : #include "lib/global_contexts.h"
29 :
30 : static int vfs_preopen_debug_level = DBGC_VFS;
31 :
32 : #undef DBGC_CLASS
33 : #define DBGC_CLASS vfs_preopen_debug_level
34 :
35 : #define PREOPEN_MAX_DIGITS 19
36 : #define PREOPEN_MAX_NUMBER (uint64_t)9999999999999999999ULL
37 :
38 : struct preopen_state;
39 :
40 : struct preopen_helper {
41 : struct preopen_state *state;
42 : struct tevent_fd *fde;
43 : pid_t pid;
44 : int fd;
45 : bool busy;
46 : };
47 :
48 : struct preopen_state {
49 : int num_helpers;
50 : struct preopen_helper *helpers;
51 :
52 : size_t to_read; /* How many bytes to read in children? */
53 : int queue_max;
54 :
55 : int queue_dbglvl; /* DBGLVL_DEBUG by default */
56 : int nomatch_dbglvl; /* DBGLVL_INFO by default */
57 : int match_dbglvl; /* DBGLVL_INFO by default */
58 : int reset_dbglvl; /* DBGLVL_INFO by default */
59 : int nodigits_dbglvl; /* DBGLVL_WARNING by default */
60 : int founddigits_dbglvl; /* DBGLVL_NOTICE by default */
61 : int push_dbglvl; /* DBGLVL_NOTICE by default */
62 :
63 : char *template_fname; /* Filename to be sent to children */
64 : size_t number_start; /* start offset into "template_fname" */
65 : int num_digits; /* How many digits is the number long? */
66 :
67 : uint64_t fnum_sent; /* last fname sent to children */
68 :
69 : uint64_t fnum_queue_end;/* last fname to be sent, based on
70 : * last open call + preopen:queuelen
71 : */
72 :
73 : struct samba_path_matching *preopen_names;
74 : ssize_t last_match_idx; /* remember the last match */
75 : };
76 :
77 0 : static void preopen_helper_destroy(struct preopen_helper *c)
78 : {
79 : int status;
80 0 : TALLOC_FREE(c->fde);
81 0 : close(c->fd);
82 0 : c->fd = -1;
83 0 : kill(c->pid, SIGKILL);
84 0 : waitpid(c->pid, &status, 0);
85 0 : c->busy = true;
86 0 : }
87 :
88 0 : static void preopen_queue_run(struct preopen_state *state)
89 : {
90 : char *pdelimiter;
91 : char delimiter;
92 :
93 0 : DBG_PREFIX(state->queue_dbglvl, ("START: "
94 : "last_fname[%s] start_offset=%zu num_digits=%d "
95 : "last_pushed_num=%"PRIu64" queue_end_num=%"PRIu64" num_helpers=%d\n",
96 : state->template_fname,
97 : state->number_start,
98 : state->num_digits,
99 : state->fnum_sent,
100 : state->fnum_queue_end,
101 : state->num_helpers));
102 :
103 0 : pdelimiter = state->template_fname + state->number_start
104 0 : + state->num_digits;
105 0 : delimiter = *pdelimiter;
106 :
107 0 : while (state->fnum_sent < state->fnum_queue_end) {
108 :
109 : ssize_t written;
110 : size_t to_write;
111 : int helper;
112 :
113 0 : for (helper=0; helper<state->num_helpers; helper++) {
114 0 : if (state->helpers[helper].busy) {
115 0 : continue;
116 : }
117 0 : break;
118 : }
119 0 : if (helper == state->num_helpers) {
120 : /* everyone is busy */
121 0 : DBG_PREFIX(state->queue_dbglvl, ("BUSY: "
122 : "template_fname[%s] start_offset=%zu num_digits=%d "
123 : "last_pushed_num=%"PRIu64" queue_end_num=%"PRIu64"\n",
124 : state->template_fname,
125 : state->number_start,
126 : state->num_digits,
127 : state->fnum_sent,
128 : state->fnum_queue_end));
129 0 : return;
130 : }
131 :
132 0 : snprintf(state->template_fname + state->number_start,
133 0 : state->num_digits + 1,
134 : "%.*llu", state->num_digits,
135 0 : (long long unsigned int)(state->fnum_sent + 1));
136 0 : *pdelimiter = delimiter;
137 :
138 0 : DBG_PREFIX(state->push_dbglvl, (
139 : "PUSH: fullpath[%s] to helper(idx=%d)\n",
140 : state->template_fname, helper));
141 :
142 0 : to_write = talloc_get_size(state->template_fname);
143 0 : written = write_data(state->helpers[helper].fd,
144 0 : state->template_fname, to_write);
145 0 : state->helpers[helper].busy = true;
146 :
147 0 : if (written != to_write) {
148 0 : preopen_helper_destroy(&state->helpers[helper]);
149 : }
150 0 : state->fnum_sent += 1;
151 : }
152 0 : DBG_PREFIX(state->queue_dbglvl, ("END: "
153 : "template_fname[%s] start_offset=%zu num_digits=%d "
154 : "last_pushed_num=%"PRIu64" queue_end_num=%"PRIu64"\n",
155 : state->template_fname,
156 : state->number_start,
157 : state->num_digits,
158 : state->fnum_sent,
159 : state->fnum_queue_end));
160 : }
161 :
162 0 : static void preopen_helper_readable(struct tevent_context *ev,
163 : struct tevent_fd *fde, uint16_t flags,
164 : void *priv)
165 : {
166 0 : struct preopen_helper *helper = (struct preopen_helper *)priv;
167 0 : struct preopen_state *state = helper->state;
168 : ssize_t nread;
169 : char c;
170 :
171 0 : if ((flags & TEVENT_FD_READ) == 0) {
172 0 : return;
173 : }
174 :
175 0 : nread = read(helper->fd, &c, 1);
176 0 : if (nread <= 0) {
177 0 : preopen_helper_destroy(helper);
178 0 : return;
179 : }
180 :
181 0 : helper->busy = false;
182 :
183 0 : DBG_PREFIX(state->queue_dbglvl, ("BEFORE: preopen_queue_run\n"));
184 0 : preopen_queue_run(state);
185 0 : DBG_PREFIX(state->queue_dbglvl, ("AFTER: preopen_queue_run\n"));
186 : }
187 :
188 0 : static int preopen_helpers_destructor(struct preopen_state *c)
189 : {
190 : int i;
191 :
192 0 : for (i=0; i<c->num_helpers; i++) {
193 0 : if (c->helpers[i].fd == -1) {
194 0 : continue;
195 : }
196 0 : preopen_helper_destroy(&c->helpers[i]);
197 : }
198 :
199 0 : return 0;
200 : }
201 :
202 0 : static bool preopen_helper_open_one(int sock_fd, char **pnamebuf,
203 : size_t to_read, void *filebuf)
204 : {
205 0 : char *namebuf = *pnamebuf;
206 : ssize_t nread;
207 0 : char c = 0;
208 : int fd;
209 :
210 0 : nread = 0;
211 :
212 : do {
213 : ssize_t thistime;
214 :
215 0 : thistime = read(sock_fd, namebuf + nread,
216 0 : talloc_get_size(namebuf) - nread);
217 0 : if (thistime <= 0) {
218 0 : return false;
219 : }
220 :
221 0 : nread += thistime;
222 :
223 0 : if (nread == talloc_get_size(namebuf)) {
224 0 : namebuf = talloc_realloc(
225 : NULL, namebuf, char,
226 : talloc_get_size(namebuf) * 2);
227 0 : if (namebuf == NULL) {
228 0 : return false;
229 : }
230 0 : *pnamebuf = namebuf;
231 : }
232 0 : } while (namebuf[nread - 1] != '\0');
233 :
234 0 : fd = open(namebuf, O_RDONLY);
235 0 : if (fd == -1) {
236 0 : goto done;
237 : }
238 0 : nread = read(fd, filebuf, to_read);
239 0 : close(fd);
240 :
241 0 : done:
242 0 : sys_write_v(sock_fd, &c, 1);
243 0 : return true;
244 : }
245 :
246 0 : static bool preopen_helper(int fd, size_t to_read)
247 : {
248 : char *namebuf;
249 : void *readbuf;
250 :
251 0 : namebuf = talloc_array(NULL, char, 1024);
252 0 : if (namebuf == NULL) {
253 0 : return false;
254 : }
255 :
256 0 : readbuf = talloc_size(NULL, to_read);
257 0 : if (readbuf == NULL) {
258 0 : TALLOC_FREE(namebuf);
259 0 : return false;
260 : }
261 :
262 0 : while (preopen_helper_open_one(fd, &namebuf, to_read, readbuf)) {
263 : ;
264 : }
265 :
266 0 : TALLOC_FREE(readbuf);
267 0 : TALLOC_FREE(namebuf);
268 0 : return false;
269 : }
270 :
271 0 : static NTSTATUS preopen_init_helper(struct preopen_helper *h)
272 : {
273 : int fdpair[2];
274 : NTSTATUS status;
275 :
276 0 : if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) == -1) {
277 0 : status = map_nt_error_from_unix(errno);
278 0 : DEBUG(10, ("socketpair() failed: %s\n", strerror(errno)));
279 0 : return status;
280 : }
281 :
282 0 : h->pid = fork();
283 :
284 0 : if (h->pid == -1) {
285 0 : return map_nt_error_from_unix(errno);
286 : }
287 :
288 0 : if (h->pid == 0) {
289 0 : close(fdpair[0]);
290 0 : preopen_helper(fdpair[1], h->state->to_read);
291 0 : exit(0);
292 : }
293 0 : close(fdpair[1]);
294 0 : h->fd = fdpair[0];
295 0 : h->fde = tevent_add_fd(global_event_context(), h->state, h->fd,
296 : TEVENT_FD_READ, preopen_helper_readable, h);
297 0 : if (h->fde == NULL) {
298 0 : close(h->fd);
299 0 : h->fd = -1;
300 0 : return NT_STATUS_NO_MEMORY;
301 : }
302 0 : h->busy = false;
303 0 : return NT_STATUS_OK;
304 : }
305 :
306 0 : static NTSTATUS preopen_init_helpers(TALLOC_CTX *mem_ctx, size_t to_read,
307 : int num_helpers, int queue_max,
308 : struct preopen_state **presult)
309 : {
310 : struct preopen_state *result;
311 : int i;
312 :
313 0 : result = talloc(mem_ctx, struct preopen_state);
314 0 : if (result == NULL) {
315 0 : return NT_STATUS_NO_MEMORY;
316 : }
317 :
318 0 : result->num_helpers = num_helpers;
319 0 : result->helpers = talloc_array(result, struct preopen_helper,
320 : num_helpers);
321 0 : if (result->helpers == NULL) {
322 0 : TALLOC_FREE(result);
323 0 : return NT_STATUS_NO_MEMORY;
324 : }
325 :
326 0 : result->to_read = to_read;
327 0 : result->queue_max = queue_max;
328 0 : result->template_fname = NULL;
329 0 : result->fnum_sent = 0;
330 0 : result->fnum_queue_end = 0;
331 :
332 0 : for (i=0; i<num_helpers; i++) {
333 0 : result->helpers[i].state = result;
334 0 : result->helpers[i].fd = -1;
335 : }
336 :
337 0 : talloc_set_destructor(result, preopen_helpers_destructor);
338 :
339 0 : for (i=0; i<num_helpers; i++) {
340 0 : preopen_init_helper(&result->helpers[i]);
341 : }
342 :
343 0 : *presult = result;
344 0 : return NT_STATUS_OK;
345 : }
346 :
347 0 : static void preopen_free_helpers(void **ptr)
348 : {
349 0 : TALLOC_FREE(*ptr);
350 0 : }
351 :
352 0 : static struct preopen_state *preopen_state_get(vfs_handle_struct *handle)
353 : {
354 : struct preopen_state *state;
355 : NTSTATUS status;
356 : const char *namelist;
357 :
358 0 : if (SMB_VFS_HANDLE_TEST_DATA(handle)) {
359 0 : SMB_VFS_HANDLE_GET_DATA(handle, state, struct preopen_state,
360 : return NULL);
361 0 : return state;
362 : }
363 :
364 0 : namelist = lp_parm_const_string(SNUM(handle->conn), "preopen", "names",
365 : NULL);
366 :
367 0 : if (namelist == NULL) {
368 0 : return NULL;
369 : }
370 :
371 0 : status = preopen_init_helpers(
372 : NULL,
373 0 : lp_parm_int(SNUM(handle->conn), "preopen", "num_bytes", 1),
374 0 : lp_parm_int(SNUM(handle->conn), "preopen", "helpers", 1),
375 0 : lp_parm_int(SNUM(handle->conn), "preopen", "queuelen", 10),
376 : &state);
377 0 : if (!NT_STATUS_IS_OK(status)) {
378 0 : return NULL;
379 : }
380 :
381 0 : state->queue_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "queue_log_level", DBGLVL_DEBUG);
382 0 : state->nomatch_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "nomatch_log_level", DBGLVL_INFO);
383 0 : state->match_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "match_log_level", DBGLVL_INFO);
384 0 : state->reset_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "reset_log_level", DBGLVL_INFO);
385 0 : state->nodigits_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "nodigits_log_level", DBGLVL_WARNING);
386 0 : state->founddigits_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "founddigits_log_level", DBGLVL_NOTICE);
387 0 : state->push_dbglvl = lp_parm_int(SNUM(handle->conn), "preopen", "push_log_level", DBGLVL_NOTICE);
388 :
389 0 : if (lp_parm_bool(SNUM(handle->conn), "preopen", "posix-basic-regex", false)) {
390 0 : status = samba_path_matching_regex_sub1_create(state,
391 : namelist,
392 0 : &state->preopen_names);
393 : } else {
394 0 : status = samba_path_matching_mswild_create(state,
395 : true, /* case_sensitive */
396 : namelist,
397 0 : &state->preopen_names);
398 : }
399 0 : if (!NT_STATUS_IS_OK(status)) {
400 0 : TALLOC_FREE(state);
401 0 : return NULL;
402 : }
403 0 : state->last_match_idx = -1;
404 :
405 0 : if (!SMB_VFS_HANDLE_TEST_DATA(handle)) {
406 0 : SMB_VFS_HANDLE_SET_DATA(handle, state, preopen_free_helpers,
407 : struct preopen_state, return NULL);
408 : }
409 :
410 0 : return state;
411 : }
412 :
413 0 : static bool preopen_parse_fname(const char *fname, uint64_t *pnum,
414 : size_t *pstart_idx, int *pnum_digits)
415 : {
416 0 : char digits[PREOPEN_MAX_DIGITS+1] = { 0, };
417 : const char *p;
418 0 : char *q = NULL;
419 : unsigned long long num;
420 0 : size_t start_idx = 0;
421 0 : int num_digits = -1;
422 0 : int error = 0;
423 :
424 0 : if (*pstart_idx > 0 && *pnum_digits > 0) {
425 : /*
426 : * If the caller knowns
427 : * how many digits are expected
428 : * and on what position,
429 : * we should copy the exact
430 : * subset before we start
431 : * parsing the string into a number
432 : */
433 :
434 0 : if (*pnum_digits > PREOPEN_MAX_DIGITS) {
435 : /*
436 : * a string with as much digits as
437 : * PREOPEN_MAX_DIGITS is the longest
438 : * string that would make any sense for us.
439 : *
440 : * The rest will be checked via
441 : * smb_strtoull().
442 : */
443 0 : return false;
444 : }
445 0 : p = fname + *pstart_idx;
446 0 : memcpy(digits, p, *pnum_digits);
447 0 : p = digits;
448 0 : start_idx = *pstart_idx;
449 0 : goto parse;
450 : }
451 :
452 0 : p = strrchr_m(fname, '/');
453 0 : if (p == NULL) {
454 0 : p = fname;
455 : }
456 :
457 0 : p += 1;
458 0 : while (p[0] != '\0') {
459 0 : if (isdigit(p[0]) && isdigit(p[1]) && isdigit(p[2])) {
460 0 : break;
461 : }
462 0 : p += 1;
463 : }
464 0 : if (*p == '\0') {
465 : /* no digits around */
466 0 : return false;
467 : }
468 :
469 0 : start_idx = (p - fname);
470 :
471 0 : parse:
472 0 : num = smb_strtoull(p, (char **)&q, 10, &error, SMB_STR_STANDARD);
473 0 : if (error != 0) {
474 0 : return false;
475 : }
476 :
477 0 : if (num >= PREOPEN_MAX_NUMBER) {
478 : /* overflow */
479 0 : return false;
480 : }
481 :
482 0 : num_digits = (q - p);
483 :
484 0 : if (*pnum_digits != -1 && *pnum_digits != num_digits) {
485 : /*
486 : * If the caller knowns how many digits
487 : * it expects we should fail if we got something
488 : * different.
489 : */
490 0 : return false;
491 : }
492 :
493 0 : *pnum = num;
494 0 : *pstart_idx = start_idx;
495 0 : *pnum_digits = num_digits;
496 0 : return true;
497 : }
498 :
499 0 : static uint64_t num_digits_max_value(int num_digits)
500 : {
501 0 : uint64_t num_max = 1;
502 : int i;
503 :
504 0 : if (num_digits < 1) {
505 0 : return 0;
506 : }
507 0 : if (num_digits >= PREOPEN_MAX_DIGITS) {
508 0 : return PREOPEN_MAX_NUMBER;
509 : }
510 :
511 0 : for (i = 0; i < num_digits; i++) {
512 0 : num_max *= 10;
513 : }
514 :
515 : /*
516 : * We actually want
517 : * 9 instead of 10
518 : * 99 instead of 100
519 : * 999 instead of 1000
520 : */
521 0 : return num_max - 1;
522 : }
523 :
524 0 : static int preopen_openat(struct vfs_handle_struct *handle,
525 : const struct files_struct *dirfsp,
526 : const struct smb_filename *smb_fname,
527 : struct files_struct *fsp,
528 : const struct vfs_open_how *how)
529 : {
530 0 : const char *dirname = dirfsp->fsp_name->base_name;
531 : struct preopen_state *state;
532 : int res;
533 : uint64_t num;
534 : uint64_t num_max;
535 : NTSTATUS status;
536 0 : char *new_template = NULL;
537 0 : size_t new_start = 0;
538 0 : int new_digits = -1;
539 0 : size_t new_end = 0;
540 0 : ssize_t match_idx = -1;
541 0 : ssize_t replace_start = -1;
542 0 : ssize_t replace_end = -1;
543 0 : bool need_reset = false;
544 :
545 0 : DBG_DEBUG("called on %s\n", smb_fname_str_dbg(smb_fname));
546 :
547 0 : state = preopen_state_get(handle);
548 0 : if (state == NULL) {
549 0 : return SMB_VFS_NEXT_OPENAT(handle,
550 : dirfsp,
551 : smb_fname,
552 : fsp,
553 : how);
554 : }
555 :
556 0 : res = SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, how);
557 0 : if (res == -1) {
558 0 : return -1;
559 : }
560 :
561 0 : if ((how->flags & O_ACCMODE) != O_RDONLY) {
562 0 : return res;
563 : }
564 :
565 : /*
566 : * Make sure we can later construct an absolute pathname
567 : */
568 0 : if (dirname[0] != '/') {
569 0 : return res;
570 : }
571 : /*
572 : * There's no point in preopen the directory itself.
573 : */
574 0 : if (ISDOT(smb_fname->base_name)) {
575 0 : return res;
576 : }
577 : /*
578 : * If we got an absolute path in
579 : * smb_fname it's most likely the
580 : * reopen via /proc/self/fd/$fd
581 : */
582 0 : if (smb_fname->base_name[0] == '/') {
583 0 : return res;
584 : }
585 :
586 0 : status = samba_path_matching_check_last_component(state->preopen_names,
587 0 : smb_fname->base_name,
588 : &match_idx,
589 : &replace_start,
590 : &replace_end);
591 0 : if (!NT_STATUS_IS_OK(status)) {
592 0 : match_idx = -1;
593 : }
594 0 : if (match_idx < 0) {
595 0 : DBG_PREFIX(state->nomatch_dbglvl, (
596 : "No match with the preopen:names list by name[%s]\n",
597 : smb_fname_str_dbg(smb_fname)));
598 0 : return res;
599 : }
600 :
601 0 : if (replace_start != -1 && replace_end != -1) {
602 0 : DBG_PREFIX(state->match_dbglvl, (
603 : "Pattern(idx=%zd) from preopen:names list matched name[%s] hints(start=%zd,end=%zd)\n",
604 : match_idx, smb_fname_str_dbg(smb_fname), replace_start, replace_end));
605 : } else {
606 0 : DBG_PREFIX(state->match_dbglvl, (
607 : "Pattern(idx=%zd) from preopen:names list matched name[%s]\n",
608 : match_idx, smb_fname_str_dbg(smb_fname)));
609 : }
610 :
611 0 : new_template = talloc_asprintf(
612 : state, "%s/%s",
613 0 : dirname, smb_fname->base_name);
614 0 : if (new_template == NULL) {
615 0 : DBG_ERR("talloc_asprintf(%s/%s) failed\n",
616 : dirname, smb_fname_str_dbg(smb_fname));
617 0 : return res;
618 : }
619 :
620 0 : if (replace_start != -1 && replace_end != -1) {
621 0 : size_t dirofs = strlen(dirname) + 1;
622 0 : new_start = dirofs + replace_start;
623 0 : new_digits = replace_end - replace_start;
624 : }
625 :
626 0 : if (!preopen_parse_fname(new_template, &num,
627 : &new_start, &new_digits)) {
628 0 : DBG_PREFIX(state->nodigits_dbglvl, (
629 : "Pattern(idx=%zd) no valid digits found on fullpath[%s]\n",
630 : match_idx, new_template));
631 0 : TALLOC_FREE(new_template);
632 0 : return res;
633 : }
634 0 : new_end = new_start + new_digits;
635 :
636 0 : DBG_PREFIX(state->founddigits_dbglvl, (
637 : "Pattern(idx=%zd) found num_digits[%d] start_offset[%zd] parsed_num[%"PRIu64"] fullpath[%s]\n",
638 : match_idx, new_digits, new_start, num, new_template));
639 :
640 0 : if (state->last_match_idx != match_idx) {
641 : /*
642 : * If a different pattern caused the match
643 : * we better reset the queue
644 : */
645 0 : if (state->last_match_idx != -1) {
646 0 : DBG_PREFIX(state->reset_dbglvl, ("RESET: "
647 : "pattern changed from idx=%zd to idx=%zd by fullpath[%s]\n",
648 : state->last_match_idx, match_idx, new_template));
649 : }
650 0 : need_reset = true;
651 0 : } else if (state->number_start != new_start) {
652 : /*
653 : * If the digits started at a different position
654 : * we better reset the queue
655 : */
656 0 : DBG_PREFIX(state->reset_dbglvl, ("RESET: "
657 : "start_offset changed from byte=%zd to byte=%zd by fullpath[%s]\n",
658 : state->number_start, new_start, new_template));
659 0 : need_reset = true;
660 0 : } else if (state->num_digits != new_digits) {
661 : /*
662 : * If number of digits changed
663 : * we better reset the queue
664 : */
665 0 : DBG_PREFIX(state->reset_dbglvl, ("RESET: "
666 : "num_digits changed %d to %d by fullpath[%s]\n",
667 : state->num_digits, new_digits, new_template));
668 0 : need_reset = true;
669 0 : } else if (strncmp(state->template_fname, new_template, new_start) != 0) {
670 : /*
671 : * If name before the digits changed
672 : * we better reset the queue
673 : */
674 0 : DBG_PREFIX(state->reset_dbglvl, ("RESET: "
675 : "leading pathprefix[%.*s] changed by fullpath[%s]\n",
676 : (int)state->number_start, state->template_fname, new_template));
677 0 : need_reset = true;
678 0 : } else if (strcmp(state->template_fname + new_end, new_template + new_end) != 0) {
679 : /*
680 : * If name after the digits changed
681 : * we better reset the queue
682 : */
683 0 : DBG_PREFIX(state->reset_dbglvl, ("RESET: "
684 : "trailing suffix[%s] changed by fullpath[%s]\n",
685 : state->template_fname + new_end, new_template));
686 0 : need_reset = true;
687 : }
688 :
689 0 : if (need_reset) {
690 : /*
691 : * Reset the queue
692 : */
693 0 : state->fnum_sent = 0;
694 0 : state->fnum_queue_end = 0;
695 0 : state->last_match_idx = match_idx;
696 : }
697 :
698 0 : TALLOC_FREE(state->template_fname);
699 0 : state->template_fname = new_template;
700 0 : state->number_start = new_start;
701 0 : state->num_digits = new_digits;
702 :
703 0 : if (num > state->fnum_sent) {
704 : /*
705 : * Helpers were too slow, there's no point in reading
706 : * files in helpers that we already read in the
707 : * parent.
708 : */
709 0 : state->fnum_sent = num;
710 : }
711 :
712 0 : if ((state->fnum_queue_end != 0) /* Something was started earlier */
713 0 : && (num < (state->fnum_queue_end - state->queue_max))) {
714 : /*
715 : * "num" is before the queue we announced. This means
716 : * a new run is started.
717 : */
718 0 : state->fnum_sent = num;
719 : }
720 :
721 0 : num_max = num_digits_max_value(state->num_digits);
722 0 : state->fnum_queue_end = MIN(num_max, num + state->queue_max);
723 :
724 0 : DBG_PREFIX(state->queue_dbglvl, ("BEFORE: preopen_queue_run\n"));
725 0 : preopen_queue_run(state);
726 0 : DBG_PREFIX(state->queue_dbglvl, ("AFTER: preopen_queue_run\n"));
727 :
728 0 : return res;
729 : }
730 :
731 : static struct vfs_fn_pointers vfs_preopen_fns = {
732 : .openat_fn = preopen_openat,
733 : };
734 :
735 : static_decl_vfs;
736 27 : NTSTATUS vfs_preopen_init(TALLOC_CTX *ctx)
737 : {
738 : NTSTATUS status;
739 :
740 27 : status = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
741 : "preopen",
742 : &vfs_preopen_fns);
743 27 : if (!NT_STATUS_IS_OK(status)) {
744 0 : return status;
745 : }
746 :
747 27 : vfs_preopen_debug_level = debug_add_class("preopen");
748 27 : if (vfs_preopen_debug_level == -1) {
749 0 : vfs_preopen_debug_level = DBGC_VFS;
750 0 : DBG_ERR("Couldn't register custom debugging class!\n");
751 : } else {
752 27 : DBG_DEBUG("Debug class number of 'preopen': %d\n",
753 : vfs_preopen_debug_level);
754 : }
755 :
756 27 : return NT_STATUS_OK;
757 : }
|