FilePermissionsMask.cpp 4.0 KB

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