parseListUnix.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.transformList = exports.parseLine = exports.testLine = void 0;
  4. const FileInfo_1 = require("./FileInfo");
  5. const JA_MONTH = "\u6708";
  6. const JA_DAY = "\u65e5";
  7. const JA_YEAR = "\u5e74";
  8. /**
  9. * This parser is based on the FTP client library source code in Apache Commons Net provided
  10. * under the Apache 2.0 license. It has been simplified and rewritten to better fit the Javascript language.
  11. *
  12. * https://github.com/apache/commons-net/blob/master/src/main/java/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java
  13. *
  14. * Below is the regular expression used by this parser.
  15. *
  16. * Permissions:
  17. * r the file is readable
  18. * w the file is writable
  19. * x the file is executable
  20. * - the indicated permission is not granted
  21. * L mandatory locking occurs during access (the set-group-ID bit is
  22. * on and the group execution bit is off)
  23. * s the set-user-ID or set-group-ID bit is on, and the corresponding
  24. * user or group execution bit is also on
  25. * S undefined bit-state (the set-user-ID bit is on and the user
  26. * execution bit is off)
  27. * t the 1000 (octal) bit, or sticky bit, is on [see chmod(1)], and
  28. * execution is on
  29. * T the 1000 bit is turned on, and execution is off (undefined bit-
  30. * state)
  31. * e z/OS external link bit
  32. * Final letter may be appended:
  33. * + file has extended security attributes (e.g. ACL)
  34. * Note: local listings on MacOSX also use '@'
  35. * this is not allowed for here as does not appear to be shown by FTP servers
  36. * {@code @} file has extended attributes
  37. */
  38. const RE_LINE = new RegExp("([bcdelfmpSs-])" // file type
  39. + "(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]?)))\\+?" // permissions
  40. + "\\s*" // separator TODO why allow it to be omitted??
  41. + "(\\d+)" // link count
  42. + "\\s+" // separator
  43. + "(?:(\\S+(?:\\s\\S+)*?)\\s+)?" // owner name (optional spaces)
  44. + "(?:(\\S+(?:\\s\\S+)*)\\s+)?" // group name (optional spaces)
  45. + "(\\d+(?:,\\s*\\d+)?)" // size or n,m
  46. + "\\s+" // separator
  47. /**
  48. * numeric or standard format date:
  49. * yyyy-mm-dd (expecting hh:mm to follow)
  50. * MMM [d]d
  51. * [d]d MMM
  52. * N.B. use non-space for MMM to allow for languages such as German which use
  53. * diacritics (e.g. umlaut) in some abbreviations.
  54. * Japanese uses numeric day and month with suffixes to distinguish them
  55. * [d]dXX [d]dZZ
  56. */
  57. + "(" +
  58. "(?:\\d+[-/]\\d+[-/]\\d+)" + // yyyy-mm-dd
  59. "|(?:\\S{3}\\s+\\d{1,2})" + // MMM [d]d
  60. "|(?:\\d{1,2}\\s+\\S{3})" + // [d]d MMM
  61. "|(?:\\d{1,2}" + JA_MONTH + "\\s+\\d{1,2}" + JA_DAY + ")" +
  62. ")"
  63. + "\\s+" // separator
  64. /**
  65. * year (for non-recent standard format) - yyyy
  66. * or time (for numeric or recent standard format) [h]h:mm
  67. * or Japanese year - yyyyXX
  68. */
  69. + "((?:\\d+(?::\\d+)?)|(?:\\d{4}" + JA_YEAR + "))" // (20)
  70. + "\\s" // separator
  71. + "(.*)"); // the rest (21)
  72. /**
  73. * Returns true if a given line might be a Unix-style listing.
  74. *
  75. * - Example: `-rw-r--r--+ 1 patrick staff 1057 Dec 11 14:35 test.txt`
  76. */
  77. function testLine(line) {
  78. return RE_LINE.test(line);
  79. }
  80. exports.testLine = testLine;
  81. /**
  82. * Parse a single line of a Unix-style directory listing.
  83. */
  84. function parseLine(line) {
  85. const groups = line.match(RE_LINE);
  86. if (groups === null) {
  87. return undefined;
  88. }
  89. const name = groups[21];
  90. if (name === "." || name === "..") { // Ignore parent directory links
  91. return undefined;
  92. }
  93. const file = new FileInfo_1.FileInfo(name);
  94. file.size = parseInt(groups[18], 10);
  95. file.user = groups[16];
  96. file.group = groups[17];
  97. file.hardLinkCount = parseInt(groups[15], 10);
  98. file.rawModifiedAt = groups[19] + " " + groups[20];
  99. file.permissions = {
  100. user: parseMode(groups[4], groups[5], groups[6]),
  101. group: parseMode(groups[8], groups[9], groups[10]),
  102. world: parseMode(groups[12], groups[13], groups[14]),
  103. };
  104. // Set file type
  105. switch (groups[1].charAt(0)) {
  106. case "d":
  107. file.type = FileInfo_1.FileType.Directory;
  108. break;
  109. case "e": // NET-39 => z/OS external link
  110. file.type = FileInfo_1.FileType.SymbolicLink;
  111. break;
  112. case "l":
  113. file.type = FileInfo_1.FileType.SymbolicLink;
  114. break;
  115. case "b":
  116. case "c":
  117. file.type = FileInfo_1.FileType.File; // TODO change this if DEVICE_TYPE implemented
  118. break;
  119. case "f":
  120. case "-":
  121. file.type = FileInfo_1.FileType.File;
  122. break;
  123. default:
  124. // A 'whiteout' file is an ARTIFICIAL entry in any of several types of
  125. // 'translucent' filesystems, of which a 'union' filesystem is one.
  126. file.type = FileInfo_1.FileType.Unknown;
  127. }
  128. // Separate out the link name for symbolic links
  129. if (file.isSymbolicLink) {
  130. const end = name.indexOf(" -> ");
  131. if (end !== -1) {
  132. file.name = name.substring(0, end);
  133. file.link = name.substring(end + 4);
  134. }
  135. }
  136. return file;
  137. }
  138. exports.parseLine = parseLine;
  139. function transformList(files) {
  140. return files;
  141. }
  142. exports.transformList = transformList;
  143. function parseMode(r, w, x) {
  144. let value = 0;
  145. if (r !== "-") {
  146. value += FileInfo_1.FileInfo.UnixPermission.Read;
  147. }
  148. if (w !== "-") {
  149. value += FileInfo_1.FileInfo.UnixPermission.Write;
  150. }
  151. const execToken = x.charAt(0);
  152. if (execToken !== "-" && execToken.toUpperCase() !== execToken) {
  153. value += FileInfo_1.FileInfo.UnixPermission.Execute;
  154. }
  155. return value;
  156. }