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
_dump_volume(const mount * bsdVolume,void (* printFunc)(const char *,...))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
kprintf_volume(int argc,char ** argv)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
dprintf_volume(mount * bsdVolume)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
_dump_node(const vnode * bsdNode,void (* printFunc)(const char *,...))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
kprintf_node(int argc,char ** argv)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
dprintf_node(vnode * bsdNode)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
dprintf_winentry(msdosfsmount * fatVolume,winentry * entry,const uint32 * index)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