lseek() w bardzo dużym pliku

0

Dobry wieczór,
jestem tutaj nowy, początkujący :-) i chciałbym się przywitać !

Do rzeczy:
piszę sobie taki prosty program poszukujący sektory na dysku mające sygnaturkę "NTFS " (wiadomo, chodzi o sektory z BB) i mam problem.
Samo przeszukiwanie polega na zmianie wskaźnika pozycji w pliku i poruszanie się po cylindrach.

.....|Sektor 254|Sektor 255|>>>(CYLINDER m-1/255/63)<<<|>>>(CYLINDER m/0/1)<<<|Sektor 0|Sektor 1|.....

(E MATKO, ma być .....|sektor 62|sektor 63| ..... )
(tak to wygląda, a przynajmniej myślę że mój programik odpowiada temu wyżej :-) )

I teraz :
mimo deklaracji zmiennej typu uint64_t zawierającej aktualną pozycje w pliku wartość ta nie przekracza uint32_t !! następuje przepełnienie (chyba) i programik startuje ze zmienna od nowa.
Próbowałem już sztuczek z
#define _FILE_OFFSET_BITS 64 oraz #define _LARGEFILE64_SOURCE
i bawiłem się funkcjami lseek64,open64,fopen64(?),fseeko64(?), a ze zmiennymi off_t i off64_t wyprawiałem cuda na kiju :-) no ale nic nie pomogło.
Sprawdzone na Ubuntu 11.04 32bit i 64bit oraz w kazdej wersji tegoz systemu wartosc zmiennej start_sector w programie gdb zawsze miała 4 bajty, np.

(gdb) print &start_sector
$2 = (uint64_t *) 0x7fffffffe1d8
(gdb) x/4x &start_sector-1
0x7fffffffe1d0: 0x00603130 0x00000000 0xec0ffc00 0x00000000
(gdb)

( 0xec0ffc00 ma być wartością pierwszego przesunięcia pliku pod CHS 2048/255/63 )

Proszę o jakąś radę, albo podpowiedź. NIE LICZĘ NA GOTOWCA :-)

#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE

#include	<stdio.h>
#include	<stdint.h>
#include	<stdlib.h>
#include	<sys/types.h>
#include	<sys/stat.h>
#include	<fcntl.h>
#include	<unistd.h>
#include	<string.h>

// from ntfs-3g - 2011.4.12

// : types.h

typedef uint8_t  u8;			/* Unsigned types of an exact size */
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;

typedef int8_t  s8;			/* Signed types of an exact size */
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;

typedef u16 le16;
typedef u32 le32;
typedef u64 le64;

typedef u16 sle16;
typedef u32 sle32;
typedef u64 sle64;

typedef u16 ntfschar;

typedef s64 VCN;
typedef sle64 leVCN;
typedef s64 LCN;
typedef sle64 leLCN;

typedef s64 LSN;
typedef sle64 leLSN;

// END : types.h

// : endians.h

#define __le16_to_cpu(x) (x)
#define __le32_to_cpu(x) (x)
#define __le64_to_cpu(x) (x)

#define __cpu_to_le16(x) (x)
#define __cpu_to_le32(x) (x)
#define __cpu_to_le64(x) (x)

#define __constant_le16_to_cpu(x) (x)
#define __constant_le32_to_cpu(x) (x)
#define __constant_le64_to_cpu(x) (x)

#define __constant_cpu_to_le16(x) (x)
#define __constant_cpu_to_le32(x) (x)
#define __constant_cpu_to_le64(x) (x)

// END : endians.h

// : layout.h

//#define magicNTFS	__constant_cpu_to_le64(0x202020205346544e)	/* "NTFS    " */
unsigned long long int 	magicNTFS = 0x4e54465320202020;
unsigned int 		NTFS_SB_MAGIC = 0x5346544e;			/* 'NTFS' */
unsigned short		SECTOR_MARKER = 0xaa55;

