/* * support.c * Specific support functions * * Copyright (C) 1997 Martin von Löwis * Copyright (C) 1997 Régis Duchesne * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "ntfstypes.h" #include "struct.h" #include "support.h" #include #include #include #include #include "util.h" #include "inode.h" #include "macros.h" static char print_buf[1024]; #ifdef DEBUG #include "sysctl.h" #include /* Debugging output */ void ntfs_debug(int mask, const char *fmt, ...) { va_list ap; /* Filter it with the debugging level required */ if(ntdebug & mask){ va_start(ap,fmt); strcpy(print_buf, KERN_DEBUG); vsprintf(print_buf + 3, fmt, ap); printk(print_buf); va_end(ap); } } #ifndef ntfs_malloc /* Verbose kmalloc */ void *ntfs_malloc(int size) { void *ret; ret = kmalloc(size, GFP_KERNEL); ntfs_debug(DEBUG_MALLOC, "Allocating %x at %p\n", size, ret); return ret; } #endif #ifndef ntfs_free /* Verbose kfree() */ void ntfs_free(void *block) { ntfs_debug(DEBUG_MALLOC, "Freeing memory at %p\n", block); kfree(block); } #endif #else void ntfs_debug(int mask, const char *fmt, ...) { } #ifndef ntfs_malloc void *ntfs_malloc(int size) { return kmalloc(size, GFP_KERNEL); } #endif #ifndef ntfs_free void ntfs_free(void *block) { kfree(block); } #endif #endif /* DEBUG */ void ntfs_bzero(void *s, int n) { memset(s, 0, n); } /* These functions deliberately return no value. It is dest, anyway, and not used anywhere in the NTFS code. */ void ntfs_memcpy(void *dest, const void *src, ntfs_size_t n) { memcpy(dest, src, n); } void ntfs_memmove(void *dest, const void *src, ntfs_size_t n) { memmove(dest, src, n); } /* Warn that an error occured. */ void ntfs_error(const char *fmt,...) { va_list ap; va_start(ap, fmt); strcpy(print_buf, KERN_ERR); vsprintf(print_buf + 3, fmt, ap); printk(print_buf); va_end(ap); } int ntfs_read_mft_record(ntfs_volume *vol, int mftno, char *buf) { int error; ntfs_io io; ntfs_debug(DEBUG_OTHER, "read_mft_record %x\n",mftno); if(mftno==FILE_MFT) { ntfs_memcpy(buf,vol->mft,vol->mft_recordsize); return 0; } if(!vol->mft_ino) { printk("ntfs:something is terribly wrong here\n"); return ENODATA; } io.fn_put=ntfs_put; io.fn_get=0; io.param=buf; io.size=vol->mft_recordsize; error=ntfs_read_attr(vol->mft_ino,vol->at_data,NULL, mftno*vol->mft_recordsize,&io); if(error || (io.size!=vol->mft_recordsize)) { ntfs_debug(DEBUG_OTHER, "read_mft_record: read %x failed (%d,%d,%d)\n", mftno,error,io.size,vol->mft_recordsize); return error?error:ENODATA; } ntfs_debug(DEBUG_OTHER, "read_mft_record: finished read %x\n",mftno); if(!ntfs_check_mft_record(vol,buf)) { printk("Invalid MFT record for %x\n",mftno); return EINVAL; } ntfs_debug(DEBUG_OTHER, "read_mft_record: Done %x\n",mftno); return 0; } int ntfs_getput_clusters(ntfs_volume *vol, int cluster, ntfs_size_t start_offs, ntfs_io *buf) { struct super_block *sb=NTFS_SB(vol); struct buffer_head *bh; ntfs_size_t to_copy; int length=buf->size; if(buf->do_read) ntfs_debug(DEBUG_OTHER, "get_clusters %d %d %d\n",cluster,start_offs,length); else ntfs_debug(DEBUG_OTHER, "put_clusters %d %d %d\n",cluster,start_offs,length); while(length) { if(!(bh=bread(sb->s_dev,cluster,vol->clustersize))) { ntfs_debug(DEBUG_OTHER, "%s failed\n", buf->do_read?"Reading":"Writing"); return EIO; } to_copy=min(vol->clustersize-start_offs,length); lock_buffer(bh); if(buf->do_read) buf->fn_put(buf,bh->b_data+start_offs,to_copy); else { buf->fn_get(bh->b_data+start_offs,buf,to_copy); mark_buffer_dirty(bh,1); } unlock_buffer(bh); length-=to_copy; start_offs=0; cluster++; brelse(bh); } return 0; } ntfs_time64_t ntfs_now(void) { return ntfs_unixutc2ntutc(CURRENT_TIME); } /* when printing unicode characters base64, use this table. It is not strictly base64, but the Linux vfat encoding. base64 has the disadvantage of using the slash. */ static char uni2esc[64]= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-"; static unsigned char esc2uni(char c) { if(c<'0')return 255; if(c<='9')return c-'0'; if(c<'A')return 255; if(c<='Z')return c-'A'+10; if(c<'a')return 255; if(c<='z')return c-'a'+36; if(c=='+')return 62; if(c=='-')return 63; return 255; } int ntfs_dupuni2map(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out, int *out_len) { int i,o,val; char *result,*buf; struct nls_table* nls=vol->nls_map; result=ntfs_malloc(in_len+1); if(!result)return ENOMEM; *out_len=in_len; result[in_len]='\0'; for(i=o=0;i> 8) & 0xFF; if(!nls){ if(!ch){ result[o++]=cl; continue; } }else{ uni_page=nls->page_uni2charset[ch]; if(uni_page && uni_page[cl]){ result[o++]=uni_page[cl]; continue; } } if(!(vol->nct & nct_uni_xlate))goto inval; /* realloc */ buf=ntfs_malloc(*out_len+3); if( !buf ) { ntfs_free( result ); return ENOMEM; } memcpy(buf,result,o); ntfs_free(result); result=buf; *out_len+=3; result[o++]=':'; if(vol->nct & nct_uni_xlate_vfat){ val=(cl<<8)+ch; result[o+2]=uni2esc[val & 0x3f]; val>>=6; result[o+1]=uni2esc[val & 0x3f]; val>>=6; result[o]=uni2esc[val & 0x3f]; o+=3; }else{ val=(ch<<8)+cl; result[o++]=uni2esc[val & 0x3f]; val>>=6; result[o++]=uni2esc[val & 0x3f]; val>>=6; result[o++]=uni2esc[val & 0x3f]; } } *out=result; return 0; inval: ntfs_free(result); *out=0; return EILSEQ; } int ntfs_dupmap2uni(ntfs_volume *vol, char* in, int in_len, ntfs_u16 **out, int *out_len) { int i,o; ntfs_u16* result; struct nls_table* nls=vol->nls_map; *out=result=ntfs_malloc(2*in_len); if(!result)return ENOMEM; *out_len=in_len; for(i=o=0;inct & nct_uni_xlate)==0){ cl=nls->charset2uni[(unsigned char)in[i]].uni1; ch=nls->charset2uni[(unsigned char)in[i]].uni2; }else{ unsigned char c1,c2,c3; *out_len-=3; c1=esc2uni(in[++i]); c2=esc2uni(in[++i]); c3=esc2uni(in[++i]); if(c1==255 || c2==255 || c3==255) cl=ch=0; else if(vol->nct & nct_uni_xlate_vfat){ cl = (c1 << 4) + (c2 >> 2); ch = ((c2 & 0x3) << 6) + c3; }else{ ch=(c3 << 4) + (c2 >> 2); cl=((c2 & 0x3) << 6) + c1; } } /* FIXME: byte order */ result[o] = (ch<<8) | cl; if(!result[o]){ ntfs_free(result); return EILSEQ; } } return 0; } /* * Local variables: * c-file-style: "linux" * End: */