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 
22 static char print_buf[1024];
23 
24 #ifdef DEBUG
25 #include "sysctl.h"
26 #include <linux/kernel.h>
27 
28 /* Debugging output */
ntfs_debug(int mask,const char * fmt,...)29 void 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 */
ntfs_malloc(int size)45 void *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() */
ntfs_free(void * block)58 void 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
ntfs_malloc(int size)67 void *ntfs_malloc(int size)
68 {
69 	return kmalloc(size, GFP_KERNEL);
70 }
71 #endif
72 
73 #ifndef ntfs_free
ntfs_free(void * block)74 void ntfs_free(void *block)
75 {
76 	kfree(block);
77 }
78 #endif
79 #endif /* DEBUG */
80 
ntfs_bzero(void * s,int n)81 void 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 
ntfs_memcpy(void * dest,const void * src,ntfs_size_t n)89 void ntfs_memcpy(void *dest, const void *src, ntfs_size_t n)
90 {
91 	memcpy(dest, src, n);
92 }
93 
ntfs_memmove(void * dest,const void * src,ntfs_size_t n)94 void 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. */
ntfs_error(const char * fmt,...)100 void 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 
ntfs_read_mft_record(ntfs_volume * vol,int mftno,char * buf)111 int 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 		/* FIXME: This is incomplete behaviour. We might be able to
148 		 * recover at this stage. ntfs_check_mft_record() is too
149 		 * conservative at aborting it's operations. It is OK for
150 		 * now as we just can't handle some on disk structures
151 		 * this way. (AIA) */
152 		printk(KERN_WARNING "NTFS: Invalid MFT record for 0x%x\n", mftno);
153 		return -EIO;
154 	}
155 	ntfs_debug(DEBUG_OTHER, "read_mft_record: Done 0x%x\n", mftno);
156 	return 0;
157 }
158 
ntfs_getput_clusters(ntfs_volume * vol,int cluster,ntfs_size_t start_offs,ntfs_io * buf)159 int ntfs_getput_clusters(ntfs_volume *vol, int cluster, ntfs_size_t start_offs,
160 		ntfs_io *buf)
161 {
162 	struct super_block *sb = NTFS_SB(vol);
163 	struct buffer_head *bh;
164 	int length = buf->size;
165 	int error = 0;
166 	ntfs_size_t to_copy;
167 
168 	ntfs_debug(DEBUG_OTHER, "%s_clusters %d %d %d\n",
169 		   buf->do_read ? "get" : "put", cluster, start_offs, length);
170 	to_copy = vol->cluster_size - start_offs;
171 	while (length) {
172 		if (!(bh = sb_bread(sb, cluster))) {
173 			ntfs_debug(DEBUG_OTHER, "%s failed\n",
174 				   buf->do_read ? "Reading" : "Writing");
175 			error = -EIO;
176 			goto error_ret;
177 		}
178 		if (to_copy > length)
179 			to_copy = length;
180 		lock_buffer(bh);
181 		if (buf->do_read) {
182 			buf->fn_put(buf, bh->b_data + start_offs, to_copy);
183 			unlock_buffer(bh);
184 		} else {
185 			buf->fn_get(bh->b_data + start_offs, buf, to_copy);
186 			mark_buffer_dirty(bh);
187 			unlock_buffer(bh);
188 			/*
189 			 * Note: We treat synchronous IO on a per volume basis
190 			 * disregarding flags of individual inodes. This can
191 			 * lead to some strange write ordering effects upon a
192 			 * remount with a change in the sync flag but it should
193 			 * not break anything. [Except if the system crashes
194 			 * at that point in time but there would be more thigs
195 			 * to worry about than that in that case...]. (AIA)
196 			 */
197 			if (sb->s_flags & MS_SYNCHRONOUS) {
198 				ll_rw_block(WRITE, 1, &bh);
199 				wait_on_buffer(bh);
200 				if (buffer_req(bh) && !buffer_uptodate(bh)) {
201 					printk(KERN_ERR "IO error syncing NTFS "
202 					       "cluster [%s:%i]\n",
203 					       bdevname(sb->s_dev), cluster);
204 					brelse(bh);
205 					error = -EIO;
206 					goto error_ret;
207 				}
208 			}
209 		}
210 		brelse(bh);
211 		length -= to_copy;
212 		start_offs = 0;
213 		to_copy = vol->cluster_size;
214 		cluster++;
215 	}
216 error_ret:
217 	return error;
218 }
219 
ntfs_now(void)220 ntfs_time64_t ntfs_now(void)
221 {
222 	return ntfs_unixutc2ntutc(CURRENT_TIME);
223 }
224 
ntfs_dupuni2map(ntfs_volume * vol,ntfs_u16 * in,int in_len,char ** out,int * out_len)225 int ntfs_dupuni2map(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
226 		int *out_len)
227 {
228 	int i, o, chl, chi;
229 	char *result, *buf, charbuf[NLS_MAX_CHARSET_SIZE];
230 	struct nls_table *nls = vol->nls_map;
231 
232 	result = ntfs_malloc(in_len + 1);
233 	if (!result)
234 		return -ENOMEM;
235 	*out_len = in_len;
236 	for (i = o = 0; i < in_len; i++) {
237 		/* FIXME: Byte order? */
238 		wchar_t uni = in[i];
239 		if ((chl = nls->uni2char(uni, charbuf,
240 				NLS_MAX_CHARSET_SIZE)) > 0) {
241 			/* Adjust result buffer. */
242 			if (chl > 1) {
243 				buf = ntfs_malloc(*out_len + chl);
244 				if (!buf) {
245 					i = -ENOMEM;
246 					goto err_ret;
247 				}
248 				memcpy(buf, result, o);
249 				ntfs_free(result);
250 				result = buf;
251 				*out_len += (chl - 1);
252 			}
253 			for (chi = 0; chi < chl; chi++)
254 				result[o++] = charbuf[chi];
255 		} else {
256 			/* Invalid character. */
257 			printk(KERN_ERR "NTFS: Unicode name contains a "
258 					"character that cannot be converted "
259 					"to chosen character set. Remount "
260 					"with utf8 encoding and this should "
261 					"work.\n");
262 			i = -EILSEQ;
263 			goto err_ret;
264 		}
265 	}
266 	result[*out_len] = '\0';
267 	*out = result;
268 	return 0;
269 err_ret:
270 	ntfs_free(result);
271 	*out_len = 0;
272 	*out = NULL;
273 	return i;
274 }
275 
ntfs_dupmap2uni(ntfs_volume * vol,char * in,int in_len,ntfs_u16 ** out,int * out_len)276 int ntfs_dupmap2uni(ntfs_volume *vol, char* in, int in_len, ntfs_u16 **out,
277 		int *out_len)
278 {
279 	int i, o;
280 	ntfs_u16 *result;
281 	struct nls_table *nls = vol->nls_map;
282 
283 	*out = result = ntfs_malloc(2 * in_len);
284 	if (!result) {
285 		*out_len = 0;
286 		return -ENOMEM;
287 	}
288 	*out_len = in_len;
289 	for (i = o = 0; i < in_len; i++, o++) {
290 		wchar_t uni;
291 		int charlen;
292 
293 		charlen = nls->char2uni(&in[i], in_len - i, &uni);
294 		if (charlen < 0) {
295 			i = charlen;
296 			goto err_ret;
297 		}
298 		*out_len -= charlen - 1;
299 		i += charlen - 1;
300 		/* FIXME: Byte order? */
301 		result[o] = uni;
302 		if (!result[o]) {
303 			i = -EILSEQ;
304 			goto err_ret;
305 		}
306 	}
307 	return 0;
308 err_ret:
309 	printk(KERN_ERR "NTFS: Name contains a character that cannot be "
310 			"converted to Unicode.\n");
311 	ntfs_free(result);
312 	*out_len = 0;
313 	*out = NULL;
314 	return i;
315 }
316 
317