typedef struct {
	u16 bytes_per_sector;		/* Size of a sector in bytes. */
	u8  sectors_per_cluster;	/* Size of a cluster in sectors. */
	u16 reserved_sectors;		/* zero */
	u8  fats;			/* zero */
	u16 root_entries;		/* zero */
	u16 sectors;			/* zero */
	u8  media_type;			/* 0xf8 = hard disk */
	u16 sectors_per_fat;		/* zero */
/*0x0d*/u16 sectors_per_track;		/* Required to boot Windows. */
/*0x0f*/u16 heads;			/* Required to boot Windows. */
/*0x11*/u32 hidden_sectors;		/* Offset to the start of the partition
					   relative to the disk in sectors.
					   Required to boot Windows. */
/*0x15*/u32 large_sectors;		/* zero */
/* sizeof() = 25 (0x19) bytes */
} __attribute__((__packed__)) BIOS_PARAMETER_BLOCK;

typedef struct {
	u8  jump[3];			/* Irrelevant (jump to boot up code).*/
	u64 oem_id;			/* Magic "NTFS    ". */
/*0x0b*/BIOS_PARAMETER_BLOCK bpb;	/* See BIOS_PARAMETER_BLOCK. */
	u8 physical_drive;		/* 0x00 floppy, 0x80 hard disk */
	u8 current_head;		/* zero */
	u8 extended_boot_signature; 	/* 0x80 */
	u8 reserved2;			/* zero */
/*0x28*/s64 number_of_sectors;		/* Number of sectors in volume. Gives
					   maximum volume size of 2^63 sectors.
					   Assuming standard sector size of 512
					   bytes, the maximum byte size is
					   approx. 4.7x10^21 bytes. (-; */
	s64 mft_lcn;			/* Cluster location of mft data. */
	s64 mftmirr_lcn;		/* Cluster location of copy of mft. */
	s8  clusters_per_mft_record;	/* Mft record size in clusters. */
	u8  reserved0[3];		/* zero */
	s8  clusters_per_index_record;	/* Index block size in clusters. */
	u8  reserved1[3];		/* zero */
	u64 volume_serial_number;	/* Irrelevant (serial number). */
	u32 checksum;			/* Boot sector checksum. */
/*0x54*/u8  bootstrap[426];		/* Irrelevant (boot up code). */
	u16 end_of_sector_marker;	/* End of bootsector magic. Always is
					   0xaa55 in little endian. */
/* sizeof() = 512 (0x200) bytes */
} __attribute__((__packed__)) NTFS_BOOT_SECTOR;

// END : layout.h

// END : from ntfs-3g - 2011.4.12

// : DEFINES

int	verbose = 1;

#define DEV		"/dev/"

#define CYLINDERS 	0
#define HEADS		255
#define SECTORS		63
#define SSIZE		512
#define NSEC		4
#define HALF_NSEC	(NSEC/2)

#define CYLINDER_LBA	1 * HEADS * SECTORS
#define CYLINDER_BYTES	CYLINDER_LBA * SSIZE

