1 /* 2 * Copyright 1999-2001, Be Incorporated. All Rights Reserved. 3 * Copyright 2024, Haiku, Inc. All rights reserved. 4 * This file may be used under the terms of the Be Sample Code License. 5 */ 6 7 8 #include "debug.h" 9 10 #include <stdlib.h> 11 12 #ifdef FS_SHELL 13 #include "fssh_api_wrapper.h" 14 #endif 15 16 #define _KERNEL 17 18 extern "C" 19 { 20 #include "sys/param.h" 21 #include "sys/buf.h" 22 #include "sys/conf.h" 23 #include "sys/iconv.h" 24 #include "sys/mount.h" 25 #include "sys/mutex.h" 26 #include "sys/namei.h" 27 #include "sys/vnode.h" 28 29 #include "fs/msdosfs/bootsect.h" 30 #include "fs/msdosfs/bpb.h" 31 #include "fs/msdosfs/denode.h" 32 #include "fs/msdosfs/direntry.h" 33 #include "fs/msdosfs/fat.h" 34 #include "fs/msdosfs/msdosfsmount.h" 35 } 36 37 #include "vcache.h" 38 39 40 static status_t 41 _dump_volume(const mount* bsdVolume, void (*printFunc)(const char*, ...)) 42 { 43 #ifdef _KERNEL_MODE 44 if (bsdVolume == NULL) 45 return B_BAD_VALUE; 46 47 msdosfsmount* fatVolume = reinterpret_cast<msdosfsmount*>(bsdVolume->mnt_data); 48 49 cdev* dev = fatVolume->pm_dev; 50 51 if (FAT12(fatVolume) == true) 52 printFunc("FAT12 volume "); 53 else if (FAT16(fatVolume)) 54 printFunc("FAT16 volume "); 55 else if (FAT32(fatVolume)) 56 printFunc("FAT32 volume "); 57 printFunc("@ %p\n", bsdVolume); 58 printFunc("volume label [%s], file %s, device %" B_PRIdDEV ", fd %u,\n", dev->si_name, 59 dev->si_device, dev->si_id, dev->si_fd); 60 printFunc("mounted at %s\n", bsdVolume->mnt_stat.f_mntonname); 61 printFunc("msdosfsmount flags 0x%" B_PRIx64 ", media descriptor 0x%" B_PRIx8 "\n", 62 fatVolume->pm_flags, fatVolume->pm_Media); 63 printFunc("%" B_PRIu32 " bytes/sector, %lu sectors/cluster\n", fatVolume->pm_BytesPerSec, 64 SECTORS_PER_CLUSTER(fatVolume)); 65 printFunc("%" B_PRIu16 " reserved sectors, %" B_PRIu16 " FATs, %lu blocks per FAT\n", 66 fatVolume->pm_ResSectors, fatVolume->pm_FATs, fatVolume->pm_FATsecs); 67 if (FAT32(fatVolume) == true) { 68 printFunc("fat mirroring is %s, fs info sector at block %lu, data start block %lu\n", 69 fatVolume->pm_curfat == 0 ? "on" : "off", fatVolume->pm_fsinfo, 70 fatVolume->pm_firstcluster); 71 } else { 72 printFunc("root start block %lu, %lu root blocks, data start block %lu\n", 73 fatVolume->pm_rootdirblk, fatVolume->pm_rootdirsize, fatVolume->pm_firstcluster); 74 } 75 printFunc("%" B_PRIu32 " total blocks, %lu max cluster number, %lu free clusters\n", 76 fatVolume->pm_HugeSectors, fatVolume->pm_maxcluster, fatVolume->pm_freeclustercount); 77 printFunc("last fake vnid %" B_PRIdINO ", vnid cache @ (%p %p)\n", bsdVolume->vcache.cur_vnid, 78 bsdVolume->vcache.by_vnid, bsdVolume->vcache.by_loc); 79 80 dump_vcache(bsdVolume); 81 #endif // _KERNEL_MODE 82 83 return B_OK; 84 } 85 86 87 int 88 kprintf_volume(int argc, char** argv) 89 { 90 if ((argc == 1) || strcmp(argv[1], "--help") == 0) { 91 kprintf("usage: fat <address>\n" 92 " address: address of a FAT private volume (struct mount)\n" 93 " Use 'mounts' to list mounted volume ids, and 'mount <id>' to display a private " 94 "volume address.\n"); 95 return 0; 96 } 97 98 mount* bsdVolume = reinterpret_cast<mount*>(strtoul(argv[1], NULL, 0)); 99 100 return _dump_volume(bsdVolume, kprintf); 101 } 102 103 104 status_t 105 dprintf_volume(mount* bsdVolume) 106 { 107 #ifdef _KERNEL_MODE 108 return _dump_volume(bsdVolume, dprintf); 109 #else 110 return B_OK; 111 #endif // !_KERNEL_MODE 112 } 113 114 115 static status_t 116 _dump_node(const vnode* bsdNode, void (*printFunc)(const char*, ...)) 117 { 118 #ifdef _KERNEL_MODE 119 if (bsdNode == NULL) 120 return B_BAD_VALUE; 121 122 denode* fatNode = reinterpret_cast<denode*>(bsdNode->v_data); 123 124 printFunc("private node @ %p\n", bsdNode); 125 printFunc("inode # %lu\n", fatNode->de_inode); 126 if (bsdNode->v_type == VNON) 127 printFunc("v_type VNON, "); 128 else if (bsdNode->v_type == VDIR) 129 printFunc("v_type VDIR, "); 130 else if (bsdNode->v_type == VREG) 131 printFunc("v_type VREG, "); 132 if (bsdNode->v_state == VSTATE_UNINITIALIZED) 133 printFunc("v_state VSTATE_UNINITIALIZED\n"); 134 else if (bsdNode->v_state == VSTATE_CONSTRUCTED) 135 printFunc("v_state VSTATE_CONSTRUCTED\n"); 136 printFunc("short name %s\n", fatNode->de_Name); 137 printFunc("entry cluster %lu\n", fatNode->de_dirclust); 138 printFunc("entry offset %lu\n", fatNode->de_diroffset); 139 printFunc("file start cluster %lu\n", fatNode->de_StartCluster); 140 printFunc("size %lu bytes\n", fatNode->de_FileSize); 141 printFunc("rw lock @ %p\n", &bsdNode->v_vnlock->haikuRW); 142 #endif // _KERNEL_MODE 143 144 return B_OK; 145 } 146 147 148 int 149 kprintf_node(int argc, char** argv) 150 { 151 if ((argc == 1) || strcmp(argv[1], "--help") == 0) { 152 kprintf("usage: fat_node <address>\n" 153 " address: address of a FAT private node (BSD struct vnode)\n" 154 " Node addresses can be found with the 'vnodes' command.\n" 155 " If the driver was built with the DEBUG flag, the command 'fat' lists node" 156 "addresses\n"); 157 return B_OK; 158 } 159 160 vnode* bsdNode = reinterpret_cast<vnode*>(strtoul(argv[1], NULL, 0)); 161 162 return _dump_node(bsdNode, kprintf); 163 } 164 165 166 status_t 167 dprintf_node(vnode* bsdNode) 168 { 169 #ifdef _KERNEL_MODE 170 return _dump_node(bsdNode, dprintf); 171 #else 172 return B_OK; 173 #endif // !_KERNEL_MODE 174 } 175 176 177 status_t 178 dprintf_winentry(msdosfsmount* fatVolume, winentry* entry, const uint32* index) 179 { 180 #ifdef DEBUG 181 uint8 order = entry->weCnt & ~WIN_LAST; 182 mbnambuf namePart; 183 mbnambuf_init(&namePart); 184 win2unixfn(&namePart, entry, entry->weChksum, fatVolume); 185 186 namePart.nb_buf[(order - 1) * 14 + namePart.nb_len] = '\0'; 187 char* namePtr = namePart.nb_buf + (order - 1) * 13; 188 189 const char* lastNote; 190 if ((entry->weCnt & WIN_LAST) != 0) 191 lastNote = " (last one)"; 192 else 193 lastNote = ""; 194 195 PRINT("index %" B_PRIu32 ": winentry %u%s, checksum %u, filename part %s\n", *index, order, 196 lastNote, entry->weChksum, namePtr); 197 #endif // DEBUG 198 199 return B_OK; 200 } 201