static int vt_filter( sqlite3_vtab_cursor *p_vtc, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ) { /* Initialize the cursor structure. */ vtab_cursor *p_cur = (vtab_cursor*)p_vtc; vtab *p_vt = (vtab*)p_vtc->pVtab; if (argc > 0) { p_cur->search_paths = strdup(sqlite3_value_text(argv[0])); } else { /* Start search at root file system. */ p_cur->search_paths = strdup("/"); } /* p_cur->search_paths is a comma-delimited list of directories to ** search. p_cur->root_path keeps track of the current directory we are ** searching. We move to the next in the list using next_directory(), which ** searces the root_path string for the next directory. */ /* Place root_path to beginning of search path string. */ p_cur->root_path = p_cur->search_paths; /* Zero rows returned thus far. */ p_cur->count = 0; /* Have not reached end of set. */ p_cur->eof = 0; /* Load first directory to search. */ return next_directory(p_cur); return SQLITE_OK; }
int file_completion(char *path, int index) { static int dir_in_use = 0; static char *head, *tail = NULL; static int tail_offset; char nbuf[FILENAME], buffer[FILENAME]; char *dir, *base; if (path) { if (dir_in_use) { close_directory(); dir_in_use = 0; } if (index < 0) return 0; head = path; tail = path + index; } if (!dir_in_use) { path = head; *tail = NUL; if (*path == '|') return -1; /* no completion for pipes */ if (*path == '+' || *path == '~') { if (!expand_file_name(nbuf, path, 0x11)) return 0; /* no completions */ } else strcpy(nbuf, path); if ((base = strrchr(nbuf, '/'))) { if (base == nbuf) { dir = "/"; base++; } else { *base++ = NUL; dir = nbuf; } } else { base = nbuf; dir = "."; } tail_offset = strlen(base); dir_in_use = list_directory(dir, base); return dir_in_use; } if (index) return compl_help_directory(); if (!next_directory(buffer, 1)) return 0; strcpy(tail, buffer + tail_offset); return 1; }
static int vt_next(sqlite3_vtab_cursor *cur) { vtab_cursor *p_cur = (vtab_cursor*)cur; vtab* p_vt = (vtab*)cur->pVtab; /** This is a rather involved function. It is the core of this virtual * table. This function recursively reads down into a directory. It * automatically decends into a directory when it finds one, and * automatically ascends out of it when it has read all of its entries. * The logic is as follows: * The p_cur->current_node (a filenode struct) points to the current file * entry (given by the APR handle p_cur->current_node->dirent) and its * associated directory (given by the APR handle * p_cur->current_node->dirent) * We attempt to read the next entry in p_cur->current_node->dir, filling * the p_cur->current_node->dirent. If we succeed, then we have either a * file or a directory. If we have a directory, then we descend into it. If * we have a file, we proceed as usual. In either case, the dirent entry * will consitute a row in the result set, as we have done as much as we * have to and can exit the function. Our only job is to get to the next * valid file or directory entry to return as the current row in the * rowset. * If there are no more entries in the current directory, then we * deallocate p_cur->current_node and proceed up one directory (given by * p_cur->current_node->parent). We thus set p_cur->current_node to * p_cur->current_node->parent, and start over again. */ read_next_entry: /** First, check for a special case where the top level directory is * actually a top-level file. In this case, we rely that * p_cur->current_node->dir == NULL (set by next_directory()). If this is * true, resort to next_directory(). */ if (p_cur->current_node->dir == NULL) { return next_directory(p_cur); } /* Read the next directory entry. */ /* Increment the current row count. */ p_cur->count += 1; struct filenode* d = p_cur->current_node; struct filenode* prev_d = d; reread_next_entry: /* Read the next entry in the directory (d->dir). Fills the d->dirent member. */ if ( apr_dir_read( &d->dirent, APR_FINFO_DIRENT|APR_FINFO_PROT|APR_FINFO_TYPE| APR_FINFO_NAME|APR_FINFO_SIZE, d->dir) != APR_SUCCESS ) { /** If we get here, the call failed. There are no more entries in * directory. */ /** If we are at the top level directory */ if (d->parent == NULL) { /** We are done with this directory. See if there is another * top-level directory to search. * * If there is not another directory, next_directory() will have set * eof=1. We are at the end of the result set. If there is another * directory to search, then it will load the next dirent for * us. Either way, we have nothing left to do here. */ return next_directory(p_cur); } else { /** There is a parent directory that we still have to search * through. Free this filenode and resume iterating through the * parent. */ d = move_up_directory(p_cur); /* Start over, reading the next entry from parent. */ goto read_next_entry; } } /* If the current dirent is a directory, then descend into it. */ if (d->dirent.filetype == APR_DIR) { /* Skip . and .. entries */ if (d->dirent.name != NULL) { if (strcmp(d->dirent.name, ".") == 0 || strcmp(d->dirent.name, "..") == 0) { goto read_next_entry; } } /* Create a new child directory node */ /* Combine the path and file names to get full path */ char path[1024]; sprintf(&path[0], "%s/%s", d->path, d->dirent.name); /* Allocate space for new filenode and initlialize members. */ d = malloc(sizeof(struct filenode)); d->path = strdup(path); d->parent = p_cur->current_node; /* See note ZERO-FILL DIRENT below. */ memset(&d->dirent, 0, sizeof(apr_finfo_t)); /* Set current pointer to it. */ p_cur->current_node = d; /* Clear the pool memory associated with the path string allocated above. */ apr_pool_clear(p_cur->tmp_pool); /* Open the directory */ if ((p_cur->status = apr_dir_open(&d->dir, d->path, p_cur->pool)) != APR_SUCCESS) { /* Problem. Couldn't open directory. */ fprintf( stderr, "Failed to open directory: %s\n", p_cur->current_node->path ); /* Set this to null to move_up_directory() doesn't try to * apr_close() it (->core dump) */ p_cur->current_node->dir = NULL; /* Skip to next entry */ deallocate_filenode(d); p_cur->current_node = d = prev_d; goto reread_next_entry; } /* Else we were able to open directory. Update the currnet dirent info ** to that of the opened directory. This is our next row in the result ** set. */ apr_stat( &d->dirent, d->path, APR_FINFO_DIRENT|APR_FINFO_TYPE|APR_FINFO_NAME, p_cur->pool ); } return SQLITE_OK; }