FilePermissionsMask.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * Copyright (c) 2021, Xavier Defrang <xavier.defrang@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Assertions.h>
  7. #include <AK/CharacterTypes.h>
  8. #include <AK/StringUtils.h>
  9. #include <LibCore/FilePermissionsMask.h>
  10. namespace Core {
  11. enum State {
  12. Classes,
  13. Operation,
  14. Mode
  15. };
  16. enum ClassFlag {
  17. Other = 1,
  18. Group = 2,
  19. User = 4
  20. };
  21. enum Operation {
  22. Add,
  23. Remove,
  24. Assign,
  25. };
  26. ErrorOr<FilePermissionsMask> FilePermissionsMask::parse(StringView string)
  27. {
  28. return (!string.is_empty() && is_ascii_digit(string[0]))
  29. ? from_numeric_notation(string)
  30. : from_symbolic_notation(string);
  31. }
  32. ErrorOr<FilePermissionsMask> FilePermissionsMask::from_numeric_notation(StringView string)
  33. {
  34. mode_t mode = AK::StringUtils::convert_to_uint_from_octal<u16>(string).value_or(01000);
  35. if (mode > 0777)
  36. return Error::from_string_literal("invalid octal representation"sv);
  37. return FilePermissionsMask().assign_permissions(mode);
  38. }
  39. ErrorOr<FilePermissionsMask> FilePermissionsMask::from_symbolic_notation(StringView string)
  40. {
  41. auto mask = FilePermissionsMask();
  42. u8 state = State::Classes;
  43. u8 classes = 0;
  44. u8 operation = 0;
  45. for (auto ch : string) {
  46. switch (state) {
  47. case State::Classes: {
  48. // one or more [ugoa] terminated by one operator [+-=]
  49. if (ch == 'u') {
  50. classes |= ClassFlag::User;
  51. state = State::Operation;
  52. break;
  53. } else if (ch == 'g') {
  54. classes |= ClassFlag::Group;
  55. state = State::Operation;
  56. break;
  57. } else if (ch == 'o') {
  58. classes |= ClassFlag::Other;
  59. state = State::Operation;
  60. break;
  61. } else if (ch == 'a') {
  62. classes = ClassFlag::User | ClassFlag::Group | ClassFlag::Other;
  63. state = State::Operation;
  64. break;
  65. }
  66. }
  67. [[fallthrough]];
  68. case State::Operation: {
  69. if (ch == '+')
  70. operation = Operation::Add;
  71. else if (ch == '-')
  72. operation = Operation::Remove;
  73. else if (ch == '=')
  74. operation = Operation::Assign;
  75. else if (classes == 0)
  76. return Error::from_string_literal("invalid access class: expected 'u', 'g', 'o' or 'a' "sv);
  77. else
  78. return Error::from_string_literal("invalid operation: expected '+', '-' or '='"sv);
  79. // if an operation was specified without a class, assume all
  80. if (classes == 0)
  81. classes = ClassFlag::User | ClassFlag::Group | ClassFlag::Other;
  82. state = State::Mode;
  83. break;
  84. }
  85. case State::Mode: {
  86. // one or more [rwx] terminated by a comma
  87. // End of mode part, expect class next
  88. if (ch == ',') {
  89. state = State::Classes;
  90. classes = operation = 0;
  91. continue;
  92. }
  93. mode_t write_bits = 0;
  94. if (ch == 'r')
  95. write_bits = 4;
  96. else if (ch == 'w')
  97. write_bits = 2;
  98. else if (ch == 'x')
  99. write_bits = 1;
  100. else
  101. return Error::from_string_literal("invalid symbolic permission"sv);
  102. mode_t clear_bits = operation == Operation::Assign ? 7 : write_bits;
  103. // Update masks one class at a time in other, group, user order
  104. for (auto cls = classes; cls != 0; cls >>= 1) {
  105. if (cls & 1) {
  106. if (operation == Operation::Add || operation == Operation::Assign)
  107. mask.add_permissions(write_bits);
  108. if (operation == Operation::Remove || operation == Operation::Assign)
  109. mask.remove_permissions(clear_bits);
  110. }
  111. write_bits <<= 3;
  112. clear_bits <<= 3;
  113. }
  114. break;
  115. }
  116. default:
  117. VERIFY_NOT_REACHED();
  118. }
  119. }
  120. return mask;
  121. }
  122. FilePermissionsMask& FilePermissionsMask::assign_permissions(mode_t mode)
  123. {
  124. m_write_mask = mode;
  125. m_clear_mask = 0777;
  126. return *this;
  127. }
  128. FilePermissionsMask& FilePermissionsMask::add_permissions(mode_t mode)
  129. {
  130. m_write_mask |= mode;
  131. return *this;
  132. }
  133. FilePermissionsMask& FilePermissionsMask::remove_permissions(mode_t mode)
  134. {
  135. m_clear_mask |= mode;
  136. return *this;
  137. }
  138. }