The C language convention counts array indices from 0. Why do inode numbers start from 1 and not 0?
If inode 0 is reserved is for some special use, then what is the significance of inode 0?
0 is used as a sentinel value to indicate null or no inode. similar to how pointers can be NULL in C. without a sentinel, you'd need an extra bit to test if an inode in a struct was set or not.
more info here:
All block and inode addresses start at
1. The first block on the disk is block 1. 0 is used to indicate no
block. (Sparse files can have these
inside them)
http://uranus.chrysocome.net/explore2fs/es2fs.htm
for instance, in old filesystems where directories were represented as a fixed array of file entries, deleting a file would result in setting that entry's inode val to 0. when traversing the directory, any entry with an inode of 0 would be ignored.
Usually, the inode 0 is reserved because a return value of 0 usually signals an error. Multiple method in the Linux kernel -- especially in the VFS layer shared by all file systems -- return an ino_t, e.g. find_inode_number.
There are more reserved inode numbers. For example in ext2:
#define EXT2_BAD_INO 1 /* Bad blocks inode */
#define EXT2_ROOT_INO 2 /* Root inode */
#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
and ext3 has:
#define EXT3_BAD_INO 1 /* Bad blocks inode */
#define EXT3_ROOT_INO 2 /* Root inode */
#define EXT3_BOOT_LOADER_INO 5 /* Boot loader inode */
#define EXT3_UNDEL_DIR_INO 6 /* Undelete directory inode */
#define EXT3_RESIZE_INO 7 /* Reserved group descriptors inode */
#define EXT3_JOURNAL_INO 8 /* Journal inode */
and ext4 has:
#define EXT4_BAD_INO 1 /* Bad blocks inode */
#define EXT4_ROOT_INO 2 /* Root inode */
#define EXT4_USR_QUOTA_INO 3 /* User quota inode */
#define EXT4_GRP_QUOTA_INO 4 /* Group quota inode */
#define EXT4_BOOT_LOADER_INO 5 /* Boot loader inode */
#define EXT4_UNDEL_DIR_INO 6 /* Undelete directory inode */
#define EXT4_RESIZE_INO 7 /* Reserved group descriptors inode */
#define EXT4_JOURNAL_INO 8 /* Journal inode */
Other fileystems use the ino 1 as root inode number. In general, a file system is free to choose its inode numbers and its reserved ino values (with the exception of 0).
OSX specifies that inode 0 signifies a deleted file that has not yet been deleted; this may have also been used in other filesystems, as OSX is BSD-derived, although at least NetBSD seems to have now removed this usage.
See the OSX manpage for getdirentries http://developer.apple.com/library/ios/#documentation/System/Conceptual/ManPages_iPhoneOS/man2/getdirentries.2.html
When I wrote a filesystem ages ago, I used inode 0 for the .badblocks pseudo-file.
On some filesystems .badblocks is actually present in the root directory as a regular file owned by root and mode 0. root can open it but reading or writing it is undefined.
There is some ancient tradition that inodes start from 1, #1 is .badblocks, and #2 is the root directory. Even though .badblocks is not particularly well-guaranteed, many filesystems go out of their way to make root #2.
Related
So to pull super block in file system (i.e. if my sda storage is ext2 formatted) is easy. I just need to skip 1024 bytes to get the super block fro sda storage
lseek(fd, 1024, SEEK_SET);
read(fd, &super_block, sizeof(super_block));
and to pull the group descriptor is also super easy (only if I understood correctly from looking at code)
lseek(fd, 1024 + [block_size_ext_1024_bytes]=1024, SEEK_SET);
read(fd, &block_group, sizeof(block_group));
or
lseek(fd, 1024 + 1024, SEEK_SET);
read(fd, &block_group, sizeof(block_group));
1024=Base offset
But I am not feeling at confort because the real challege I found is to pull inode is only I have file name. I know file names are stored in directory struct so first challege is to extract directory struct from there and in directory struct I can get the inode number. and from Inode number I can extract inode struct. but I do not know how to extract directory struct in ext2 formatted image. Can anyone please telll me this? thanks
Yes pulling super block is just a matter of skipping Base_Offset=1024 bytes in ext2 and then reading it like so
lseek(fd, BASE_OFFSET + block_size, SEEK_SET);
//BASE_OFFSET for EXT2 == 1024
read(fd, &super_block, sizeof(super_block));
block_size = 1024 << super_block.s_log_block_size;
printf("Block size is [%d]\n",super_block.s_log_block_size);
The size of a super-block is given by s_log_block_size. This value expresses the size of a block as a power of 2, using 1024(specifically for ext2) bytes as the unit. Thus, 0 denotes 1024-byte blocks, 1 denotes 2048-byte blocks, and so on. To calculate the size in bytes of a block:
unsigned int block_size = 1024 << super.s_log_block_size; /* block
super.s_log_block_size always 0 if need to hardcode 1024 and super.s_log_block_size is multiple of 2 so if 1024 block size super.s_log_block_size is should be 0
Then I can extract group descriptor. So for my image there is only one group descrptor. I dont know how many descriptor will I have if I have 1TB of storage as I do have this and file system is ext4. May be someone will tell me this.
Like this to extract group descriptor by further moving forward 1024 bytes
lseek(fd, BASE_OFFSET + block_size, SEEK_SET);
read(fd, &block_group, sizeof(block_group));
I think this gives the idea of finding out how many group desciptors are there in storage in ext2
unsigned int group_count = 1 + (super_block.s_blocks_count-1) / super_block.s_blocks_per_group;
so for example On my device image it has 128 blocks so first block always Boot info, second block contains super block, the third block contains first group descriptor -- still like to know what would be the offset of my second group descriptor if I had more space on my storage. Please someone shed light on this
Moving on, to extract specific inode the formula is this to seek the offset of specific inode
lseek(fd, BLOCK_OFFSET(block_group->bg_inode_table)+(inode_no-1)*sizeof(struct ext2_inode),
SEEK_SET);
bg_inode_table can be used to extract inode
The group descriptor tells us the location of the block/[inode bitmaps] and of the inode table (described later) through the bg_block_bitmap, bg_inode_bitmap and bg_inode_table fields.
Now to extract root inode=(should be ino_num=2) for example I just need to do
lseek(fd, BLOCK_OFFSET(block_group->bg_inode_table)+(2-1)*sizeof(struct ext2_inode),
SEEK_SET);
The block number of the first block of the inode table is stored in the bg_inode_table field of the group descriptor.
so inode table came to help in find specific inode
To extract the directory struct I just need to use inode.i_block[0] array. filled in last step
each i_block element is number that can be used in this way. basically a pointer points to actual blocks containing content of file with inode
lseek(...BASE_OFFSET+(i_block[x]-1)*block_size...)
block_size always 1024 for ext2
This way I can read the block at whose base contain directory struct in ext2 file system
read
void *block;
read(fd, block, block_size);
and the above line give me first directory mapped to specific inode
I can simple do a loop to get all entries
http://www.science.smith.edu/~nhowe/teaching/csc262/oldlabs/ext2.html
My OS is linux. I program in C. I know I can use the lstat() to recognize the soft link, i.e., use S_ISLNK(st.st_mode). But how can I recognize the link is hard link? if the link is hard link, it will be thought of as regular file. However, I also want to distinguish the regular file from the hard link. Are there any ways to handle this case?
But how can I recognize the link is hard link?
You can't.
A "hard link" isn't actually anything special. It's just a directory entry that happens to point to the same data on disk as a directory entry somewhere else. The only way to reliably identify hard links is to map all the paths on your filesystem to inodes, and then see which ones point to the same value.
struct stat has st_nlink member for number of hard links. It is > 1, file is being stated in one of the hard links to actual file content.
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
Here is sample program:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main()
{
struct stat buf = {0};
lstat("origfile", &buf);
printf("number of hard links for origfile: %d\n", buf.st_nlink);
}
output:
$ touch origfile
$ ./a.out
number of hard links for origfile: 1
$ ln origfile hardlink1
$ ./a.out
number of hard links for origfile: 2
$ ln origfile hardlink2
$ ./a.out
number of hard links for origfile: 3
I found many links but almost all are pointing to fix not the reason.
I created a 7GB ext4 partition on a sd card connected via USB card reader to PC. I have an application which is writing 10488576 bytes to the mentioned partition (/dev/sdc2). After the application run the filesystem is looking corrupt:
#fsck.ext4 -v /dev/sdc2
e2fsck 1.42.8 (20-Jun-2013)
ext2fs_open2: Bad magic number in super-block
fsck.ext4: Superblock invalid, trying backup blocks...
Superblock has an invalid journal (inode 8).
Clear<y>? no
fsck.ext4: Illegal inode number while checking ext3 journal for /dev/sdc2
/dev/sdc2: ***** FILE SYSTEM WAS MODIFIED *****
/dev/sdc2: ********** WARNING: Filesystem still has errors **********
#dumpe2fs /dev/sdc2
dumpe2fs 1.42.8 (20-Jun-2013)
dumpe2fs: Bad magic number in super-block while trying to open /dev/sdc2
Couldn't find valid filesystem superblock.
The application is simply using something like below (i can't post exact code):
char *write_buf; //declared in header
write_buf = (char *) malloc(size) // where size = 10488576. This allocation is happening in function a() called from main
char *buf; // declared locally in function b()
buf = write_buf; // in function b()
write(fd,buf,size); // in function b()
The filesystem block size is 4K.
Backup superblock at 32768 , 98304 ,163840 ,229376 , 294912 ,819200, 884736 ,1605632
Let me know if any more information required. I need to understand what might cause this corruption , because I'm very much affirmative that something may be wrong with application code.
EDIT:
I can see that primary superblock starts at 0 , and the lseek() call before write() is also doing SEEK_SET to 0, which would overwrite superblock information. I am going to try lseek far from superblock before write().
EDIT:
I have got this fixed by doing as I mentioned above. As per dumpe2fs o/p I had below for group 0:
Group 0: (Blocks 0-32767)
Checksum 0x8bba, unused inodes 8069
Primary superblock at 0, Group descriptors at 1-1
Reserved GDT blocks at 2-474
Block bitmap at 475 (+475), Inode bitmap at 491 (+491)
Inode table at 507-1011 (+507)
24175 free blocks, 8069 free inodes, 2 directories, 8069 unused inodes
Free blocks: 8593-32767
Free inodes: 12-8080
So before writing I did lseek to 8593*4096 .Now filesystem is not getting corrupt.
I have got this fixed by doing as I mentioned above. As per dumpe2fs o/p I had below for group 0:
Group 0: (Blocks 0-32767)
Checksum 0x8bba, unused inodes 8069
Primary superblock at 0, Group descriptors at 1-1
Reserved GDT blocks at 2-474
Block bitmap at 475 (+475), Inode bitmap at 491 (+491)
Inode table at 507-1011 (+507)
24175 free blocks, 8069 free inodes, 2 directories, 8069 unused inodes
Free blocks: 8593-32767
Free inodes: 12-8080
So before writing I did lseek to 8593*4096.Now filesystem is not getting corrupt.
I am working with batches of files that contain information about the same object at the different times of its life, and the only way to order them is by creation date.
I was using this:
//char* buffer has the name of file
struct stat buf;
FILE *tf;
tf = fopen(buffer,"r");
//check handle
fstat(tf, &buf);
fclose(tf);
pMyObj->lastchanged=buf.st_mtime;
But that does not seems to work.
What am I doing wrong? Are there other, more reliable/simple ways to get file creation date under Linux?
The nearest approximation to 'creation date' is the st_ctime member in the struct stat, but that actually records the last time the inode changed. If you create the file and never modify its size or permissions, that works as a creation time. Otherwise, there is no record of when the file was created, at least in standard Unix systems.
For your purposes, sort by st_mtime...or get the files named with a timestamp in the name.
Note that if you are on Darwin (Mac OS X), the creation time is available. From the man page for stat(2):
However, when the macro _DARWIN_FEATURE_64_BIT_INODE is defined, the stat structure will now be defined as:
struct stat { /* when _DARWIN_FEATURE_64_BIT_INODE is defined */
dev_t st_dev; /* ID of device containing file */
mode_t st_mode; /* Mode of file (see below) */
nlink_t st_nlink; /* Number of hard links */
ino_t st_ino; /* File serial number */
uid_t st_uid; /* User ID of the file */
gid_t st_gid; /* Group ID of the file */
dev_t st_rdev; /* Device ID */
struct timespec st_atimespec; /* time of last access */
struct timespec st_mtimespec; /* time of last data modification */
struct timespec st_ctimespec; /* time of last status change */
struct timespec st_birthtimespec; /* time of file creation(birth) */
off_t st_size; /* file size, in bytes */
blkcnt_t st_blocks; /* blocks allocated for file */
blksize_t st_blksize; /* optimal blocksize for I/O */
uint32_t st_flags; /* user defined flags for file */
uint32_t st_gen; /* file generation number */
int32_t st_lspare; /* RESERVED: DO NOT USE! */
int64_t st_qspare[2]; /* RESERVED: DO NOT USE! */
};
Note the st_birthtimespec field. Note, too, that all the times are in struct timespec values, so there is sub-second timing (tv_nsec gives nanosecond resolution). POSIX 2008 <sys/stat.h> requires the struct timespec time keeping on the standard times; Darwin follows that.
fstat works on file descriptors, not FILE structures. The simplest version:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#ifdef HAVE_ST_BIRTHTIME
#define birthtime(x) x.st_birthtime
#else
#define birthtime(x) x.st_ctime
#endif
int main(int argc, char *argv[])
{
struct stat st;
size_t i;
for( i=1; i<argc; i++ )
{
if( stat(argv[i], &st) != 0 )
perror(argv[i]);
printf("%i\n", birthtime(st));
}
return 0;
}
You will need to figure out if your system has st_birthtime in its stat structure by inspecting sys/stat.h or using some kind of autoconf construct.
File creation time is not stored anywhere, you can only retrieve one of the following:
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
Your code should give you the last modification time, however. Note: you can use stat() instead of fstat() without opening the file (stat() takes the file name as param).
To get the file creation date in linux, I use the following method
root#sathishkumar# cat << _eof > test.txt
> Hello
> This is my test file
> _eof
root#sathishkumar# cat test.txt
Hello
This is my test file
root#sathishkumar# ls -i test.txt
2097517 test.txt
root#sathishkumar# debugfs -R 'stat <2097517>' /dev/sda5
Inode: 2097517 Type: regular Mode: 0664 Flags: 0x80000
Generation: 4245143992 Version: 0x00000000:00000001
User: 1000 Group: 1000 Size: 27
File ACL: 0 Directory ACL: 0
Links: 1 Blockcount: 8
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x50ea6d84:4826cc94 -- Mon Jan 7 12:09:00 2013
atime: 0x50ea6d8e:75ed8a04 -- Mon Jan 7 12:09:10 2013
mtime: 0x50ea6d84:4826cc94 -- Mon Jan 7 12:09:00 2013
crtime: 0x5056d493:bbabf49c -- Mon Sep 17 13:13:15 2012
Size of extra inode fields: 28
EXTENTS:
(0):8421789
atime: Last time file was opened or executed
ctime: Time the inode information was updated. ctime also gets updated when file is modified
mtime: Last modified time
crtime: File creation time
For recent Linux versions, there is xstat which includes btime. https://unix.stackexchange.com/a/407305/103120
I am trying to implement the ls command in C without using the system function.
Is there a C function to get the directory/file permissions, so that I can display them?
Thanks.
The stat() system call takes a filename string and returns the following structure:
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
This works equally well on directory entries as well as files and the st_mode is the specific field you're looking for.
The <sys/stat.h> header file should contain that structure and all the definitions along with #defines and/or macros for intelligently decoding the fields (see here for a sample).
If you're interested in how it's really done, you can look at the ls source code in GNU coreutils. But only use that to educate yourself. It's GPL so you can't just grab it for your own purposes and, if this is homework, your educator will almost certainly fail you if you turn in something that looks too similar to this.
Look into stat(). Sounds like you're on a Linux or POSIX system, so that should be the way.
Then look at the st_mode field of the struct stat, it contains the information about protection bits, which are often collectively called a file's "mode" (as reflected by the chmod command that changes the settings).
Going from the binary bits to a textual representation like ls' is ... an interesting challenge.
The stat functions family (stat(), lstat(), fstat()).