#define SOF(type,name)	\
	type name;	\
	if(verbose==1)	\
	{		\
	printf("%d: sizeof(", __LINE__);	\
	printf("%s %s", #type, #name);	\
	printf(") == %d\n",sizeof(name));	\
	}

struct harddg {
	unsigned int 	c;
	unsigned char	h;
	unsigned char	s;
} harddg;

void fill_geometry(char *, struct harddg *);

// END : DEFINES

// : FUNCTIONS

void fill_geometry(char *device, struct harddg *g) {
	
	char *LSTR = "/sys/block/";
	char *RSTR = "/size";
	
	//char *devpath = strcat(DEV, device);
	//char *stok = strtok(devpath, "/");
	uint64_t size = 0;
	char *path = (char *)calloc(1,128);
	char *pp = path;
	pp = strcpy(pp, LSTR);
	pp += strlen(pp);
	pp = strcpy(pp, device);
	pp += (strlen(pp));
	pp = strcpy(pp, RSTR);
	
	char *buf = (char *)calloc(1,64);
	
	printf("fill_geometry: path %s\n",path);
	
	if(strstr(path,device)) {
		FILE *p = fopen(path,"rt");
		if(p) {
			fread((char *)buf, 64, 1, p);
			if(buf) {
				size = strtoull(buf,NULL,0); // ???
				uint32_t cylinders = size / HEADS / SECTORS;
				g->c = cylinders;
				g->h = HEADS;
				g->s = SECTORS;
				fclose(p);
				//return size;
			} else {
				printf("fill_geometry: %s not readed\n",path);
				fclose(p);
				//return 0;
			}
		} else {
			printf("fill_geometry: %s not opened\n",path);
			//return 0;
		}
	} else {
		printf("fill_geometry: string %s error\n",device);
		//return 0;
	}
	
}
// END : FUNCTIONS
int main(int argc, char *argt[]) {
	if(argc<2) {
		printf("%s: use eg. %s sda\n",argt[0],argt[0]);
		return 1;
	}

	char *progname 	= argt[0];
	char *device 	= argt[1];

	char *devpath = (char *)calloc(1,10);
	devpath = strcpy(devpath, DEV);
	devpath = strcat(devpath, device);
	
	if(argc==2 && device && (strlen(device)==3 || strlen(device)==4)) {
		struct harddg *hdg = (struct harddg *)calloc(1,sizeof(struct harddg));
			
		fill_geometry(device, hdg);
		//if(!size) {
		//	printf("%s: fill_geometry error\n", progname);
		//	return 1;
		//}
		
		int devicef = open64(devpath, O_LARGEFILE | O_RDONLY, "rb");
		//FILE *devicef = fopen(devpath, "rb");
		if(!devicef) {
			printf("%s: device %s not opened\n", progname, device);
			return 1;
		}
		
		//fseek(devicef,0L,SEEK_SET);
		
		unsigned int start_cylinder = 2048;
		unsigned int end_cylinder = hdg->c;
		
		SOF(uint64_t,start_sector);//= (start_cylinder * HEADS * SECTORS * SSIZE) - (SSIZE * HALF_NSEC);
		
		//fseek(devicef, start_sector, SEEK_SET);
		int nsec = 0;
		
		for( ; start_cylinder<end_cylinder+1; start_cylinder++) {
			start_sector = (start_cylinder * HEADS * SECTORS * SSIZE) - (SSIZE * HALF_NSEC);
			if(lseek64(devicef, start_sector, SEEK_SET)<0) {
				printf("%s: Error seek not set\n", progname);
				//fclose(devicef);
				close(devicef);				
				return 1;
			}
			char *buffer = (char *)calloc(SSIZE*NSEC,1);
			//size_t readed = fread(buffer, 1, SSIZE*NSEC, devicef);
			size_t readed = read(devicef, buffer, 1 * SSIZE*NSEC);
			if(!(start_cylinder%1024))
				printf("%s:\tCYLINDER: %d\n",progname,start_cylinder);
			if(!(start_sector%(1*1024*1024)))
				printf("%s:\t\tOFFSET: %lu\n",progname,start_sector);
			for(nsec = 0; nsec < NSEC; nsec++) {
				NTFS_BOOT_SECTOR *ntfs_bs = (NTFS_BOOT_SECTOR *)&buffer[nsec*SSIZE];
				if(ntfs_bs->oem_id==magicNTFS) 
				{
					printf("%s: MAGICNTFS found on \
					%u/%d cylinder\n", progname, start_cylinder, nsec);
				}
			}
			free(buffer);
			//start_sector = (start_cylinder * HEADS * SECTORS * SSIZE) - (SSIZE * HALF_NSEC);
			//fseek(devicef, start_sector, SEEK_SET);
		}
		
		close(devicef);
	} else {
		printf("%s: bad arguments\n", progname);
	}
}
 
0

Nikt nie pomoże ?

0

za duży kawałek kodu, mało czytelny post (jakieś cyferki - literki, jeśli już to powinny być w znacznikach < code >), wielu to odstrasza na sam widok i nie czytają dalej.

0

dodaj do tego, że okrasiłeś temat dość wąską specjalistyczną wiedzą na temat NTFS (na dodatek mam wrażenie, że pomieszałeś różne poziomy abstrakcji: "przeszukiwanie polega na zmianie wskaźnika pozycji w pliku i poruszanie się po cylindrach"), a temat nie wzbudzi zainteresowania.

0

Aha.
W takim razie sorki.
Azarien: myślałem że jest ok, już poprawiam.
MarekR22: napisałem na początku że jestem początkujący :-) Sam cytat nie jest stwierdzeniem/powtórzeniem jakiejś definicji lecz moimi słowami :-)
W każdym razie nie chodzi o specjalistyczną wiedzę NTFS, bo sam takowej nie posiadam. Znam tylko podstawowe struktury danych i podstawy łączenia LCNów dla atrybu, indeksu, informacji o pliku... Moje pytanie dotyczyło prostej rzeczy, mianowicie czemu mimo użycia 64bitowych wartości w dodatku w 64bit. systemie, programik nalicza mi zmienną dla unsigned int jak w 32bit. architekturze i jaki powinien byc prawidłowy typ zmiennej. Zniknęły mi tablice partycji na 320gb dysku (czysty 1 sektor) no a nie pamiętam jak mw. były rozmieszczone. W dodatku powiem że program TestDisk również nie wskazał prawidłowych wartości.

