LCOV - code coverage report
Current view: top level - source3/modules - vfs_preopen.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 7 308 2.3 %
Date: 2024-05-31 13:13:24 Functions: 1 14 7.1 %

          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             : }

Generated by: LCOV version 1.14