1/*
2 * support.c -  Specific support functions
3 *
4 * Copyright (C) 1997 Martin von L�wis
5 * Copyright (C) 1997 R�gis Duchesne
6 * Copyright (C) 2001 Anton Altaparmakov (AIA)
7 */
8
9#include "ntfstypes.h"
10#include "struct.h"
11#include "support.h"
12
13#include <stdarg.h>
14#include <linux/slab.h>
15#include <linux/locks.h>
16#include <linux/fs.h>
17#include "util.h"
18#include "inode.h"
19#include "macros.h"
20#include <linux/nls.h>
21
22static char print_buf[1024];
23
24#ifdef DEBUG
25#include "sysctl.h"
26#include <linux/kernel.h>
27
28/* Debugging output */
29void ntfs_debug(int mask, const char *fmt, ...)
30{
31	va_list ap;
32
33	/* Filter it with the debugging level required */
34	if (ntdebug & mask) {
35		va_start(ap,fmt);
36		strcpy(print_buf, KERN_DEBUG "NTFS: ");
37		vsprintf(print_buf + 9, fmt, ap);
38		printk(print_buf);
39		va_end(ap);
40	}
41}
42
43#ifndef ntfs_malloc
44/* Verbose kmalloc */
45void *ntfs_malloc(int size)
46{
47	void *ret;
48
49	ret = kmalloc(size, GFP_KERNEL);
50	ntfs_debug(DEBUG_MALLOC, "Allocating %x at %p\n", size, ret);
51
52	return ret;
53}
54#endif
55
56#ifndef ntfs_free
57/* Verbose kfree() */
58void ntfs_free(void *block)
59{
60        ntfs_debug(DEBUG_MALLOC, "Freeing memory at %p\n", block);
61	kfree(block);
62}
63#endif
64#else /* End of DEBUG functions. Normal ones below... */
65
66#ifndef ntfs_malloc
67void *ntfs_malloc(int size)
68{
69	return kmalloc(size, GFP_KERNEL);
70}
71#endif
72
73#ifndef ntfs_free
74void ntfs_free(void *block)
75{
76	kfree(block);
77}
78#endif
79#endif /* DEBUG */
80
81void ntfs_bzero(void *s, int n)
82{
83	memset(s, 0, n);
84}
85
86/* These functions deliberately return no value. It is dest, anyway,
87   and not used anywhere in the NTFS code.  */
88
89void ntfs_memcpy(void *dest, const void *src, ntfs_size_t n)
90{
91	memcpy(dest, src, n);
92}
93
94void ntfs_memmove(void *dest, const void *src, ntfs_size_t n)
95{
96	memmove(dest, src, n);
97}
98
99/* Warn that an error occurred. */
100void ntfs_error(const char *fmt,...)
101{
102        va_list ap;
103
104        va_start(ap, fmt);
105        strcpy(print_buf, KERN_ERR "NTFS: ");
106        vsprintf(print_buf + 9, fmt, ap);
107        printk(print_buf);
108        va_end(ap);
109}
110
111int ntfs_read_mft_record(ntfs_volume *vol, int mftno, char *buf)
112{
113	int error;
114	ntfs_io io;
115
116	ntfs_debug(DEBUG_OTHER, "read_mft_record 0x%x\n", mftno);
117	if (mftno == FILE_Mft)
118	{
119		ntfs_memcpy(buf, vol->mft, vol->mft_record_size);
120		return 0;
121	}
122	if (!vol->mft_ino)
123	{
124		printk(KERN_ERR "NTFS: mft_ino is NULL. Something is terribly "
125				"wrong here!\n");
126		return -ENODATA;
127	}
128 	io.fn_put = ntfs_put;
129	io.fn_get = 0;
130	io.param = buf;
131	io.size = vol->mft_record_size;
132	ntfs_debug(DEBUG_OTHER, "read_mft_record: calling ntfs_read_attr with: "
133		"mftno = 0x%x, vol->mft_record_size_bits = 0x%x, "
134		"mftno << vol->mft_record_size_bits = 0x%Lx\n", mftno,
135		vol->mft_record_size_bits,
136		(__s64)mftno << vol->mft_record_size_bits);
137	error = ntfs_read_attr(vol->mft_ino, vol->at_data, NULL,
138				(__s64)mftno << vol->mft_record_size_bits, &io);
139	if (error || (io.size != vol->mft_record_size)) {
140		ntfs_debug(DEBUG_OTHER, "read_mft_record: read 0x%x failed "
141				   	"(%d,%d,%d)\n", mftno, error, io.size,
142				   	vol->mft_record_size);
143		return error ? error : -ENODATA;
144	}
145	ntfs_debug(DEBUG_OTHER, "read_mft_record: finished read 0x%x\n", mftno);
146	if (!ntfs_check_mft_record(vol, buf)) {
147		printk(KERN_WARNING "NTFS: Invalid MFT record for 0x%x\n", mftno);
148		return -EIO;
149	}
150	ntfs_debug(DEBUG_OTHER, "read_mft_record: Done 0x%x\n", mftno);
151	return 0;
152}
153
154int ntfs_getput_clusters(ntfs_volume *vol, int cluster, ntfs_size_t start_offs,
155		ntfs_io *buf)
156{
157	struct super_block *sb = NTFS_SB(vol);
158	struct buffer_head *bh;
159	int length = buf->size;
160	int error = 0;
161	ntfs_size_t to_copy;
162
163	ntfs_debug(DEBUG_OTHER, "%s_clusters %d %d %d\n",
164		   buf->do_read ? "get" : "put", cluster, start_offs, length);
165	to_copy = vol->cluster_size - start_offs;
166	while (length) {
167		if (!(bh = sb_bread(sb, cluster))) {
168			ntfs_debug(DEBUG_OTHER, "%s failed\n",
169				   buf->do_read ? "Reading" : "Writing");
170			error = -EIO;
171			goto error_ret;
172		}
173		if (to_copy > length)
174			to_copy = length;
175		lock_buffer(bh);
176		if (buf->do_read) {
177			buf->fn_put(buf, bh->b_data + start_offs, to_copy);
178			unlock_buffer(bh);
179		} else {
180			buf->fn_get(bh->b_data + start_offs, buf, to_copy);
181			mark_buffer_dirty(bh);
182			unlock_buffer(bh);
183			/*
184			 * Note: We treat synchronous IO on a per volume basis
185			 * disregarding flags of individual inodes. This can
186			 * lead to some strange write ordering effects upon a
187			 * remount with a change in the sync flag but it should
188			 * not break anything. [Except if the system crashes
189			 * at that point in time but there would be more thigs
190			 * to worry about than that in that case...]. (AIA)
191			 */
192			if (sb->s_flags & MS_SYNCHRONOUS) {
193				ll_rw_block(WRITE, 1, &bh);
194				wait_on_buffer(bh);
195				if (buffer_req(bh) && !buffer_uptodate(bh)) {
196					printk(KERN_ERR "IO error syncing NTFS "
197					       "cluster [%s:%i]\n",
198					       bdevname(sb->s_dev), cluster);
199					brelse(bh);
200					error = -EIO;
201					goto error_ret;
202				}
203			}
204		}
205		brelse(bh);
206		length -= to_copy;
207		start_offs = 0;
208		to_copy = vol->cluster_size;
209		cluster++;
210	}
211error_ret:
212	return error;
213}
214
215ntfs_time64_t ntfs_now(void)
216{
217	return ntfs_unixutc2ntutc(CURRENT_TIME);
218}
219
220int ntfs_dupuni2map(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
221		int *out_len)
222{
223	int i, o, chl, chi;
224	char *result, *buf, charbuf[NLS_MAX_CHARSET_SIZE];
225	struct nls_table *nls = vol->nls_map;
226
227	result = ntfs_malloc(in_len + 1);
228	if (!result)
229		return -ENOMEM;
230	*out_len = in_len;
231	for (i = o = 0; i < in_len; i++) {
232		wchar_t uni = in[i];
233		if ((chl = nls->uni2char(uni, charbuf,
234				NLS_MAX_CHARSET_SIZE)) > 0) {
235			/* Adjust result buffer. */
236			if (chl > 1) {
237				buf = ntfs_malloc(*out_len + chl - 1);
238				if (!buf) {
239					i = -ENOMEM;
240					goto err_ret;
241				}
242				memcpy(buf, result, o);
243				ntfs_free(result);
244				result = buf;
245				*out_len += (chl - 1);
246			}
247			for (chi = 0; chi < chl; chi++)
248				result[o++] = charbuf[chi];
249		} else {
250			/* Invalid character. */
251			printk(KERN_ERR "NTFS: Unicode name contains a "
252					"character that cannot be converted "
253					"to chosen character set. Remount "
254					"with utf8 encoding and this should "
255					"work.\n");
256			i = -EILSEQ;
257			goto err_ret;
258		}
259	}
260	result[*out_len] = '\0';
261	*out = result;
262	return 0;
263err_ret:
264	ntfs_free(result);
265	*out_len = 0;
266	*out = NULL;
267	return i;
268}
269
270int ntfs_dupmap2uni(ntfs_volume *vol, char* in, int in_len, ntfs_u16 **out,
271		int *out_len)
272{
273	int i, o;
274	ntfs_u16 *result;
275	struct nls_table *nls = vol->nls_map;
276
277	*out = result = ntfs_malloc(2 * in_len);
278	if (!result) {
279		*out_len = 0;
280		return -ENOMEM;
281	}
282	*out_len = in_len;
283	for (i = o = 0; i < in_len; i++, o++) {
284		wchar_t uni;
285		int charlen;
286
287		charlen = nls->char2uni(&in[i], in_len - i, &uni);
288		if (charlen < 0) {
289			i = charlen;
290			goto err_ret;
291		}
292		*out_len -= charlen - 1;
293		i += charlen - 1;
294		result[o] = uni;
295		if (!result[o]) {
296			i = -EILSEQ;
297			goto err_ret;
298		}
299	}
300	return 0;
301err_ret:
302	printk(KERN_ERR "NTFS: Name contains a character that cannot be "
303			"converted to Unicode.\n");
304	ntfs_free(result);
305	*out_len = 0;
306	*out = NULL;
307	return i;
308}
309
310