180bca3d3SAxel Dörfler/* ntfsdir.c - directory functions
280bca3d3SAxel Dörfler *
3570ab00aSGerasim Troeglazov * Copyright (c) 2006 Troeglazov Gerasim (3dEyes**)
480bca3d3SAxel Dörfler *
580bca3d3SAxel Dörfler * This program/include file is free software; you can redistribute it and/or
680bca3d3SAxel Dörfler * modify it under the terms of the GNU General Public License as published
780bca3d3SAxel Dörfler * by the Free Software Foundation; either version 2 of the License, or
880bca3d3SAxel Dörfler * (at your option) any later version.
980bca3d3SAxel Dörfler *
1080bca3d3SAxel Dörfler * This program/include file is distributed in the hope that it will be
1180bca3d3SAxel Dörfler * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
1380bca3d3SAxel Dörfler * GNU General Public License for more details.
1480bca3d3SAxel Dörfler *
1580bca3d3SAxel Dörfler * You should have received a copy of the GNU General Public License
1680bca3d3SAxel Dörfler * along with this program (in the main directory of the Linux-NTFS
1780bca3d3SAxel Dörfler * distribution in the file COPYING); if not, write to the Free Software
1880bca3d3SAxel Dörfler * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1980bca3d3SAxel Dörfler */
2079dd7e57SMichael Lotz
21b62dd5abSJérôme Duval
22b62dd5abSJérôme Duval#include "ntfsdir.h"
23b62dd5abSJérôme Duval
24b62dd5abSJérôme Duval#include <ctype.h>
25b62dd5abSJérôme Duval#include <dirent.h>
2680bca3d3SAxel Dörfler#include <errno.h>
27b62dd5abSJérôme Duval#include <fcntl.h>
28b62dd5abSJérôme Duval#include <stdio.h>
29b62dd5abSJérôme Duval#include <stdlib.h>
3080bca3d3SAxel Dörfler#include <string.h>
3180bca3d3SAxel Dörfler#include <time.h>
32b62dd5abSJérôme Duval#include <unistd.h>
3380bca3d3SAxel Dörfler#include <sys/stat.h>
3480bca3d3SAxel Dörfler
3579dd7e57SMichael Lotz
3639f5f304Sthreedeyesstatic int
3739f5f304Sthreedeyes_ntfs_dirent_filler(void *_dirent, const ntfschar *name,
3879dd7e57SMichael Lotz	const int name_len, const int name_type, const s64 pos, const MFT_REF mref,
3979dd7e57SMichael Lotz	const unsigned dt_type)
4080bca3d3SAxel Dörfler{
4180bca3d3SAxel Dörfler	char *filename = NULL;
4279dd7e57SMichael Lotz	dircookie *cookie = (dircookie*)_dirent;
4379dd7e57SMichael Lotz
446a15f740SGerasim Troeglazov	if (name_type == FILE_NAME_DOS)
456a15f740SGerasim Troeglazov		return 0;
4679dd7e57SMichael Lotz
4779dd7e57SMichael Lotz	if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user
4839f5f304Sthreedeyes		|| cookie->show_sys_files) {
4939f5f304Sthreedeyes		int len = ntfs_ucstombs(name, name_len, &filename, 0);
5039f5f304Sthreedeyes		if (len >= 0 && filename != NULL) {
5139f5f304Sthreedeyes			cache_entry* new_entry =
5239f5f304Sthreedeyes				(cache_entry*)ntfs_calloc(sizeof(cache_entry));
5339f5f304Sthreedeyes			if (new_entry == NULL) {
5439f5f304Sthreedeyes				free(filename);
5539f5f304Sthreedeyes				return -1;
5639f5f304Sthreedeyes			}
5839f5f304Sthreedeyes			new_entry->ent =
5939f5f304Sthreedeyes				(struct dirent*)ntfs_calloc(sizeof(struct dirent) + len);
6039f5f304Sthreedeyes			new_entry->ent->d_dev = cookie->dev_id;
6139f5f304Sthreedeyes			new_entry->ent->d_ino = MREF(mref);
6239f5f304Sthreedeyes			memcpy(new_entry->ent->d_name,filename, len + 1);
6339f5f304Sthreedeyes			new_entry->ent->d_reclen =  sizeof(struct dirent) + len;
656882e5efSGerasim Troeglazov			if (cookie->cache_root == NULL || cookie->entry == NULL) {
6639f5f304Sthreedeyes				cookie->cache_root = new_entry;
6739f5f304Sthreedeyes				cookie->entry = cookie->cache_root;
6839f5f304Sthreedeyes				cookie->entry->next = NULL;
6939f5f304Sthreedeyes			} else {
7039f5f304Sthreedeyes				cookie->entry->next = (void*)new_entry;
7139f5f304Sthreedeyes				cookie->entry = cookie->entry->next;
7239f5f304Sthreedeyes				cookie->entry->next = NULL;
7330bc84e9SGerasim Troeglazov			}
7479dd7e57SMichael Lotz
7539f5f304Sthreedeyes		   	free(filename);
7639f5f304Sthreedeyes		   	return 0;
7779dd7e57SMichael Lotz		}
7839f5f304Sthreedeyes		return -1;
7979dd7e57SMichael Lotz	}
8080bca3d3SAxel Dörfler	return 0;
8180bca3d3SAxel Dörfler}
8280bca3d3SAxel Dörfler
8379dd7e57SMichael Lotz
8480bca3d3SAxel Dörflerstatus_t
8539f5f304Sthreedeyesfs_free_dircookie(fs_volume *_vol, fs_vnode *vnode, void *_cookie)
8680bca3d3SAxel Dörfler{
8731aa96d8SGerasim Troeglazov	nspace		*ns = (nspace*)_vol->private_volume;
8839f5f304Sthreedeyes	dircookie	*cookie = (dircookie*)_cookie;
9039f5f304Sthreedeyes	LOCK_VOL(ns);
914375e3f9SJérôme Duval	TRACE("fs_free_dircookie - ENTER\n");
9339f5f304Sthreedeyes	if (cookie != NULL) {
9439f5f304Sthreedeyes		cache_entry *entry = cookie->cache_root;
95bd2b61fbSthreedeyes		while (entry != NULL) {
9639f5f304Sthreedeyes			cache_entry *next = entry->next;
976882e5efSGerasim Troeglazov			free(entry->ent);
9839f5f304Sthreedeyes			free(entry);
9939f5f304Sthreedeyes			entry = next;
10039f5f304Sthreedeyes		}
10179dd7e57SMichael Lotz		free(cookie);
10239f5f304Sthreedeyes	}
10380bca3d3SAxel Dörfler
1044375e3f9SJérôme Duval	TRACE("fs_free_dircookie - EXIT\n");
10580bca3d3SAxel Dörfler	UNLOCK_VOL(ns);
10680bca3d3SAxel Dörfler
10780bca3d3SAxel Dörfler	return B_NO_ERROR;
10880bca3d3SAxel Dörfler}
10980bca3d3SAxel Dörfler
11079dd7e57SMichael Lotz
11180bca3d3SAxel Dörflerstatus_t
11279dd7e57SMichael Lotzfs_opendir(fs_volume *_vol, fs_vnode *_node, void** _cookie)
11380bca3d3SAxel Dörfler{
11431aa96d8SGerasim Troeglazov	nspace		*ns = (nspace*)_vol->private_volume;
11531aa96d8SGerasim Troeglazov	vnode		*node = (vnode*)_node->private_node;
11605326911SJérôme Duval	dircookie	*cookie = NULL;
11779dd7e57SMichael Lotz	ntfs_inode	*ni = NULL;
11839f5f304Sthreedeyes	int			result = B_NO_ERROR;
11979dd7e57SMichael Lotz
12080bca3d3SAxel Dörfler	LOCK_VOL(ns);
1214375e3f9SJérôme Duval	TRACE("fs_opendir - ENTER\n");
12279dd7e57SMichael Lotz
12379dd7e57SMichael Lotz	ni = ntfs_inode_open(ns->ntvol, node->vnid);
12479dd7e57SMichael Lotz	if (ni == NULL) {
12579dd7e57SMichael Lotz		result = ENOENT;
12679dd7e57SMichael Lotz		goto exit;
12779dd7e57SMichael Lotz	}
12880bca3d3SAxel Dörfler
12980bca3d3SAxel Dörfler	if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
13080bca3d3SAxel Dörfler		result = EMFILE;
13180bca3d3SAxel Dörfler		goto exit;
13280bca3d3SAxel Dörfler	}
133570ab00aSGerasim Troeglazov
13405326911SJérôme Duval	cookie = (dircookie*)ntfs_calloc(sizeof(dircookie));
13579dd7e57SMichael Lotz	if (cookie != NULL) {
13679dd7e57SMichael Lotz		cookie->pos = 0;
13739f5f304Sthreedeyes		cookie->dev_id = ns->id;
138570ab00aSGerasim Troeglazov		cookie->show_sys_files = ns->show_sys_files;
13939f5f304Sthreedeyes		cookie->cache_root = NULL;
14039f5f304Sthreedeyes		cookie->entry = cookie->cache_root;
14180bca3d3SAxel Dörfler		*_cookie = (void*)cookie;
14279dd7e57SMichael Lotz	} else
143570ab00aSGerasim Troeglazov		result = ENOMEM;
14479dd7e57SMichael Lotz
14579dd7e57SMichael Lotzexit:
14639f5f304Sthreedeyes	if (ni != NULL)
14779dd7e57SMichael Lotz		ntfs_inode_close(ni);
14879dd7e57SMichael Lotz
1494375e3f9SJérôme Duval	TRACE("fs_opendir - EXIT\n");
15080bca3d3SAxel Dörfler	UNLOCK_VOL(ns);
151570ab00aSGerasim Troeglazov
15280bca3d3SAxel Dörfler	return result;
15380bca3d3SAxel Dörfler}
15480bca3d3SAxel Dörfler
15579dd7e57SMichael Lotz
15680bca3d3SAxel Dörflerstatus_t
15779dd7e57SMichael Lotzfs_closedir(fs_volume *_vol, fs_vnode *_node, void *cookie)
15880bca3d3SAxel Dörfler{
15939f5f304Sthreedeyes	return B_NO_ERROR;
16080bca3d3SAxel Dörfler}
16180bca3d3SAxel Dörfler
16279dd7e57SMichael Lotz
16380bca3d3SAxel Dörflerstatus_t
1646b81e706SMichael Lotzfs_readdir(fs_volume *_vol, fs_vnode *_node, void *_cookie, struct dirent *buf,
1656b81e706SMichael Lotz	size_t bufsize, uint32 *num)
16680bca3d3SAxel Dörfler{
16731aa96d8SGerasim Troeglazov	nspace		*ns = (nspace*)_vol->private_volume;
16831aa96d8SGerasim Troeglazov	vnode		*node = (vnode*)_node->private_node;
16980bca3d3SAxel Dörfler	dircookie	*cookie = (dircookie*)_cookie;
17039f5f304Sthreedeyes	ntfs_inode	*ni = NULL;
1726b81e706SMichael Lotz	uint32 		nameLength = bufsize - sizeof(struct dirent), realLen;
173570ab00aSGerasim Troeglazov	int 		result = B_NO_ERROR;
17479dd7e57SMichael Lotz
17580bca3d3SAxel Dörfler	LOCK_VOL(ns);
1764375e3f9SJérôme Duval	TRACE("fs_readdir - ENTER (sizeof(buf)=%d, bufsize=%d, num=%d\n",
1774375e3f9SJérôme Duval		sizeof(buf), bufsize, *num);
1798f226f2eSPhilippe Saint-Pierre	if (!ns || !node || !cookie || !num || bufsize < sizeof(*buf)) {
180570ab00aSGerasim Troeglazov	 	result = EINVAL;
181570ab00aSGerasim Troeglazov		goto exit;
18279dd7e57SMichael Lotz	}
18379dd7e57SMichael Lotz
18479dd7e57SMichael Lotz	ni = ntfs_inode_open(ns->ntvol, node->vnid);
18579dd7e57SMichael Lotz	if (ni == NULL) {
18639f5f304Sthreedeyes		TRACE("fs_readdir - dir not opened\n");
187570ab00aSGerasim Troeglazov		result = ENOENT;
188570ab00aSGerasim Troeglazov		goto exit;
18979dd7e57SMichael Lotz	}
19079dd7e57SMichael Lotz
1916882e5efSGerasim Troeglazov	if (cookie->cache_root == NULL) {
19239f5f304Sthreedeyes		cookie->entry = NULL;
19339f5f304Sthreedeyes		result = ntfs_readdir(ni, &cookie->pos, cookie,
19439f5f304Sthreedeyes			(ntfs_filldir_t)_ntfs_dirent_filler);
19539f5f304Sthreedeyes		cookie->entry = cookie->cache_root;
1966882e5efSGerasim Troeglazov		if (result) {
19739f5f304Sthreedeyes			result = ENOENT;
19839f5f304Sthreedeyes			goto exit;
19939f5f304Sthreedeyes		}
20039f5f304Sthreedeyes	}
20130bc84e9SGerasim Troeglazov
2026882e5efSGerasim Troeglazov	if (cookie->entry == NULL) {
20339f5f304Sthreedeyes		result = ENOENT;
20439f5f304Sthreedeyes		goto exit;
20539f5f304Sthreedeyes	}
2076882e5efSGerasim Troeglazov	if (cookie->entry->ent == NULL) {
20839f5f304Sthreedeyes		result = ENOENT;
20939f5f304Sthreedeyes		goto exit;
21039f5f304Sthreedeyes	}
2126b81e706SMichael Lotz	realLen = nameLength > 255 ? 255 : nameLength;
21430bc84e9SGerasim Troeglazov	buf->d_dev = ns->id;
21539f5f304Sthreedeyes	buf->d_ino = cookie->entry->ent->d_ino;
21639f5f304Sthreedeyes	strlcpy(buf->d_name, cookie->entry->ent->d_name, realLen + 1);
2176b81e706SMichael Lotz	buf->d_reclen = sizeof(struct dirent) + realLen;
21939f5f304Sthreedeyes	cookie->entry = (cache_entry*)cookie->entry->next;
22079dd7e57SMichael Lotz
2214375e3f9SJérôme Duval	TRACE("fs_readdir - FILE: [%s]\n",buf->d_name);
22280bca3d3SAxel Dörfler
223570ab00aSGerasim Troeglazovexit:
22439f5f304Sthreedeyes	if (ni != NULL)
225570ab00aSGerasim Troeglazov		ntfs_inode_close(ni);
22679dd7e57SMichael Lotz
22779dd7e57SMichael Lotz	if (result == B_NO_ERROR)
22880bca3d3SAxel Dörfler		*num = 1;
22980bca3d3SAxel Dörfler	else
23080bca3d3SAxel Dörfler		*num = 0;
23179dd7e57SMichael Lotz
23279dd7e57SMichael Lotz	if (result == ENOENT)
23380bca3d3SAxel Dörfler		result = B_NO_ERROR;
23480bca3d3SAxel Dörfler
23539f5f304Sthreedeyes	TRACE("fs_readdir - EXIT num=%d result (%s)\n",*num, strerror(result));
23680bca3d3SAxel Dörfler	UNLOCK_VOL(ns);
23779dd7e57SMichael Lotz
23880bca3d3SAxel Dörfler	return result;
23980bca3d3SAxel Dörfler}
24079dd7e57SMichael Lotz
24179dd7e57SMichael Lotz
24280bca3d3SAxel Dörflerstatus_t
243bd2b61fbSthreedeyesfs_rewinddir(fs_volume *_vol, fs_vnode *_node, void *_cookie)
24480bca3d3SAxel Dörfler{
24531aa96d8SGerasim Troeglazov	nspace		*ns = (nspace*)_vol->private_volume;
2467106362eSGerasim Troeglazov	dircookie	*cookie = (dircookie*)_cookie;
247570ab00aSGerasim Troeglazov	int			result = EINVAL;
248570ab00aSGerasim Troeglazov
24980bca3d3SAxel Dörfler	LOCK_VOL(ns);
2504375e3f9SJérôme Duval	TRACE("fs_rewinddir - ENTER\n");
25279dd7e57SMichael Lotz	if (cookie != NULL) {
25339f5f304Sthreedeyes		cache_entry *entry = cookie->cache_root;
254bd2b61fbSthreedeyes		while (entry != NULL) {
25539f5f304Sthreedeyes			cache_entry *next = entry->next;
2566882e5efSGerasim Troeglazov			free(entry->ent);
25739f5f304Sthreedeyes			free(entry);
25839f5f304Sthreedeyes			entry = next;
25939f5f304Sthreedeyes		}
26079dd7e57SMichael Lotz		cookie->pos = 0;
26139f5f304Sthreedeyes		cookie->dev_id = ns->id;
26239f5f304Sthreedeyes		cookie->show_sys_files = ns->show_sys_files;
26339f5f304Sthreedeyes		cookie->cache_root = NULL;
26439f5f304Sthreedeyes		cookie->entry = cookie->cache_root;
26580bca3d3SAxel Dörfler		result = B_NO_ERROR;
26680bca3d3SAxel Dörfler	}
26779dd7e57SMichael Lotz
2684375e3f9SJérôme Duval	TRACE("fs_rewinddir - EXIT, result is %s\n", strerror(result));
26980bca3d3SAxel Dörfler	UNLOCK_VOL(ns);
27079dd7e57SMichael Lotz
27180bca3d3SAxel Dörfler	return result;
27280bca3d3SAxel Dörfler}