summaryrefslogtreecommitdiffstats
path: root/fs/ntfs/util.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
commit27cfca1ec98e91261b1a5355d10a8996464b63af (patch)
tree8e895a53e372fa682b4c0a585b9377d67ed70d0e /fs/ntfs/util.c
parent6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff)
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too o Upgrade to 2.1.89. Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'fs/ntfs/util.c')
-rw-r--r--fs/ntfs/util.c343
1 files changed, 343 insertions, 0 deletions
diff --git a/fs/ntfs/util.c b/fs/ntfs/util.c
new file mode 100644
index 000000000..0cd556177
--- /dev/null
+++ b/fs/ntfs/util.c
@@ -0,0 +1,343 @@
+/*
+ * util.c
+ * Miscellaneous support
+ *
+ * Copyright (C) 1997 Martin von Löwis
+ * Copyright (C) 1997 Régis Duchesne
+ *
+ * The utf8 routines are copied from Python wstrop module,
+ */
+
+#include "types.h"
+#include "struct.h"
+#include "util.h"
+
+#include <errno.h>
+/* FreeBSD doesn't seem to have EILSEQ in errno.h */
+#ifndef EILSEQ
+# define EILSEQ EINVAL
+#endif
+#include "support.h"
+
+/* Converts a single wide character to a sequence of utf8 bytes.
+ * Returns the number of bytes, or 0 on error.
+ */
+static int
+to_utf8(ntfs_u16 c,unsigned char* buf)
+{
+ if(c==0)
+ return 0; /* No support for embedded 0 runes */
+ if(c<0x80){
+ if(buf)buf[0]=c;
+ return 1;
+ }
+ if(c<0x800){
+ if(buf){
+ buf[0] = 0xc0 | (c>>6);
+ buf[1] = 0x80 | (c & 0x3f);
+ }
+ return 2;
+ }
+ if(c<0x10000){
+ if(buf){
+ buf[0] = 0xe0 | (c>>12);
+ buf[1] = 0x80 | ((c>>6) & 0x3f);
+ buf[2] = 0x80 | (c & 0x3f);
+ }
+ return 3;
+ }
+ /* We don't support characters above 0xFFFF in NTFS */
+ return 0;
+}
+
+/* Decodes a sequence of utf8 bytes into a single wide character.
+ * Returns the number of bytes consumed, or 0 on error
+ */
+static int
+from_utf8(const unsigned char* str,ntfs_u16 *c)
+{
+ int l=0,i;
+
+ if(*str<0x80){
+ *c = *str;
+ return 1;
+ }
+ if(*str<0xc0) /* lead byte must not be 10xxxxxx */
+ return 0; /* is c0 a possible lead byte? */
+ if(*str<0xe0){ /* 110xxxxx */
+ *c = *str & 0x1f;
+ l=2;
+ }else if(*str<0xf0){ /* 1110xxxx */
+ *c = *str & 0xf;
+ l=3;
+ }else if(*str<0xf8){ /* 11110xxx */
+ *c = *str & 7;
+ l=4;
+ }else /* We don't support characters above 0xFFFF in NTFS */
+ return 0;
+
+
+ for(i=1;i<l;i++){
+ /* all other bytes must be 10xxxxxx */
+ if((str[i] & 0xc0) != 0x80)
+ return 0;
+ *c <<= 6;
+ *c |= str[i] & 0x3f;
+ }
+ return l;
+}
+
+/* Converts wide string to UTF-8. Expects two in- and two out-parameters.
+ * Returns 0 on success, or error code.
+ * The caller has to free the result string.
+ * There is no support for UTF-16, yet
+ */
+static int ntfs_dupuni2utf8(ntfs_u16* in, int in_len,char **out,int *out_len)
+{
+ int i,tmp;
+ int len8;
+ unsigned char *result;
+
+ ntfs_debug(DEBUG_OTHER,"converting l=%d\n",in_len);
+ /* count the length of the resulting UTF-8 */
+ for(i=len8=0;i<in_len;i++){
+ tmp=to_utf8(in[i],0);
+ if(!tmp)
+ /* invalid character */
+ return EILSEQ;
+ len8+=tmp;
+ }
+ *out=result=ntfs_malloc(len8+1); /* allow for zero-termination */
+
+ if(!result)
+ return ENOMEM;
+ result[len8]='\0';
+ *out_len=len8;
+ for(i=len8=0;i<in_len;i++)
+ len8+=to_utf8(in[i],result+len8);
+ return 0;
+}
+
+/* Converts an UTF-8 sequence to a wide string. Same conventions as the
+ * previous function
+ */
+static int ntfs_duputf82uni(unsigned char* in, int in_len,ntfs_u16** out,int *out_len)
+{
+ int i,tmp;
+ int len16;
+
+ ntfs_u16* result;
+ ntfs_u16 wtmp;
+ for(i=len16=0;i<in_len;i+=tmp,len16++){
+ tmp=from_utf8(in+i,&wtmp);
+ if(!tmp)
+ return EILSEQ;
+ }
+ *out=result=ntfs_malloc(2*(len16+1));
+ if(!result)
+ return ENOMEM;
+ result[len16]=0;
+ *out_len=len16;
+ for(i=len16=0;i<in_len;i+=tmp,len16++)
+ tmp=from_utf8(in+i,result+len16);
+ return 0;
+}
+
+/* See above. Produces ISO-8859-1 from wide strings */
+static int ntfs_dupuni288591(ntfs_u16* in,int in_len,char** out,int *out_len)
+{
+ int i;
+ char *result;
+
+ /* check for characters out of range */
+ for(i=0;i<in_len;i++)
+ if(in[i]>=256)
+ return EILSEQ;
+ *out=result=ntfs_malloc(in_len+1);
+ if(!result)
+ return ENOMEM;
+ result[in_len]='\0';
+ *out_len=in_len;
+ for(i=0;i<in_len;i++)
+ result[i]=in[i];
+ return 0;
+}
+
+/* See above */
+static int ntfs_dup885912uni(unsigned char* in,int in_len,ntfs_u16 **out,int *out_len)
+{
+ int i;
+
+ ntfs_u16* result;
+ *out=result=ntfs_malloc(2*in_len);
+ if(!result)
+ return ENOMEM;
+ *out_len=in_len;
+ for(i=0;i<in_len;i++)
+ result[i]=in[i];
+ return 0;
+}
+
+/* Encodings dispatcher */
+int ntfs_encodeuni(ntfs_volume *vol,ntfs_u16 *in, int in_len,
+ char **out, int *out_len)
+{
+ if(vol->nct & nct_utf8)
+ return ntfs_dupuni2utf8(in,in_len,out,out_len);
+ else if(vol->nct & nct_iso8859_1)
+ return ntfs_dupuni288591(in,in_len,out,out_len);
+ else if(vol->nct & (nct_map|nct_uni_xlate))
+ /* uni_xlate is handled inside map */
+ return ntfs_dupuni2map(vol,in,in_len,out,out_len);
+ else
+ return EINVAL; /* unknown encoding */
+}
+
+int ntfs_decodeuni(ntfs_volume *vol,char *in, int in_len,
+ ntfs_u16 **out, int *out_len)
+{
+ if(vol->nct & nct_utf8)
+ return ntfs_duputf82uni(in,in_len,out,out_len);
+ else if(vol->nct & nct_iso8859_1)
+ return ntfs_dup885912uni(in,in_len,out,out_len);
+ else if(vol->nct & (nct_map | nct_uni_xlate))
+ return ntfs_dupmap2uni(vol,in,in_len,out,out_len);
+ else
+ return EINVAL;
+}
+
+/* Same address space copies */
+void ntfs_put(ntfs_io *dest,void *src,ntfs_size_t n)
+{
+ ntfs_memcpy(dest->param,src,n);
+ dest->param+=n;
+}
+
+void ntfs_get(void* dest,ntfs_io *src,ntfs_size_t n)
+{
+ ntfs_memcpy(dest,src->param,n);
+ src->param+=n;
+}
+
+void *ntfs_calloc(int size)
+{
+ void *result=ntfs_malloc(size);
+
+ if(result)
+ ntfs_bzero(result,size);
+ return result;
+}
+
+#if 0
+/* copy len unicode characters from from to to :) */
+void ntfs_uni2ascii(char *to,char *from,int len)
+{
+ int i;
+
+ for(i=0;i<len;i++)
+ to[i]=from[2*i];
+ to[i]='\0';
+}
+#endif
+
+/* copy len asci characters from from to to :) */
+void ntfs_ascii2uni(short int *to,char *from,int len)
+{
+ int i;
+
+ for(i=0;i<len;i++)
+ to[i]=from[i];
+ to[i]=0;
+}
+
+/* strncmp for Unicode strings */
+int ntfs_uni_strncmp(short int* a,short int *b,int n)
+{
+ int i;
+
+ for(i=0;i<n;i++)
+ {
+ if(a[i]<b[i])
+ return -1;
+ if(b[i]<a[i])
+ return 1;
+ }
+ return 0;
+}
+
+/* strncmp between Unicode and ASCII strings */
+int ntfs_ua_strncmp(short int* a,char* b,int n)
+{
+ int i;
+
+ for(i=0;i<n;i++)
+ {
+ if(a[i]<b[i])
+ return -1;
+ if(b[i]<a[i])
+ return 1;
+ }
+ return 0;
+}
+
+/* Convert the NT UTC (based 1.1.1601, in hundred nanosecond units)
+ * into Unix UTC (based 1.1.1970, in seconds)
+ */
+ntfs_time_t ntfs_ntutc2unixutc(ntfs_time64_t ntutc)
+{
+/*
+ * This is very gross because
+ * 1: We must do 64-bit division on a 32-bit machine
+ * 2: We can't use libgcc for long long operations in the kernel
+ * 3: Floating point math in the kernel would corrupt user data
+ */
+ const unsigned int D = 10000000;
+ unsigned int H = (ntutc >> 32);
+ unsigned int L = (unsigned int)ntutc;
+ unsigned int numerator2;
+ unsigned int lowseconds;
+ unsigned int result;
+
+ /* It is best to subtract 0x019db1ded53e8000 first. */
+ /* Then the 1601-based date becomes a 1970-based date. */
+ if(L < (unsigned)0xd53e8000) H--;
+ L -= (unsigned)0xd53e8000;
+ H -= (unsigned)0x019db1de;
+
+ /*
+ * Now divide 64-bit numbers on a 32-bit machine :-)
+ * With the subtraction already done, the result fits in 32 bits.
+ * The numerator fits in 56 bits and the denominator fits
+ * in 24 bits, so we can shift by 8 bits to make this work.
+ */
+
+ numerator2 = (H<<8) | (L>>24);
+ result = (numerator2 / D); /* shifted 24 right!! */
+ lowseconds = result << 24;
+
+ numerator2 = ((numerator2-result*D)<<8) | ((L>>16)&0xff);
+ result = (numerator2 / D); /* shifted 16 right!! */
+ lowseconds |= result << 16;
+
+ numerator2 = ((numerator2-result*D)<<8) | ((L>>8)&0xff);
+ result = (numerator2 / D); /* shifted 8 right!! */
+ lowseconds |= result << 8;
+
+ numerator2 = ((numerator2-result*D)<<8) | (L&0xff);
+ result = (numerator2 / D); /* not shifted */
+ lowseconds |= result;
+
+ return lowseconds;
+}
+
+/* Convert the Unix UTC into NT UTC */
+ntfs_time64_t ntfs_unixutc2ntutc(ntfs_time_t t)
+{
+ return ((t + (ntfs_time64_t)(369*365+89)*24*3600) * 10000000);
+}
+
+/*
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */