import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / fs / ntfs / support.c
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 */
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 */
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() */
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
67 void *ntfs_malloc(int size)
68 {
69         return kmalloc(size, GFP_KERNEL);
70 }
71 #endif
72
73 #ifndef ntfs_free
74 void ntfs_free(void *block)
75 {
76         kfree(block);
77 }
78 #endif
79 #endif /* DEBUG */
80
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
89 void ntfs_memcpy(void *dest, const void *src, ntfs_size_t n)
90 {
91         memcpy(dest, src, n);
92 }
93
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. */
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
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
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
220 ntfs_time64_t ntfs_now(void)
221 {
222         return ntfs_unixutc2ntutc(CURRENT_TIME);
223 }
224
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
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