FilePermissionsMask.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. Mode
  14. };
  15. enum ClassFlag {
  16. Other = 1,
  17. Group = 2,
  18. User = 4,
  19. All = 7
  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. string = string.trim_whitespace();
  35. mode_t mode = AK::StringUtils::convert_to_uint_from_octal<u16>(string, TrimWhitespace::No).value_or(010000);
  36. if (mode > 07777)
  37. return Error::from_string_literal("invalid octal representation");
  38. FilePermissionsMask mask;
  39. mask.assign_permissions(mode);
  40. // For compatibility purposes, just clear the special mode bits if we explicitly passed a 4-character mode.
  41. if (string.length() >= 4)
  42. mask.remove_permissions(07000);
  43. return mask;
  44. }
  45. ErrorOr<FilePermissionsMask> FilePermissionsMask::from_symbolic_notation(StringView string)
  46. {
  47. auto mask = FilePermissionsMask();
  48. u8 state = State::Classes;
  49. u8 classes = 0;
  50. u8 operation = 0;
  51. for (auto ch : string) {
  52. switch (state) {
  53. case State::Classes: {
  54. // zero or more [ugoa] terminated by one operator [+-=]
  55. if (ch == 'u')
  56. classes |= ClassFlag::User;
  57. else if (ch == 'g')
  58. classes |= ClassFlag::Group;
  59. else if (ch == 'o')
  60. classes |= ClassFlag::Other;
  61. else if (ch == 'a')
  62. classes = ClassFlag::All;
  63. else {
  64. if (ch == '+')
  65. operation = Operation::Add;
  66. else if (ch == '-')
  67. operation = Operation::Remove;
  68. else if (ch == '=')
  69. operation = Operation::Assign;
  70. else if (classes == 0)
  71. return Error::from_string_literal("invalid class: expected 'u', 'g', 'o' or 'a'");
  72. else
  73. return Error::from_string_literal("invalid operation: expected '+', '-' or '='");
  74. // if an operation was specified without a class, assume all
  75. if (classes == 0)
  76. classes = ClassFlag::All;
  77. state = State::Mode;
  78. }
  79. break;
  80. }
  81. case State::Mode: {
  82. // one or more [rwx] terminated by a comma
  83. // End of mode part, expect class next
  84. if (ch == ',') {
  85. state = State::Classes;
  86. classes = operation = 0;
  87. continue;
  88. }
  89. mode_t write_bits = 0;
  90. bool apply_to_directories_and_executables_only = false;
  91. switch (ch) {
  92. case 'r':
  93. write_bits = 4;
  94. break;
  95. case 'w':
  96. write_bits = 2;
  97. break;
  98. case 'x':
  99. write_bits = 1;
  100. break;
  101. case 'X':
  102. write_bits = 1;
  103. apply_to_directories_and_executables_only = true;
  104. break;
  105. default:
  106. return Error::from_string_literal("invalid symbolic permission: expected 'r', 'w' or 'x'");
  107. }
  108. mode_t clear_bits = operation == Operation::Assign ? 7 : write_bits;
  109. FilePermissionsMask& edit_mask = apply_to_directories_and_executables_only ? mask.directory_or_executable_mask() : mask;
  110. // Update masks one class at a time in other, group, user order
  111. for (auto cls = classes; cls != 0; cls >>= 1) {
  112. if (cls & 1) {
  113. if (operation == Operation::Add || operation == Operation::Assign)
  114. edit_mask.add_permissions(write_bits);
  115. if (operation == Operation::Remove || operation == Operation::Assign)
  116. edit_mask.remove_permissions(clear_bits);
  117. }
  118. write_bits <<= 3;
  119. clear_bits <<= 3;
  120. }
  121. break;
  122. }
  123. default:
  124. VERIFY_NOT_REACHED();
  125. }
  126. }
  127. return mask;
  128. }
  129. FilePermissionsMask& FilePermissionsMask::assign_permissions(mode_t mode)
  130. {
  131. m_write_mask = mode;
  132. m_clear_mask = 0777;
  133. return *this;
  134. }
  135. FilePermissionsMask& FilePermissionsMask::add_permissions(mode_t mode)
  136. {
  137. m_write_mask |= mode;
  138. return *this;
  139. }
  140. FilePermissionsMask& FilePermissionsMask::remove_permissions(mode_t mode)
  141. {
  142. m_clear_mask |= mode;
  143. return *this;
  144. }
  145. }