PageRenderTime 57ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/src/kits/storage/Volume.cpp

http://github.com/Barrett17/Haiku-services-branch
C++ | 569 lines | 261 code | 50 blank | 258 comment | 130 complexity | 93f4325ce55d33605444102db14783ec MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0, LGPL-2.0, LGPL-2.1, BSD-2-Clause, ISC, Apache-2.0, AGPL-1.0, MIT, MPL-2.0-no-copyleft-exception, Unlicense, BSD-3-Clause, LGPL-3.0
  1. /*
  2. * Copyright 2002-2009, Haiku Inc. All Rights Reserved.
  3. * Distributed under the terms of the MIT License.
  4. *
  5. * Authors:
  6. * Tyler Dauwalder
  7. * Ingo Weinhold
  8. */
  9. /*!
  10. \file Volume.h
  11. BVolume implementation.
  12. */
  13. #include <errno.h>
  14. #include <string.h>
  15. #include <Bitmap.h>
  16. #include <Directory.h>
  17. #include <fs_info.h>
  18. #include <Node.h>
  19. #include <Path.h>
  20. #include <Volume.h>
  21. #include <storage_support.h>
  22. #include <syscalls.h>
  23. #include <fs_interface.h>
  24. /*!
  25. \class BVolume
  26. \brief Represents a disk volume
  27. Provides an interface for querying information about a volume.
  28. The class is a simple wrapper for a \c dev_t and the function
  29. fs_stat_dev. The only exception is the method is SetName(), which
  30. sets the name of the volume.
  31. \author Vincent Dominguez
  32. \author <a href='mailto:bonefish@users.sf.net'>Ingo Weinhold</a>
  33. \version 0.0.0
  34. */
  35. /*! \var dev_t BVolume::fDevice
  36. \brief The volume's device ID.
  37. */
  38. /*! \var dev_t BVolume::fCStatus
  39. \brief The object's initialization status.
  40. */
  41. // constructor
  42. /*! \brief Creates an uninitialized BVolume.
  43. InitCheck() will return \c B_NO_INIT.
  44. */
  45. BVolume::BVolume()
  46. : fDevice((dev_t)-1),
  47. fCStatus(B_NO_INIT)
  48. {
  49. }
  50. // constructor
  51. /*! \brief Creates a BVolume and initializes it to the volume specified
  52. by the supplied device ID.
  53. InitCheck() should be called to check whether the initialization was
  54. successful.
  55. \param device The device ID of the volume.
  56. */
  57. BVolume::BVolume(dev_t device)
  58. : fDevice((dev_t)-1),
  59. fCStatus(B_NO_INIT)
  60. {
  61. SetTo(device);
  62. }
  63. // copy constructor
  64. /*! \brief Creates a BVolume and makes it a clone of the supplied one.
  65. Afterwards the object refers to the same device the supplied object
  66. does. If the latter is not properly initialized, this object isn't
  67. either.
  68. \param volume The volume object to be cloned.
  69. */
  70. BVolume::BVolume(const BVolume &volume)
  71. : fDevice(volume.fDevice),
  72. fCStatus(volume.fCStatus)
  73. {
  74. }
  75. // destructor
  76. /*! \brief Frees all resources associated with the object.
  77. Does nothing.
  78. */
  79. BVolume::~BVolume()
  80. {
  81. }
  82. // InitCheck
  83. /*! \brief Returns the result of the last initialization.
  84. \return
  85. - \c B_OK: The object is properly initialized.
  86. - an error code otherwise
  87. */
  88. status_t
  89. BVolume::InitCheck(void) const
  90. {
  91. return fCStatus;
  92. }
  93. // SetTo
  94. /*! \brief Re-initializes the object to refer to the volume specified by
  95. the supplied device ID.
  96. \param device The device ID of the volume.
  97. \param
  98. - \c B_OK: Everything went fine.
  99. - an error code otherwise
  100. */
  101. status_t
  102. BVolume::SetTo(dev_t device)
  103. {
  104. // uninitialize
  105. Unset();
  106. // check the parameter
  107. status_t error = (device >= 0 ? B_OK : B_BAD_VALUE);
  108. if (error == B_OK) {
  109. fs_info info;
  110. if (fs_stat_dev(device, &info) != 0)
  111. error = errno;
  112. }
  113. // set the new value
  114. if (error == B_OK)
  115. fDevice = device;
  116. // set the init status variable
  117. fCStatus = error;
  118. return fCStatus;
  119. }
  120. // Unset
  121. /*! \brief Uninitialized the BVolume.
  122. */
  123. void
  124. BVolume::Unset()
  125. {
  126. fDevice = (dev_t)-1;
  127. fCStatus = B_NO_INIT;
  128. }
  129. // Device
  130. /*! \brief Returns the device ID of the volume the object refers to.
  131. \return Returns the device ID of the volume the object refers to
  132. or -1, if the object is not properly initialized.
  133. */
  134. dev_t
  135. BVolume::Device() const
  136. {
  137. return fDevice;
  138. }
  139. // GetRootDirectory
  140. /*! \brief Returns the root directory of the volume referred to by the object.
  141. \param directory A pointer to a pre-allocated BDirectory to be initialized
  142. to the volume's root directory.
  143. \return
  144. - \c B_OK: Everything went fine.
  145. - \c B_BAD_VALUE: \c NULL \a directory or the object is not properly
  146. initialized.
  147. - another error code
  148. */
  149. status_t
  150. BVolume::GetRootDirectory(BDirectory *directory) const
  151. {
  152. // check parameter and initialization
  153. status_t error = (directory && InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
  154. // get FS stat
  155. fs_info info;
  156. if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
  157. error = errno;
  158. // init the directory
  159. if (error == B_OK) {
  160. node_ref ref;
  161. ref.device = info.dev;
  162. ref.node = info.root;
  163. error = directory->SetTo(&ref);
  164. }
  165. return error;
  166. }
  167. // Capacity
  168. /*! \brief Returns the volume's total storage capacity.
  169. \return
  170. - The volume's total storage capacity (in bytes), when the object is
  171. properly initialized.
  172. - \c B_BAD_VALUE otherwise.
  173. */
  174. off_t
  175. BVolume::Capacity() const
  176. {
  177. // check initialization
  178. status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
  179. // get FS stat
  180. fs_info info;
  181. if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
  182. error = errno;
  183. return (error == B_OK ? info.total_blocks * info.block_size : error);
  184. }
  185. // FreeBytes
  186. /*! \brief Returns the amount of storage that's currently unused on the
  187. volume (in bytes).
  188. \return
  189. - The amount of storage that's currently unused on the volume (in bytes),
  190. when the object is properly initialized.
  191. - \c B_BAD_VALUE otherwise.
  192. */
  193. off_t
  194. BVolume::FreeBytes() const
  195. {
  196. // check initialization
  197. status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
  198. // get FS stat
  199. fs_info info;
  200. if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
  201. error = errno;
  202. return (error == B_OK ? info.free_blocks * info.block_size : error);
  203. }
  204. /*! \brief Returns the size of one block (in bytes). It depends on the
  205. underlying file system what this means exactly.
  206. \return
  207. - The block size in bytes.
  208. - \c B_NO_INIT if the volume is not initialized.
  209. - Other errors forwarded from the file system.
  210. */
  211. off_t
  212. BVolume::BlockSize() const
  213. {
  214. // check initialization
  215. if (InitCheck() != B_OK)
  216. return B_NO_INIT;
  217. // get FS stat
  218. fs_info info;
  219. if (fs_stat_dev(fDevice, &info) != 0)
  220. return errno;
  221. return info.block_size;
  222. }
  223. // GetName
  224. /*! \brief Returns the name of the volume.
  225. The name of the volume is copied into the provided buffer.
  226. \param name A pointer to a pre-allocated character buffer of size
  227. \c B_FILE_NAME_LENGTH or larger into which the name of the
  228. volume shall be written.
  229. \return
  230. - \c B_OK: Everything went fine.
  231. - \c B_BAD_VALUE: \c NULL \a name or the object is not properly
  232. initialized.
  233. - another error code
  234. */
  235. status_t
  236. BVolume::GetName(char *name) const
  237. {
  238. // check parameter and initialization
  239. status_t error = (name && InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
  240. // get FS stat
  241. fs_info info;
  242. if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
  243. error = errno;
  244. // copy the name
  245. if (error == B_OK)
  246. strncpy(name, info.volume_name, B_FILE_NAME_LENGTH);
  247. return error;
  248. }
  249. // SetName
  250. /*! \brief Sets the name of the volume referred to by this object.
  251. \param name The volume's new name. Must not be longer than
  252. \c B_FILE_NAME_LENGTH (including the terminating null).
  253. \return
  254. - \c B_OK: Everything went fine.
  255. - \c B_BAD_VALUE: \c NULL \a name or the object is not properly
  256. initialized.
  257. - another error code
  258. */
  259. status_t
  260. BVolume::SetName(const char *name)
  261. {
  262. // check initialization
  263. if (!name || InitCheck() != B_OK)
  264. return B_BAD_VALUE;
  265. if (strlen(name) >= B_FILE_NAME_LENGTH)
  266. return B_NAME_TOO_LONG;
  267. // get the FS stat (including the old name) first
  268. fs_info oldInfo;
  269. if (fs_stat_dev(fDevice, &oldInfo) != 0)
  270. return errno;
  271. if (strcmp(name, oldInfo.volume_name) == 0)
  272. return B_OK;
  273. // set the volume name
  274. fs_info newInfo;
  275. strlcpy(newInfo.volume_name, name, sizeof(newInfo.volume_name));
  276. status_t error = _kern_write_fs_info(fDevice, &newInfo,
  277. FS_WRITE_FSINFO_NAME);
  278. if (error != B_OK)
  279. return error;
  280. // change the name of the mount point
  281. // R5 implementation checks, if an entry with the volume's old name
  282. // exists in the root directory and renames that entry, if it is indeed
  283. // the mount point of the volume (or a link referring to it). In all other
  284. // cases, nothing is done (even if the mount point is named like the
  285. // volume, but lives in a different directory).
  286. // We follow suit for the time being.
  287. // NOTE: If the volume name itself is actually "boot", then this code
  288. // tries to rename /boot, but that is prevented in the kernel.
  289. BPath entryPath;
  290. BEntry entry;
  291. BEntry traversedEntry;
  292. node_ref entryNodeRef;
  293. if (BPrivate::Storage::check_entry_name(name) == B_OK
  294. && BPrivate::Storage::check_entry_name(oldInfo.volume_name) == B_OK
  295. && entryPath.SetTo("/", oldInfo.volume_name) == B_OK
  296. && entry.SetTo(entryPath.Path(), false) == B_OK
  297. && entry.Exists()
  298. && traversedEntry.SetTo(entryPath.Path(), true) == B_OK
  299. && traversedEntry.GetNodeRef(&entryNodeRef) == B_OK
  300. && entryNodeRef.device == fDevice
  301. && entryNodeRef.node == oldInfo.root) {
  302. entry.Rename(name, false);
  303. }
  304. return error;
  305. }
  306. // GetIcon
  307. /*! \brief Returns the icon of the volume.
  308. \param icon A pointer to a pre-allocated BBitmap of the correct dimension
  309. to store the requested icon (16x16 for the mini and 32x32 for the
  310. large icon).
  311. \param which Specifies the size of the icon to be retrieved:
  312. \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon.
  313. */
  314. status_t
  315. BVolume::GetIcon(BBitmap *icon, icon_size which) const
  316. {
  317. // check initialization
  318. if (InitCheck() != B_OK)
  319. return B_NO_INIT;
  320. // get FS stat for the device name
  321. fs_info info;
  322. if (fs_stat_dev(fDevice, &info) != 0)
  323. return errno;
  324. // get the icon
  325. return get_device_icon(info.device_name, icon, which);
  326. }
  327. status_t
  328. BVolume::GetIcon(uint8** _data, size_t* _size, type_code* _type) const
  329. {
  330. // check initialization
  331. if (InitCheck() != B_OK)
  332. return B_NO_INIT;
  333. // get FS stat for the device name
  334. fs_info info;
  335. if (fs_stat_dev(fDevice, &info) != 0)
  336. return errno;
  337. // get the icon
  338. return get_device_icon(info.device_name, _data, _size, _type);
  339. }
  340. /*! \brief Returns whether the volume is removable.
  341. \return \c true, when the object is properly initialized and the
  342. referred to volume is removable, \c false otherwise.
  343. */
  344. bool
  345. BVolume::IsRemovable() const
  346. {
  347. // check initialization
  348. status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
  349. // get FS stat
  350. fs_info info;
  351. if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
  352. error = errno;
  353. return (error == B_OK && (info.flags & B_FS_IS_REMOVABLE));
  354. }
  355. // IsReadOnly
  356. /*! \brief Returns whether the volume is read only.
  357. \return \c true, when the object is properly initialized and the
  358. referred to volume is read only, \c false otherwise.
  359. */
  360. bool
  361. BVolume::IsReadOnly(void) const
  362. {
  363. // check initialization
  364. status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
  365. // get FS stat
  366. fs_info info;
  367. if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
  368. error = errno;
  369. return (error == B_OK && (info.flags & B_FS_IS_READONLY));
  370. }
  371. // IsPersistent
  372. /*! \brief Returns whether the volume is persistent.
  373. \return \c true, when the object is properly initialized and the
  374. referred to volume is persistent, \c false otherwise.
  375. */
  376. bool
  377. BVolume::IsPersistent(void) const
  378. {
  379. // check initialization
  380. status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
  381. // get FS stat
  382. fs_info info;
  383. if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
  384. error = errno;
  385. return (error == B_OK && (info.flags & B_FS_IS_PERSISTENT));
  386. }
  387. // IsShared
  388. /*! \brief Returns whether the volume is shared.
  389. \return \c true, when the object is properly initialized and the
  390. referred to volume is shared, \c false otherwise.
  391. */
  392. bool
  393. BVolume::IsShared(void) const
  394. {
  395. // check initialization
  396. status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
  397. // get FS stat
  398. fs_info info;
  399. if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
  400. error = errno;
  401. return (error == B_OK && (info.flags & B_FS_IS_SHARED));
  402. }
  403. // KnowsMime
  404. /*! \brief Returns whether the volume supports MIME types.
  405. \return \c true, when the object is properly initialized and the
  406. referred to volume supports MIME types, \c false otherwise.
  407. */
  408. bool
  409. BVolume::KnowsMime(void) const
  410. {
  411. // check initialization
  412. status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
  413. // get FS stat
  414. fs_info info;
  415. if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
  416. error = errno;
  417. return (error == B_OK && (info.flags & B_FS_HAS_MIME));
  418. }
  419. // KnowsAttr
  420. /*! \brief Returns whether the volume supports attributes.
  421. \return \c true, when the object is properly initialized and the
  422. referred to volume supports attributes, \c false otherwise.
  423. */
  424. bool
  425. BVolume::KnowsAttr(void) const
  426. {
  427. // check initialization
  428. status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
  429. // get FS stat
  430. fs_info info;
  431. if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
  432. error = errno;
  433. return (error == B_OK && (info.flags & B_FS_HAS_ATTR));
  434. }
  435. // KnowsQuery
  436. /*! \brief Returns whether the volume supports queries.
  437. \return \c true, when the object is properly initialized and the
  438. referred to volume supports queries, \c false otherwise.
  439. */
  440. bool
  441. BVolume::KnowsQuery(void) const
  442. {
  443. // check initialization
  444. status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
  445. // get FS stat
  446. fs_info info;
  447. if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
  448. error = errno;
  449. return (error == B_OK && (info.flags & B_FS_HAS_QUERY));
  450. }
  451. // ==
  452. /*! \brief Returns whether two BVolume objects are equal.
  453. Two volume objects are said to be equal, if they either are both
  454. uninitialized, or both are initialized and refer to the same volume.
  455. \param volume The object to be compared with.
  456. \result \c true, if this object and the supplied one are equal, \c false
  457. otherwise.
  458. */
  459. bool
  460. BVolume::operator==(const BVolume &volume) const
  461. {
  462. return ((InitCheck() != B_OK && volume.InitCheck() != B_OK)
  463. || fDevice == volume.fDevice);
  464. }
  465. // !=
  466. /*! \brief Returns whether two BVolume objects are unequal.
  467. Two volume objects are said to be equal, if they either are both
  468. uninitialized, or both are initialized and refer to the same volume.
  469. \param volume The object to be compared with.
  470. \result \c true, if this object and the supplied one are unequal, \c false
  471. otherwise.
  472. */
  473. bool
  474. BVolume::operator!=(const BVolume &volume) const
  475. {
  476. return !(*this == volume);
  477. }
  478. // =
  479. /*! \brief Assigns another BVolume object to this one.
  480. This object is made an exact clone of the supplied one.
  481. \param volume The volume from which shall be assigned.
  482. \return A reference to this object.
  483. */
  484. BVolume&
  485. BVolume::operator=(const BVolume &volume)
  486. {
  487. if (&volume != this) {
  488. this->fDevice = volume.fDevice;
  489. this->fCStatus = volume.fCStatus;
  490. }
  491. return *this;
  492. }
  493. // FBC
  494. void BVolume::_TurnUpTheVolume1() {}
  495. void BVolume::_TurnUpTheVolume2() {}
  496. void BVolume::_TurnUpTheVolume3() {}
  497. void BVolume::_TurnUpTheVolume4() {}
  498. void BVolume::_TurnUpTheVolume5() {}
  499. void BVolume::_TurnUpTheVolume6() {}
  500. void BVolume::_TurnUpTheVolume7() {}
  501. void BVolume::_TurnUpTheVolume8() {}