0

...
piszę sobie taki prosty program poszukujący sektory na dysku mające sygnaturkę "NTFS " (wiadomo, chodzi o sektory z BB) i mam problem.

Poszukiwanie tychże sektorów to nic innego jak prosta zmiana pozycji w pliku funkcją seek wyliczoną wg. LBA512=cylinder255*63 bajtów.
Aby się zabezpieczyć przed 'ślepym szczałem' programik czyta sektor na początku danego cylindra dysku (cylinder/0/1) start_sector, 2 sektory przed start_sector oraz jeden za start_sector. W sumie 4 sektory (czyli 2048bajtów) i jeżeli znajdzie w którymś z 4 sektorów sygnaturkę, wyświetla odpowiedni monit.

Wizualnie (tu: model logiczny) wygląda to tak:
.....|Cm-1/H255/S62|Cm-1/H255/S63|>>>(koniec cylindra m-1/255/63, na dysku ten obszar między |>>> a <<< ** NIE ISTNIEJE !)<<<|>>>(początek cylindra m/0/1, na dysku ten obszar między >>> a <<<| ** NIE ISTNIEJE !)<<<|Cm/H0/S1|Cm/H0/S2|.....

Znak : | - oznacza 512bajtów, C to cylinder, H to głowice, S to sektory
Komentarze między >>> a <<< to po prostu komentarze i nie mają wpływu na nic prócz uświadomienia :-)

a prościej

|C1/H0/S1|C1/H0/S2|...//**|C1/H255/S62|C1/H255/S63|C2/H0/S1|C2/H0/S2|**//...|Cx/H255/S63|
Między | i | są 512b bloki a podkreślony podciąg to bloki czytane dla 2 cylindra.

I teraz :
mimo deklaracji zmiennej typu **uint64_t start_sector ** zawierającej aktualną pozycje w pliku wartość ta nie przekracza uint32_t (czyli mimo zastosowania 64bit architektury, naliczanie zmiennej zatrzymuje sie na wartości 4 miliardy coś tam i leci od początku) !!
Próbowałem już sztuczek z

 #define _FILE_OFFSET_BITS 64 
#define _LARGEFILE64_SOURCE

(man lseek64(3))

i bawiłem się funkcjami lseek64,open64,fopen64(?),fseeko64(?), a ze zmiennymi off_t i off64_t wyprawiałem cuda na kiju :-) no ale nic nie pomogło.
Sprawdzone na Ubuntu 11.04 32bit i 64bit oraz w kazdej wersji tegoz systemu wartosc zmiennej **start_sector ** w programie gdb zawsze miała 4 bajty (a nie 8 bajtów tak jak mówi dokumentacja i intuicja).

Poniżej kod z programu gdb poleceniem
gdb -ggdb -o program program.c

(gdb) print &start_sector
$2 = (uint64_t *) 0x7fffffffe1d8
(gdb) x/4x &start_sector-1
0x7fffffffe1d0:        0x00603130        0x00000000        0xec0ffc00        0x00000000
(gdb)

(pierwsze to adres zmiennej start_sector w pamięci ($2) a 2 polecenie to adres zmiennej $2 - 1 (czyli xBAJTÓW-8BAJTÓW :-) ) wypisana w formie 32bitowych wartości 4 razy)

(Przepraszam za takie szczegółowe rozpisanie. Nie wiem jak do tego podejść, bo dla mnie takie rzeczy są oczywiste :-) )
Proszę o jakąś radę, albo podpowiedź. NIE LICZĘ NA GOTOWCA :-)

0

Witam !

Programik ruszył, zmienna jest juz OK.
Pozdrawiam.

1 użytkowników online, w tym zalogowanych: 0, gości: 1