root/source3/modules/vfs_dirsort.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. compare_dirent
  2. free_dirsort_privates
  3. open_and_sort_dir
  4. dirsort_opendir
  5. dirsort_readdir
  6. dirsort_seekdir
  7. dirsort_telldir
  8. dirsort_rewinddir
  9. vfs_dirsort_init

   1 /*
   2  * VFS module to provide a sorted directory list.
   3  *
   4  * Copyright (C) Andy Kelk (andy@mopoke.co.uk), 2009
   5  *
   6  *
   7  * This program is free software; you can redistribute it and/or modify
   8  * it under the terms of the GNU General Public License as published by
   9  * the Free Software Foundation; either version 3 of the License, or
  10  * (at your option) any later version.
  11  *
  12  * This program is distributed in the hope that it will be useful,
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15  * GNU General Public License for more details.
  16  *
  17  * You should have received a copy of the GNU General Public License
  18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  19  */
  20 
  21 #include "includes.h"
  22 
  23 static int compare_dirent (const void *a, const void *b) {
     /* [<][>][^][v][top][bottom][index][help] */
  24         const SMB_STRUCT_DIRENT *da = (const SMB_STRUCT_DIRENT *) a;
  25         const SMB_STRUCT_DIRENT *db = (const SMB_STRUCT_DIRENT *) b;
  26         return StrCaseCmp(da->d_name, db->d_name);
  27 }
  28 
  29 struct dirsort_privates {
  30         long pos;
  31         SMB_STRUCT_DIRENT *directory_list;
  32         long number_of_entries;
  33         time_t mtime;
  34         SMB_STRUCT_DIR *source_directory;
  35         int fd;
  36 };
  37 
  38 static void free_dirsort_privates(void **datap) {
     /* [<][>][^][v][top][bottom][index][help] */
  39         struct dirsort_privates *data = (struct dirsort_privates *) *datap;
  40         SAFE_FREE(data->directory_list);
  41         SAFE_FREE(data);
  42         *datap = NULL;
  43 
  44         return;
  45 }
  46 
  47 static void open_and_sort_dir (vfs_handle_struct *handle)
     /* [<][>][^][v][top][bottom][index][help] */
  48 {
  49         SMB_STRUCT_DIRENT *dp;
  50         struct stat dir_stat;
  51         long current_pos;
  52         struct dirsort_privates *data = NULL;
  53 
  54         SMB_VFS_HANDLE_GET_DATA(handle, data, struct dirsort_privates, return);
  55 
  56         data->number_of_entries = 0;
  57 
  58         if (fstat(data->fd, &dir_stat) == 0) {
  59                 data->mtime = dir_stat.st_mtime;
  60         }
  61 
  62         while (SMB_VFS_NEXT_READDIR(handle, data->source_directory, NULL)
  63                != NULL) {
  64                 data->number_of_entries++;
  65         }
  66 
  67         /* Open the underlying directory and count the number of entries
  68            Skip back to the beginning as we'll read it again */
  69         SMB_VFS_NEXT_REWINDDIR(handle, data->source_directory);
  70 
  71         /* Set up an array and read the directory entries into it */
  72         SAFE_FREE(data->directory_list); /* destroy previous cache if needed */
  73         data->directory_list = (SMB_STRUCT_DIRENT *)SMB_MALLOC(
  74                 data->number_of_entries * sizeof(SMB_STRUCT_DIRENT));
  75         current_pos = data->pos;
  76         data->pos = 0;
  77         while ((dp = SMB_VFS_NEXT_READDIR(handle, data->source_directory,
  78                                           NULL)) != NULL) {
  79                 data->directory_list[data->pos++] = *dp;
  80         }
  81 
  82         /* Sort the directory entries by name */
  83         data->pos = current_pos;
  84         qsort(data->directory_list, data->number_of_entries,
  85               sizeof(SMB_STRUCT_DIRENT), compare_dirent);
  86 }
  87 
  88 static SMB_STRUCT_DIR *dirsort_opendir(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
  89                                        const char *fname, const char *mask,
  90                                        uint32 attr)
  91 {
  92         struct dirsort_privates *data = NULL;
  93 
  94         /* set up our private data about this directory */
  95         data = (struct dirsort_privates *)SMB_MALLOC(
  96                 sizeof(struct dirsort_privates));
  97 
  98         data->directory_list = NULL;
  99         data->pos = 0;
 100 
 101         /* Open the underlying directory and count the number of entries */
 102         data->source_directory = SMB_VFS_NEXT_OPENDIR(handle, fname, mask,
 103                                                       attr);
 104 
 105         data->fd = dirfd(data->source_directory);
 106 
 107         SMB_VFS_HANDLE_SET_DATA(handle, data, free_dirsort_privates,
 108                                 struct dirsort_privates, return NULL);
 109 
 110         open_and_sort_dir(handle);
 111 
 112         return data->source_directory;
 113 }
 114 
 115 static SMB_STRUCT_DIRENT *dirsort_readdir(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 116                                           SMB_STRUCT_DIR *dirp)
 117 {
 118         struct dirsort_privates *data = NULL;
 119         time_t current_mtime;
 120         struct stat dir_stat;
 121 
 122         SMB_VFS_HANDLE_GET_DATA(handle, data, struct dirsort_privates,
 123                                 return NULL);
 124 
 125         if (fstat(data->fd, &dir_stat) == -1) {
 126                 return NULL;
 127         }
 128 
 129         current_mtime = dir_stat.st_mtime;
 130 
 131         /* throw away cache and re-read the directory if we've changed */
 132         if (current_mtime > data->mtime) {
 133                 open_and_sort_dir(handle);
 134         }
 135 
 136         if (data->pos >= data->number_of_entries) {
 137                 return NULL;
 138         }
 139 
 140         return &data->directory_list[data->pos++];
 141 }
 142 
 143 static void dirsort_seekdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp,
     /* [<][>][^][v][top][bottom][index][help] */
 144                             long offset)
 145 {
 146         struct dirsort_privates *data = NULL;
 147         SMB_VFS_HANDLE_GET_DATA(handle, data, struct dirsort_privates, return);
 148 
 149         data->pos = offset;
 150 }
 151 
 152 static long dirsort_telldir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp)
     /* [<][>][^][v][top][bottom][index][help] */
 153 {
 154         struct dirsort_privates *data = NULL;
 155         SMB_VFS_HANDLE_GET_DATA(handle, data, struct dirsort_privates,
 156                                 return -1);
 157 
 158         return data->pos;
 159 }
 160 
 161 static void dirsort_rewinddir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp)
     /* [<][>][^][v][top][bottom][index][help] */
 162 {
 163         struct dirsort_privates *data = NULL;
 164         SMB_VFS_HANDLE_GET_DATA(handle, data, struct dirsort_privates, return);
 165 
 166         data->pos = 0;
 167 }
 168 
 169 /* VFS operations structure */
 170 
 171 static vfs_op_tuple dirsort_op_tuples[] = {
 172 
 173     /* Directory operations */
 174 
 175     {SMB_VFS_OP(dirsort_opendir),            SMB_VFS_OP_OPENDIR,
 176      SMB_VFS_LAYER_TRANSPARENT},
 177     {SMB_VFS_OP(dirsort_readdir),            SMB_VFS_OP_READDIR,
 178      SMB_VFS_LAYER_TRANSPARENT},
 179     {SMB_VFS_OP(dirsort_seekdir),            SMB_VFS_OP_SEEKDIR,
 180      SMB_VFS_LAYER_TRANSPARENT},
 181     {SMB_VFS_OP(dirsort_telldir),            SMB_VFS_OP_TELLDIR,
 182      SMB_VFS_LAYER_TRANSPARENT},
 183     {SMB_VFS_OP(dirsort_rewinddir),          SMB_VFS_OP_REWINDDIR,
 184      SMB_VFS_LAYER_TRANSPARENT},
 185 
 186     {NULL,                                   SMB_VFS_OP_NOOP,
 187      SMB_VFS_LAYER_NOOP}
 188 };
 189 
 190 NTSTATUS vfs_dirsort_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 191 {
 192         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "dirsort",
 193                                 dirsort_op_tuples);
 194 }

/* [<][>][^][v][top][bottom][index][help] */