Grok 20.3.2
NetworkFileChecker.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2016-2026 Grok Image Compression Inc.
3 *
4 * This source code is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License, version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This source code is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Affero General Public License for more details.
12 *
13 * You should have received a copy of the GNU Affero General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#pragma once
19
20#ifndef _WIN32
21#include <sys/stat.h>
22#include <unistd.h>
23#include <sys/sysmacros.h> // For major() and minor() macros
24#endif
25
26#include <iostream>
27#include <fstream>
28#include <sstream>
29#include <string>
30#include <unordered_map>
31
32namespace grk
33{
34
36{
37public:
38 NetworkFileChecker() = default;
39
40 // Check if the file is on iSCSI storage with caching
41 bool isIscsi(const std::string& filePath)
42 {
43 bool result = false;
44#ifndef _WIN32
45 struct stat fileStat;
46 if(stat(filePath.c_str(), &fileStat) != 0)
47 {
48 perror("stat");
49 return false;
50 }
51
52 // Get the major and minor device numbers from the file's stat
53 dev_t device = fileStat.st_dev;
54 auto majorNum = major(device);
55 auto minorNum = minor(device);
56
57 // Get the device path
58 std::string devicePath = getDevicePath(majorNum, minorNum);
59 if(devicePath.empty())
60 {
61 std::cerr << "Failed to find the device path.\n";
62 return false;
63 }
64
65 // Check the cache first
66 if(deviceCache.find(devicePath) != deviceCache.end())
67 {
68 return deviceCache[devicePath];
69 }
70
71 // Perform the iSCSI check and cache the result
72 result = isIscsiDevice(devicePath);
73 deviceCache[devicePath] = result;
74#endif
75 return result;
76 }
77
78 // Get block size if the file is on iSCSI storage
79 int getBlockSize(const std::string& filePath)
80 {
81#ifndef _WIN32
82 if(isIscsi(filePath))
83 {
84 struct stat fileStat;
85 if(stat(filePath.c_str(), &fileStat) != 0)
86 {
87 perror("stat");
88 return -1;
89 }
90
91 // Get the major and minor device numbers
92 dev_t device = fileStat.st_dev;
93 auto majorNum = major(device);
94 auto minorNum = minor(device);
95
96 // Find the block device path
97 std::string devicePath = getDevicePath(majorNum, minorNum);
98 if(devicePath.empty())
99 return -1;
100
101 // Read the block size from /sys/class/block/<device>/queue/logical_block_size
102 std::string blockSizePath =
103 "/sys/class/block/" + getDeviceName(devicePath) + "/queue/logical_block_size";
104 std::ifstream blockSizeFile(blockSizePath);
105 int blockSize = -1;
106 if(blockSizeFile >> blockSize)
107 {
108 return blockSize;
109 }
110 std::cerr << "Failed to get block size.\n";
111 return -1;
112 }
113#endif
114
115 std::cerr << "The file is not on iSCSI storage.\n";
116 return -1;
117 }
118
119 // Get optimal fetch size from /sys/class/block/<device>/queue/optimal_io_size
120 int getOptimalFetchSize(const std::string& filePath)
121 {
122#ifndef _WIN32
123 struct stat fileStat;
124 if(stat(filePath.c_str(), &fileStat) != 0)
125 {
126 perror("stat");
127 return -1;
128 }
129
130 // Get the major and minor device numbers
131 dev_t device = fileStat.st_dev;
132 auto majorNum = major(device);
133 auto minorNum = minor(device);
134
135 // Find the block device path
136 std::string devicePath = getDevicePath(majorNum, minorNum);
137 if(devicePath.empty())
138 return -1;
139
140 // Read the optimal I/O size from /sys/class/block/<device>/queue/optimal_io_size
141 std::string optimalSizePath =
142 "/sys/class/block/" + getDeviceName(devicePath) + "/queue/optimal_io_size";
143 std::ifstream optimalSizeFile(optimalSizePath);
144 int optimalSize = -1;
145 if(optimalSizeFile >> optimalSize)
146 {
147 return optimalSize;
148 }
149#endif
150 std::cerr << "Failed to get optimal fetch size.\n";
151 return -1;
152 }
153
154 bool isNetworkDrive(const std::string& filePath)
155 {
156#ifndef _WIN32
157 // Check if it's an iSCSI device
158 if(isIscsi(filePath))
159 {
160 return true;
161 }
162
163 // Check /proc/mounts for network file systems like NFS or CIFS
164 std::ifstream mounts("/proc/mounts");
165 std::string line;
166
167 while(std::getline(mounts, line))
168 {
169 std::istringstream iss(line);
170 std::string devPath, mountPoint, fsType;
171
172 iss >> devPath >> mountPoint >> fsType;
173
174 // If the file path matches the mount point and the file system is NFS or CIFS
175 if(filePath.find(mountPoint) == 0 && (fsType == "nfs" || fsType == "cifs"))
176 {
177 return true; // File is on a network file system
178 }
179 }
180#endif
181 return false; // File is on local storage
182 }
183
184private:
185 // Caching whether a device is iSCSI
186 std::unordered_map<std::string, bool> deviceCache;
187
188 // Helper function to get device path from major/minor number
189 std::string getDevicePath(uint32_t majorNum, uint32_t minorNum)
190 {
191#ifndef _WIN32
192 std::ifstream mounts("/proc/mounts");
193 std::string line;
194
195 while(std::getline(mounts, line))
196 {
197 std::istringstream iss(line);
198 std::string devPath, mountPoint;
199
200 iss >> devPath >> mountPoint;
201
202 struct stat devStat;
203 if(stat(devPath.c_str(), &devStat) == 0)
204 {
205 if(major(devStat.st_rdev) == majorNum && minor(devStat.st_rdev) == minorNum)
206 {
207 return devPath;
208 }
209 }
210 }
211#endif
212 return "";
213 }
214
215 // Check if the device is part of an iSCSI session
216 bool isIscsiDevice(const std::string& devicePath)
217 {
218 // Read the /sys/class/block/<device>/device/modalias to check for "iscsi"
219 std::string modaliasPath = "/sys/class/block/" + getDeviceName(devicePath) + "/device/modalias";
220 std::ifstream modaliasFile(modaliasPath);
221 std::string modalias;
222 if(modaliasFile >> modalias)
223 {
224 return modalias.find("scsi") != std::string::npos;
225 }
226 return false;
227 }
228
229 // Helper function to extract the device name from the device path
230 std::string getDeviceName(const std::string& devicePath)
231 {
232 size_t pos = devicePath.find_last_of('/');
233 if(pos != std::string::npos)
234 {
235 return devicePath.substr(pos + 1);
236 }
237 return devicePath;
238 }
239};
240
241} // namespace grk
bool isIscsi(const std::string &filePath)
Definition NetworkFileChecker.h:41
int getOptimalFetchSize(const std::string &filePath)
Definition NetworkFileChecker.h:120
bool isNetworkDrive(const std::string &filePath)
Definition NetworkFileChecker.h:154
bool isIscsiDevice(const std::string &devicePath)
Definition NetworkFileChecker.h:216
std::string getDevicePath(uint32_t majorNum, uint32_t minorNum)
Definition NetworkFileChecker.h:189
std::unordered_map< std::string, bool > deviceCache
Definition NetworkFileChecker.h:186
std::string getDeviceName(const std::string &devicePath)
Definition NetworkFileChecker.h:230
int getBlockSize(const std::string &filePath)
Definition NetworkFileChecker.h:79
ResWindow.
Definition CompressedChunkCache.h:36