dir.c (3276B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * QNX4 file system, Linux implementation. 4 * 5 * Version : 0.2.1 6 * 7 * Using parts of the xiafs filesystem. 8 * 9 * History : 10 * 11 * 28-05-1998 by Richard Frowijn : first release. 12 * 20-06-1998 by Frank Denis : Linux 2.1.99+ & dcache support. 13 */ 14 15#include <linux/buffer_head.h> 16#include "qnx4.h" 17 18/* 19 * A qnx4 directory entry is an inode entry or link info 20 * depending on the status field in the last byte. The 21 * first byte is where the name start either way, and a 22 * zero means it's empty. 23 * 24 * Also, due to a bug in gcc, we don't want to use the 25 * real (differently sized) name arrays in the inode and 26 * link entries, but always the 'de_name[]' one in the 27 * fake struct entry. 28 * 29 * See 30 * 31 * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578#c6 32 * 33 * for details, but basically gcc will take the size of the 34 * 'name' array from one of the used union entries randomly. 35 * 36 * This use of 'de_name[]' (48 bytes) avoids the false positive 37 * warnings that would happen if gcc decides to use 'inode.di_name' 38 * (16 bytes) even when the pointer and size were to come from 39 * 'link.dl_name' (48 bytes). 40 * 41 * In all cases the actual name pointer itself is the same, it's 42 * only the gcc internal 'what is the size of this field' logic 43 * that can get confused. 44 */ 45union qnx4_directory_entry { 46 struct { 47 const char de_name[48]; 48 u8 de_pad[15]; 49 u8 de_status; 50 }; 51 struct qnx4_inode_entry inode; 52 struct qnx4_link_info link; 53}; 54 55static int qnx4_readdir(struct file *file, struct dir_context *ctx) 56{ 57 struct inode *inode = file_inode(file); 58 unsigned int offset; 59 struct buffer_head *bh; 60 unsigned long blknum; 61 int ix, ino; 62 int size; 63 64 QNX4DEBUG((KERN_INFO "qnx4_readdir:i_size = %ld\n", (long) inode->i_size)); 65 QNX4DEBUG((KERN_INFO "pos = %ld\n", (long) ctx->pos)); 66 67 while (ctx->pos < inode->i_size) { 68 blknum = qnx4_block_map(inode, ctx->pos >> QNX4_BLOCK_SIZE_BITS); 69 bh = sb_bread(inode->i_sb, blknum); 70 if (bh == NULL) { 71 printk(KERN_ERR "qnx4_readdir: bread failed (%ld)\n", blknum); 72 return 0; 73 } 74 ix = (ctx->pos >> QNX4_DIR_ENTRY_SIZE_BITS) % QNX4_INODES_PER_BLOCK; 75 for (; ix < QNX4_INODES_PER_BLOCK; ix++, ctx->pos += QNX4_DIR_ENTRY_SIZE) { 76 union qnx4_directory_entry *de; 77 78 offset = ix * QNX4_DIR_ENTRY_SIZE; 79 de = (union qnx4_directory_entry *) (bh->b_data + offset); 80 81 if (!de->de_name[0]) 82 continue; 83 if (!(de->de_status & (QNX4_FILE_USED|QNX4_FILE_LINK))) 84 continue; 85 if (!(de->de_status & QNX4_FILE_LINK)) { 86 size = sizeof(de->inode.di_fname); 87 ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1; 88 } else { 89 size = sizeof(de->link.dl_fname); 90 ino = ( le32_to_cpu(de->link.dl_inode_blk) - 1 ) * 91 QNX4_INODES_PER_BLOCK + 92 de->link.dl_inode_ndx; 93 } 94 size = strnlen(de->de_name, size); 95 QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n", size, name)); 96 if (!dir_emit(ctx, de->de_name, size, ino, DT_UNKNOWN)) { 97 brelse(bh); 98 return 0; 99 } 100 } 101 brelse(bh); 102 } 103 return 0; 104} 105 106const struct file_operations qnx4_dir_operations = 107{ 108 .llseek = generic_file_llseek, 109 .read = generic_read_dir, 110 .iterate_shared = qnx4_readdir, 111 .fsync = generic_file_fsync, 112}; 113 114const struct inode_operations qnx4_dir_inode_operations = 115{ 116 .lookup = qnx4_lookup, 117};