2005-01-31 07:28:44 +03:00
/*
* volume_id - reads filesystem label and uuid
*
* Copyright ( C ) 2005 Kay Sievers < kay . sievers @ vrfy . org >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
# endif
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
# include <errno.h>
# include <ctype.h>
# include <fcntl.h>
# include <sys/stat.h>
# include "volume_id.h"
# include "logging.h"
# include "util.h"
2005-08-01 03:33:36 +04:00
void volume_id_set_unicode16 ( char * str , size_t len , const uint8_t * buf , enum endian endianess , size_t count )
2005-03-11 10:02:47 +03:00
{
unsigned int i , j ;
2005-08-01 03:33:36 +04:00
uint16_t c ;
2005-03-11 10:02:47 +03:00
j = 0 ;
for ( i = 0 ; i + 2 < = count ; i + = 2 ) {
if ( endianess = = LE )
c = ( buf [ i + 1 ] < < 8 ) | buf [ i ] ;
else
c = ( buf [ i ] < < 8 ) | buf [ i + 1 ] ;
if ( c = = 0 ) {
str [ j ] = ' \0 ' ;
break ;
} else if ( c < 0x80 ) {
if ( j + 1 > = len )
break ;
2005-08-01 03:33:36 +04:00
str [ j + + ] = ( uint8_t ) c ;
2005-03-11 10:02:47 +03:00
} else if ( c < 0x800 ) {
if ( j + 2 > = len )
break ;
2005-08-01 03:33:36 +04:00
str [ j + + ] = ( uint8_t ) ( 0xc0 | ( c > > 6 ) ) ;
str [ j + + ] = ( uint8_t ) ( 0x80 | ( c & 0x3f ) ) ;
2005-03-11 10:02:47 +03:00
} else {
if ( j + 3 > = len )
break ;
2005-08-01 03:33:36 +04:00
str [ j + + ] = ( uint8_t ) ( 0xe0 | ( c > > 12 ) ) ;
str [ j + + ] = ( uint8_t ) ( 0x80 | ( ( c > > 6 ) & 0x3f ) ) ;
str [ j + + ] = ( uint8_t ) ( 0x80 | ( c & 0x3f ) ) ;
2005-03-11 10:02:47 +03:00
}
}
str [ j ] = ' \0 ' ;
}
2005-01-31 07:28:44 +03:00
static char * usage_to_string ( enum volume_id_usage usage_id )
{
switch ( usage_id ) {
case VOLUME_ID_FILESYSTEM :
return " filesystem " ;
case VOLUME_ID_PARTITIONTABLE :
return " partitiontable " ;
case VOLUME_ID_OTHER :
return " other " ;
case VOLUME_ID_RAID :
return " raid " ;
case VOLUME_ID_DISKLABEL :
return " disklabel " ;
2005-02-23 04:58:31 +03:00
case VOLUME_ID_CRYPTO :
return " crypto " ;
2005-01-31 07:28:44 +03:00
case VOLUME_ID_UNPROBED :
return " unprobed " ;
case VOLUME_ID_UNUSED :
return " unused " ;
}
return NULL ;
}
void volume_id_set_usage_part ( struct volume_id_partition * part , enum volume_id_usage usage_id )
{
part - > usage_id = usage_id ;
part - > usage = usage_to_string ( usage_id ) ;
}
void volume_id_set_usage ( struct volume_id * id , enum volume_id_usage usage_id )
{
id - > usage_id = usage_id ;
id - > usage = usage_to_string ( usage_id ) ;
}
2005-08-01 03:33:36 +04:00
void volume_id_set_label_raw ( struct volume_id * id , const uint8_t * buf , size_t count )
2005-01-31 07:28:44 +03:00
{
memcpy ( id - > label_raw , buf , count ) ;
id - > label_raw_len = count ;
}
2005-08-01 03:33:36 +04:00
void volume_id_set_label_string ( struct volume_id * id , const uint8_t * buf , size_t count )
2005-01-31 07:28:44 +03:00
{
unsigned int i ;
memcpy ( id - > label , buf , count ) ;
/* remove trailing whitespace */
2005-08-13 02:18:44 +04:00
i = strnlen ( id - > label , count ) ;
2005-01-31 07:28:44 +03:00
while ( i - - ) {
if ( ! isspace ( id - > label [ i ] ) )
break ;
}
id - > label [ i + 1 ] = ' \0 ' ;
}
2005-08-01 03:33:36 +04:00
void volume_id_set_label_unicode16 ( struct volume_id * id , const uint8_t * buf , enum endian endianess , size_t count )
2005-01-31 07:28:44 +03:00
{
2005-03-11 10:02:47 +03:00
volume_id_set_unicode16 ( id - > label , sizeof ( id - > label ) , buf , endianess , count ) ;
2005-01-31 07:28:44 +03:00
}
2005-08-01 03:33:36 +04:00
void volume_id_set_uuid ( struct volume_id * id , const uint8_t * buf , enum uuid_format format )
2005-01-31 07:28:44 +03:00
{
unsigned int i ;
unsigned int count = 0 ;
switch ( format ) {
case UUID_DOS :
count = 4 ;
break ;
case UUID_NTFS :
case UUID_HFS :
count = 8 ;
break ;
case UUID_DCE :
count = 16 ;
2005-03-06 04:02:45 +03:00
break ;
case UUID_DCE_STRING :
count = 36 ;
break ;
2005-01-31 07:28:44 +03:00
}
memcpy ( id - > uuid_raw , buf , count ) ;
2005-03-06 04:02:45 +03:00
id - > uuid_raw_len = count ;
2005-01-31 07:28:44 +03:00
/* if set, create string in the same format, the native platform uses */
for ( i = 0 ; i < count ; i + + )
if ( buf [ i ] ! = 0 )
goto set ;
return ;
set :
switch ( format ) {
case UUID_DOS :
sprintf ( id - > uuid , " %02X%02X-%02X%02X " ,
buf [ 3 ] , buf [ 2 ] , buf [ 1 ] , buf [ 0 ] ) ;
break ;
case UUID_NTFS :
sprintf ( id - > uuid , " %02X%02X%02X%02X%02X%02X%02X%02X " ,
buf [ 7 ] , buf [ 6 ] , buf [ 5 ] , buf [ 4 ] ,
buf [ 3 ] , buf [ 2 ] , buf [ 1 ] , buf [ 0 ] ) ;
break ;
case UUID_HFS :
sprintf ( id - > uuid , " %02X%02X%02X%02X%02X%02X%02X%02X " ,
buf [ 0 ] , buf [ 1 ] , buf [ 2 ] , buf [ 3 ] ,
buf [ 4 ] , buf [ 5 ] , buf [ 6 ] , buf [ 7 ] ) ;
break ;
case UUID_DCE :
sprintf ( id - > uuid ,
" %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x " ,
buf [ 0 ] , buf [ 1 ] , buf [ 2 ] , buf [ 3 ] ,
buf [ 4 ] , buf [ 5 ] ,
buf [ 6 ] , buf [ 7 ] ,
buf [ 8 ] , buf [ 9 ] ,
buf [ 10 ] , buf [ 11 ] , buf [ 12 ] , buf [ 13 ] , buf [ 14 ] , buf [ 15 ] ) ;
break ;
2005-03-06 04:02:45 +03:00
case UUID_DCE_STRING :
memcpy ( id - > uuid , buf , count ) ;
id - > uuid [ count ] = ' \0 ' ;
break ;
2005-01-31 07:28:44 +03:00
}
}
2005-08-01 03:33:36 +04:00
uint8_t * volume_id_get_buffer ( struct volume_id * id , uint64_t off , size_t len )
2005-01-31 07:28:44 +03:00
{
2005-09-14 16:29:59 +04:00
ssize_t buf_len ;
2005-01-31 07:28:44 +03:00
2005-08-01 03:33:36 +04:00
dbg ( " get buffer off 0x%llx(%llu), len 0x%zx " , ( unsigned long long ) off , ( unsigned long long ) off , len ) ;
2005-01-31 07:28:44 +03:00
/* check if requested area fits in superblock buffer */
if ( off + len < = SB_BUFFER_SIZE ) {
if ( id - > sbbuf = = NULL ) {
id - > sbbuf = malloc ( SB_BUFFER_SIZE ) ;
2005-08-17 18:58:19 +04:00
if ( id - > sbbuf = = NULL ) {
dbg ( " error malloc " ) ;
2005-01-31 07:28:44 +03:00
return NULL ;
2005-08-17 18:58:19 +04:00
}
2005-01-31 07:28:44 +03:00
}
/* check if we need to read */
if ( ( off + len ) > id - > sbbuf_len ) {
2005-03-10 02:58:01 +03:00
dbg ( " read sbbuf len:0x%llx " , ( unsigned long long ) ( off + len ) ) ;
2005-08-17 18:58:19 +04:00
if ( lseek ( id - > fd , 0 , SEEK_SET ) < 0 ) {
dbg ( " lseek failed (%s) " , strerror ( errno ) ) ;
return NULL ;
}
2005-01-31 07:28:44 +03:00
buf_len = read ( id - > fd , id - > sbbuf , off + len ) ;
2005-08-17 18:58:19 +04:00
if ( buf_len < 0 ) {
dbg ( " read failed (%s) " , strerror ( errno ) ) ;
return NULL ;
}
2005-08-01 03:33:36 +04:00
dbg ( " got 0x%zx (%zi) bytes " , buf_len , buf_len ) ;
2005-01-31 07:28:44 +03:00
id - > sbbuf_len = buf_len ;
2005-09-14 16:29:59 +04:00
if ( ( size_t ) buf_len < off + len ) {
2005-08-17 18:58:19 +04:00
dbg ( " requested 0x%zx bytes, got only 0x%zx bytes " , len , buf_len ) ;
2005-01-31 07:28:44 +03:00
return NULL ;
2005-08-17 18:58:19 +04:00
}
2005-01-31 07:28:44 +03:00
}
return & ( id - > sbbuf [ off ] ) ;
} else {
if ( len > SEEK_BUFFER_SIZE ) {
dbg ( " seek buffer too small %d " , SEEK_BUFFER_SIZE ) ;
return NULL ;
}
/* get seek buffer */
if ( id - > seekbuf = = NULL ) {
id - > seekbuf = malloc ( SEEK_BUFFER_SIZE ) ;
2005-08-17 18:58:19 +04:00
if ( id - > seekbuf = = NULL ) {
dbg ( " error malloc " ) ;
2005-01-31 07:28:44 +03:00
return NULL ;
2005-08-17 18:58:19 +04:00
}
2005-01-31 07:28:44 +03:00
}
/* check if we need to read */
if ( ( off < id - > seekbuf_off ) | | ( ( off + len ) > ( id - > seekbuf_off + id - > seekbuf_len ) ) ) {
2005-08-01 03:33:36 +04:00
dbg ( " read seekbuf off:0x%llx len:0x%zx " , ( unsigned long long ) off , len ) ;
2005-08-17 18:58:19 +04:00
if ( lseek ( id - > fd , off , SEEK_SET ) < 0 ) {
dbg ( " lseek failed (%s) " , strerror ( errno ) ) ;
2005-01-31 07:28:44 +03:00
return NULL ;
2005-08-17 18:58:19 +04:00
}
2005-01-31 07:28:44 +03:00
buf_len = read ( id - > fd , id - > seekbuf , len ) ;
2005-08-17 18:58:19 +04:00
if ( buf_len < 0 ) {
dbg ( " read failed (%s) " , strerror ( errno ) ) ;
return NULL ;
}
2005-08-01 03:33:36 +04:00
dbg ( " got 0x%zx (%zi) bytes " , buf_len , buf_len ) ;
2005-01-31 07:28:44 +03:00
id - > seekbuf_off = off ;
id - > seekbuf_len = buf_len ;
2005-09-14 16:29:59 +04:00
if ( ( size_t ) buf_len < len ) {
2005-08-01 03:33:36 +04:00
dbg ( " requested 0x%zx bytes, got only 0x%zx bytes " , len , buf_len ) ;
2005-01-31 07:28:44 +03:00
return NULL ;
}
}
return & ( id - > seekbuf [ off - id - > seekbuf_off ] ) ;
}
}
void volume_id_free_buffer ( struct volume_id * id )
{
if ( id - > sbbuf ! = NULL ) {
free ( id - > sbbuf ) ;
id - > sbbuf = NULL ;
id - > sbbuf_len = 0 ;
}
if ( id - > seekbuf ! = NULL ) {
free ( id - > seekbuf ) ;
id - > seekbuf = NULL ;
id - > seekbuf_len = 0 ;
}
}