1/* ntfsdir.c - directory functions 2 * 3 * Copyright (c) 2006 Troeglazov Gerasim (3dEyes**) 4 * 5 * This program/include file is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as published 7 * by the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program/include file is distributed in the hope that it will be 11 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program (in the main directory of the Linux-NTFS 17 * distribution in the file COPYING); if not, write to the Free Software 18 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 22#include "ntfsdir.h" 23 24#include <ctype.h> 25#include <dirent.h> 26#include <errno.h> 27#include <fcntl.h> 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31#include <time.h> 32#include <unistd.h> 33#include <sys/stat.h> 34 35 36static int 37_ntfs_dirent_filler(void *_dirent, const ntfschar *name, 38 const int name_len, const int name_type, const s64 pos, const MFT_REF mref, 39 const unsigned dt_type) 40{ 41 char *filename = NULL; 42 dircookie *cookie = (dircookie*)_dirent; 43 44 if (name_type == FILE_NAME_DOS) 45 return 0; 46 47 if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user 48 || cookie->show_sys_files) { 49 int len = ntfs_ucstombs(name, name_len, &filename, 0); 50 if (len >= 0 && filename != NULL) { 51 cache_entry* new_entry = 52 (cache_entry*)ntfs_calloc(sizeof(cache_entry)); 53 if (new_entry == NULL) { 54 free(filename); 55 return -1; 56 } 57 58 new_entry->ent = 59 (struct dirent*)ntfs_calloc(sizeof(struct dirent) + len); 60 new_entry->ent->d_dev = cookie->dev_id; 61 new_entry->ent->d_ino = MREF(mref); 62 memcpy(new_entry->ent->d_name,filename, len + 1); 63 new_entry->ent->d_reclen = sizeof(struct dirent) + len; 64 65 if(cookie->cache_root == NULL || cookie->entry == NULL) { 66 cookie->cache_root = new_entry; 67 cookie->entry = cookie->cache_root; 68 cookie->entry->next = NULL; 69 } else { 70 cookie->entry->next = (void*)new_entry; 71 cookie->entry = cookie->entry->next; 72 cookie->entry->next = NULL; 73 } 74 75 free(filename); 76 return 0; 77 } 78 return -1; 79 } 80 return 0; 81} 82 83 84status_t 85fs_free_dircookie(fs_volume *_vol, fs_vnode *vnode, void *_cookie) 86{ 87 nspace *ns = (nspace*)_vol->private_volume; 88 dircookie *cookie = (dircookie*)_cookie; 89 90 LOCK_VOL(ns); 91 TRACE("fs_free_dircookie - ENTER\n"); 92 93 if (cookie != NULL) { 94 cache_entry *entry = cookie->cache_root; 95 while (entry != NULL) { 96 cache_entry *next = entry->next; 97 if (entry->ent != NULL) 98 free(entry->ent); 99 free(entry); 100 entry = next; 101 } 102 free(cookie); 103 } 104 105 TRACE("fs_free_dircookie - EXIT\n"); 106 UNLOCK_VOL(ns); 107 108 return B_NO_ERROR; 109} 110 111 112status_t 113fs_opendir(fs_volume *_vol, fs_vnode *_node, void** _cookie) 114{ 115 nspace *ns = (nspace*)_vol->private_volume; 116 vnode *node = (vnode*)_node->private_node; 117 dircookie *cookie = NULL; 118 ntfs_inode *ni = NULL; 119 int result = B_NO_ERROR; 120 121 LOCK_VOL(ns); 122 TRACE("fs_opendir - ENTER\n"); 123 124 ni = ntfs_inode_open(ns->ntvol, node->vnid); 125 if (ni == NULL) { 126 result = ENOENT; 127 goto exit; 128 } 129 130 if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) { 131 result = EMFILE; 132 goto exit; 133 } 134 135 cookie = (dircookie*)ntfs_calloc(sizeof(dircookie)); 136 if (cookie != NULL) { 137 cookie->pos = 0; 138 cookie->dev_id = ns->id; 139 cookie->show_sys_files = ns->show_sys_files; 140 cookie->cache_root = NULL; 141 cookie->entry = cookie->cache_root; 142 *_cookie = (void*)cookie; 143 } else 144 result = ENOMEM; 145 146exit: 147 if (ni != NULL) 148 ntfs_inode_close(ni); 149 150 TRACE("fs_opendir - EXIT\n"); 151 UNLOCK_VOL(ns); 152 153 return result; 154} 155 156 157status_t 158fs_closedir(fs_volume *_vol, fs_vnode *_node, void *cookie) 159{ 160 return B_NO_ERROR; 161} 162 163 164status_t 165fs_readdir(fs_volume *_vol, fs_vnode *_node, void *_cookie, struct dirent *buf, 166 size_t bufsize, uint32 *num) 167{ 168 nspace *ns = (nspace*)_vol->private_volume; 169 vnode *node = (vnode*)_node->private_node; 170 dircookie *cookie = (dircookie*)_cookie; 171 ntfs_inode *ni = NULL; 172 173 uint32 nameLength = bufsize - sizeof(struct dirent), realLen; 174 int result = B_NO_ERROR; 175 176 LOCK_VOL(ns); 177 TRACE("fs_readdir - ENTER (sizeof(buf)=%d, bufsize=%d, num=%d\n", 178 sizeof(buf), bufsize, *num); 179 180 if (!ns || !node || !cookie || !num || bufsize < sizeof(*buf)) { 181 result = EINVAL; 182 goto exit; 183 } 184 185 ni = ntfs_inode_open(ns->ntvol, node->vnid); 186 if (ni == NULL) { 187 TRACE("fs_readdir - dir not opened\n"); 188 result = ENOENT; 189 goto exit; 190 } 191 192 if(cookie->cache_root == NULL) { 193 cookie->entry = NULL; 194 result = ntfs_readdir(ni, &cookie->pos, cookie, 195 (ntfs_filldir_t)_ntfs_dirent_filler); 196 cookie->entry = cookie->cache_root; 197 if(result) { 198 result = ENOENT; 199 goto exit; 200 } 201 } 202 203 if(cookie->entry == NULL) { 204 result = ENOENT; 205 goto exit; 206 } 207 208 if(cookie->entry->ent == NULL) { 209 result = ENOENT; 210 goto exit; 211 } 212 213 realLen = nameLength > 255 ? 255 : nameLength; 214 215 buf->d_dev = ns->id; 216 buf->d_ino = cookie->entry->ent->d_ino; 217 strlcpy(buf->d_name, cookie->entry->ent->d_name, realLen + 1); 218 buf->d_reclen = sizeof(struct dirent) + realLen; 219 220 cookie->entry = (cache_entry*)cookie->entry->next; 221 222 TRACE("fs_readdir - FILE: [%s]\n",buf->d_name); 223 224exit: 225 if (ni != NULL) 226 ntfs_inode_close(ni); 227 228 if (result == B_NO_ERROR) 229 *num = 1; 230 else 231 *num = 0; 232 233 if (result == ENOENT) 234 result = B_NO_ERROR; 235 236 TRACE("fs_readdir - EXIT num=%d result (%s)\n",*num, strerror(result)); 237 UNLOCK_VOL(ns); 238 239 return result; 240} 241 242 243status_t 244fs_rewinddir(fs_volume *_vol, fs_vnode *_node, void *_cookie) 245{ 246 nspace *ns = (nspace*)_vol->private_volume; 247 dircookie *cookie = (dircookie*)_cookie; 248 int result = EINVAL; 249 250 LOCK_VOL(ns); 251 TRACE("fs_rewinddir - ENTER\n"); 252 253 if (cookie != NULL) { 254 cache_entry *entry = cookie->cache_root; 255 while (entry != NULL) { 256 cache_entry *next = entry->next; 257 if (entry->ent != NULL) 258 free(entry->ent); 259 free(entry); 260 entry = next; 261 } 262 cookie->pos = 0; 263 cookie->dev_id = ns->id; 264 cookie->show_sys_files = ns->show_sys_files; 265 cookie->cache_root = NULL; 266 cookie->entry = cookie->cache_root; 267 result = B_NO_ERROR; 268 } 269 270 TRACE("fs_rewinddir - EXIT, result is %s\n", strerror(result)); 271 UNLOCK_VOL(ns); 272 273 return result; 274} 275