I'm reading the Understand the Linux Kernel book, and it says that the list of file_lock is stored in the file's inode (of field i_flock).
But in the sys_flock() of Linux 2.6.11.12, which will eventually call flock_lock_file(). It uses filp->f_dentry->d_inode->i_flock to get the list of file_lock and filp->f_dentry is an dentry of the directory which "contains" the file.
int flock_lock_file(struct file *filp, struct file_lock *new_fl) {
// ...
struct inode * inode = filp->f_dentry->d_inode;
// ...
}
Suppose that the file_lock list are linked with filp->f_dentry->d_inode->i_flock, What will happen when a hard link exists:
/some_path/foo/file.txt
/another_path/bar/file_link
and file_link is a hard link to file.txt
When we use this two path to open the same file, sys_open() will set filp->f_dentry to foo and bar separately, isn't it? If my guess is right, how file_lock can work?
The file_lock is indeed stored in the inode of the corresponding file.
An inode can be referred by several directory entries, which linked in inode's i_dentry field. Even for a unique file might have different filp->f_dentry, filp->f_dentry->d_inode is all refer to the same inode.
Related
I have a vnode and I want to get the protection bits (sticky bit, write bit, etc.) of its associated file. I know I can get the vnode's vattr struct which contains a field called u_short va_mode; /* files access mode and type */.
However, I was wondering if this is the same thing as the vnode's associated file's mode_t st_mode; /* inode protection mode */. Does anybody know if these would be the same for a given vnode and its associated file?
My final goal is to see if a sticky bit is set for a vnode's assocated file.
The st_mode in struct stat is set from the vnode's va_mode, with the addition of a flag based on vnode type (eg VREG or VDIR). Take a look at http://fxr.watson.org/fxr/source/kern/vfs_vnops.c#L1428; that's the piece of code that fills in the struct stat.
I am pulling data from a server and one of the folder name is longer than 256 bytes, so my CentOS is throwing an error that the name is too long. I have searched all over the internet but couldn't find any way to create a folder/file name with size of over 256 bytes under ext2/ext3/ext4 file systems.
However, One solution had suggested to create reiserfs file system alongside ext4 to handle files\folder with longer names. This solution might work, but I just read in one of the book that it is possible to extend the limit of filename size from 255 characters to 1012 characters if needed.
The maximal file name size is 255 characters. This limit could be extended to `1012` if needed.
Source: Google
But I couldn't find any website that explains how the filesystem could be modified to extend the size to 1012?
Can someone please help me with that?
Don't know where 1012 was found (mentioned in http://e2fsprogs.sourceforge.net/ext2intro.html - Design and Implementation of the Second Extended Filesystem, ISBN 90-367-0385-9. 1995), but in modern Linux kernel file name is fixed in struct ext2_dir_entry_2 with maximum of 255 chars (bytes):
https://elixir.bootlin.com/linux/v4.10/source/fs/ext2/ext2.h#L600
/*
* The new version of the directory entry. Since EXT2 structures are
* stored in intel byte order, and the name_len field could never be
* bigger than 255 chars, it's safe to reclaim the extra byte for the
* file_type field.
*/
struct ext2_dir_entry_2 {
__le32 inode; /* Inode number */
__le16 rec_len; /* Directory entry length */
__u8 name_len; /* Name length */
__u8 file_type;
char name[]; /* File name, up to EXT2_NAME_LEN */
};
There was struct ext2_dir_entry with longer file name length, but extra byte of name_len was redefined as file_type.
__le16 name_len; /* Name length */
So, current maximum file name length for ext2 is 255
https://elixir.bootlin.com/linux/v4.10/source/include/linux/ext2_fs.h#L22
#define EXT2_NAME_LEN 255
https://elixir.bootlin.com/linux/v4.10/source/fs/ext2/namei.c#L62
if (dentry->d_name.len > EXT2_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
Same for ext3/ext4:
https://elixir.bootlin.com/linux/v4.10/source/fs/ext4/ext4.h#L1892
/*
* Structure of a directory entry
*/
#define EXT4_NAME_LEN 255
https://elixir.bootlin.com/linux/v4.10/source/fs/ext4/namei.c
* `len <= EXT4_NAME_LEN' is guaranteed by caller.
if (namelen > EXT4_NAME_LEN)
return NULL;
if (dentry->d_name.len > EXT4_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
Ondisk format is described with 8 bit file_name too (file_type uses only 3 bits in older docs - EXT2_FT_MAX, but modern driver will not handle 255+ file names. ext4 has extra FT of 0xde):
http://www.nongnu.org/ext2-doc/ext2.html#IFDIR-NAME-LEN "4.1.3. name_len - 8bit unsigned value indicating how many bytes of character data are contained in the name."
http://cs.smith.edu/~nhowe/262/oldlabs/ext2.html#direntry "The file_type field indicates what kind of file the entry is referring to... The maximum length of a file name is EXT2_NAME_LEN, which is usually 255."
https://oss.oracle.com/projects/ocfs2/dist/documentation/disklayout.pdf#page=16 "__u8 name_len"
See https://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits, not a lot of filesystems handle filenames of more than 255 bytes.
While it may not be a direct reply to your question, I do not think you should try to go this route (changing the maximum length).
From what server do you retrieve your files? Why not changing their name when doing the retrieval?
Are you sure that the whole path name is relevant, if you extract the first or last 250 characters isn't it enough to reference each file without ambiguity?
You have many options, depending on your constraints:
either generate "random" names (or sequential ones), and just store in a text file the mapping between old true name and the new fake name
or split the initial name in 250 characters path elements (or something like that) and create intermediate directories with them
You can find similar discussion at https://serverfault.com/questions/264339/how-to-increase-filename-size-limit-on-ext3-on-ubuntu
I am trying to create patch a file using diff tool.But facing an issues.
I have created one directory named a and put original file in to it:
a/original_file.c
I have created other directory named b and put same file with modified content in to it.
b/original_file.c
I have copied the content of the b/original_file.c file from the internet and put it into some text editor.
After giving command diff -Naur a b > patch_file.patch, I can see patch_file.patch is generated and it has some unwanted changes (it's related to indentation).
For example:
return msg (MSG_NOTIFY, &msg, senr,
- sizeof (struct msgotify));
+ sizeof (struct msgotify));
You can see there are changed related to indentation where sizeof (struct msgotify)) is replaced by same sizeof (struct msgotify)) but one basis of indentation which is what we don't want.
Could anybody let me know how to get rid of this problem??
If you don't care about changes in spacing, add -b to the diff command that generates the patch.
Please explain this statement:
directory_path=dentry_path_raw(lower_dentry,buf,buflen);
also give an example of how does it work
What fields does struct dentry contain?
What does the s_root field point to?
What does the field s_root contain?
You can check the fields of dentry here. dentry_path_raw puts the full path of the directory entry from the root of the file system into the buffer. s_root is a member of super block defined in linux/fs.h and is the root of the file system, which is a dentry.
char *dentry_path_raw(struct dentry *dentry, char *buf, int buflen)
The above function returns full pathname from root of the file system into the buffer.Each field is explained as below.
#dentry-dentry of a file to lookup
#buf-buffer to store path to
#buflen-length of #buf
For more detail check fs/dcache.c file.
I'm trying to check if a folder has any subfolders without iterating through its children, in Linux. The closest I've found so far is using ftw and stopping at the first subfolder - or using scandir and filtering through the results. Both, are, however, an overkill for my purposes, I simply want a yes/no.
On Windows, this is done by calling SHGetFileInfo and then testing dwAttributes & SFGAO_HASSUBFOLDER on the returned structure. Is there such an option on Linux?
The standard answer is to call stat on the directory, then check the st_nlink field ("number of hard links"). On a standard filesystem, each directory is guaranteed to have 2 hard links (. and the link from the parent directory to the current directory), so each hard link beyond 2 indicates a subdirectory (specifically, the subdirectory's .. link to the current directory).
However, it's my understanding that filesystems aren't required to implement this (see, e.g., this mailing list posting), so it's not guaranteed to work.
Otherwise, you have to do as you're doing:
Iterate over the directory's contents using glob with the GNU-specific GLOB_ONLYDIR flag, or scandir, or readdir.
Call stat on each result and check S_ISDIR(s.st_mode) to verify that files found are directories. Or, nonportably, check struct dirent.d_type: if it's DT_DIR then it's a file, and if it's DT_UNKNOWN, you'll have to stat it after all.
The possibilities you've mentioned (as well as e.James's) seem to me like they're better suited to a shell script than a C++ program. Presuming the "C++" tag was intentional, I think you'd probably be better off using the POSIX API directly:
// warning: untested code.
bool has_subdir(char const *dir) {
std::string dot("."), dotdot("..");
bool found_subdir = false;
DIR *directory;
if (NULL == (directory = opendir(dir)))
return false;
struct dirent *entry;
while (!found_subdir && ((entry = readdir(directory)) != NULL)) {
if (entry->d_name != dot && entry->d_name != dotdot) {
struct stat status;
stat(entry->d_name, &status);
found_subdir = S_ISDIR(status.st_mode);
}
}
closedir(directory);
return found_subdir;
}
Does getdirentries do want you want it to do? I think it shoudl return nothing if there are no directories. I would have tried this myself but am temporarily without access to a linux box :(