PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/mingw-w64-v2.0.999/gcc/src/libgfortran/intrinsics/chmod.c

#
C | 531 lines | 405 code | 53 blank | 73 comment | 161 complexity | 77e1c05976ac4f3ba85b493b9ba9f54b MD5 | raw file
Possible License(s): LGPL-2.1, 0BSD, LGPL-2.0, BSD-3-Clause, AGPL-1.0, LGPL-3.0, Unlicense, GPL-2.0, GPL-3.0
  1. /* Implementation of the CHMOD intrinsic.
  2. Copyright (C) 2006, 2007, 2009, 2012 Free Software Foundation, Inc.
  3. Contributed by Fran??ois-Xavier Coudert <coudert@clipper.ens.fr>
  4. This file is part of the GNU Fortran runtime library (libgfortran).
  5. Libgfortran is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public
  7. License as published by the Free Software Foundation; either
  8. version 3 of the License, or (at your option) any later version.
  9. Libgfortran is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. Under Section 7 of GPL version 3, you are granted additional
  14. permissions described in the GCC Runtime Library Exception, version
  15. 3.1, as published by the Free Software Foundation.
  16. You should have received a copy of the GNU General Public License and
  17. a copy of the GCC Runtime Library Exception along with this program;
  18. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. <http://www.gnu.org/licenses/>. */
  20. #include "libgfortran.h"
  21. #if defined(HAVE_SYS_STAT_H)
  22. #include <stdbool.h>
  23. #include <string.h> /* For memcpy. */
  24. #include <sys/stat.h> /* For stat, chmod and umask. */
  25. /* INTEGER FUNCTION CHMOD (NAME, MODE)
  26. CHARACTER(len=*), INTENT(IN) :: NAME, MODE
  27. Sets the file permission "chmod" using a mode string.
  28. For MinGW, only _S_IWRITE and _S_IREAD are supported. To set those,
  29. only the user attributes are used.
  30. The mode string allows for the same arguments as POSIX's chmod utility.
  31. a) string containing an octal number.
  32. b) Comma separated list of clauses of the form:
  33. [<who-list>]<op>[<perm-list>|<permcopy>][<op>[<perm-list>|<permcopy>],...]
  34. <who> - 'u', 'g', 'o', 'a'
  35. <op> - '+', '-', '='
  36. <perm> - 'r', 'w', 'x', 'X', 's', t'
  37. If <op> is not followed by a perm-list or permcopy, '-' and '+' do not
  38. change the mode while '=' clears all file mode bits. 'u' stands for the
  39. user permissions, 'g' for the group and 'o' for the permissions for others.
  40. 'a' is equivalent to 'ugo'. '+' sets the given permission in addition to
  41. the ones of the file, '-' unsets the given permissions of the file, while
  42. '=' sets the file to that mode. 'r' sets the read, 'w' the write, and
  43. 'x' the execute mode. 'X' sets the execute bit if the file is a directory
  44. or if the user, group or other executable bit is set. 't' sets the sticky
  45. bit, 's' (un)sets the and/or S_ISUID/S_ISGID bit.
  46. Note that if <who> is omitted, the permissions are filtered by the umask.
  47. A return value of 0 indicates success, -1 an error of chmod() while 1
  48. indicates a mode parsing error. */
  49. extern int chmod_func (char *, char *, gfc_charlen_type, gfc_charlen_type);
  50. export_proto(chmod_func);
  51. int
  52. chmod_func (char *name, char *mode, gfc_charlen_type name_len,
  53. gfc_charlen_type mode_len)
  54. {
  55. char * file;
  56. int i;
  57. bool ugo[3];
  58. bool rwxXstugo[9];
  59. int set_mode, part;
  60. bool honor_umask, continue_clause = false;
  61. #ifndef __MINGW32__
  62. bool is_dir;
  63. #endif
  64. mode_t mode_mask, file_mode, new_mode;
  65. struct stat stat_buf;
  66. /* Trim trailing spaces of the file name. */
  67. while (name_len > 0 && name[name_len - 1] == ' ')
  68. name_len--;
  69. /* Make a null terminated copy of the file name. */
  70. file = gfc_alloca (name_len + 1);
  71. memcpy (file, name, name_len);
  72. file[name_len] = '\0';
  73. if (mode_len == 0)
  74. return 1;
  75. if (mode[0] >= '0' && mode[0] <= '9')
  76. {
  77. #ifdef __MINGW32__
  78. unsigned fmode;
  79. if (sscanf (mode, "%o", &fmode) != 1)
  80. return 1;
  81. file_mode = (mode_t) fmode;
  82. #else
  83. if (sscanf (mode, "%o", &file_mode) != 1)
  84. return 1;
  85. #endif
  86. return chmod (file, file_mode);
  87. }
  88. /* Read the current file mode. */
  89. if (stat (file, &stat_buf))
  90. return 1;
  91. file_mode = stat_buf.st_mode & ~S_IFMT;
  92. #ifndef __MINGW32__
  93. is_dir = stat_buf.st_mode & S_IFDIR;
  94. #endif
  95. #ifdef HAVE_UMASK
  96. /* Obtain the umask without distroying the setting. */
  97. mode_mask = 0;
  98. mode_mask = umask (mode_mask);
  99. (void) umask (mode_mask);
  100. #else
  101. honor_umask = false;
  102. #endif
  103. for (i = 0; i < mode_len; i++)
  104. {
  105. if (!continue_clause)
  106. {
  107. ugo[0] = false;
  108. ugo[1] = false;
  109. ugo[2] = false;
  110. #ifdef HAVE_UMASK
  111. honor_umask = true;
  112. #endif
  113. }
  114. continue_clause = false;
  115. rwxXstugo[0] = false;
  116. rwxXstugo[1] = false;
  117. rwxXstugo[2] = false;
  118. rwxXstugo[3] = false;
  119. rwxXstugo[4] = false;
  120. rwxXstugo[5] = false;
  121. rwxXstugo[6] = false;
  122. rwxXstugo[7] = false;
  123. rwxXstugo[8] = false;
  124. part = 0;
  125. set_mode = -1;
  126. for (; i < mode_len; i++)
  127. {
  128. switch (mode[i])
  129. {
  130. /* User setting: a[ll]/u[ser]/g[roup]/o[ther]. */
  131. case 'a':
  132. if (part > 1)
  133. return 1;
  134. ugo[0] = true;
  135. ugo[1] = true;
  136. ugo[2] = true;
  137. part = 1;
  138. #ifdef HAVE_UMASK
  139. honor_umask = false;
  140. #endif
  141. break;
  142. case 'u':
  143. if (part == 2)
  144. {
  145. rwxXstugo[6] = true;
  146. part = 4;
  147. break;
  148. }
  149. if (part > 1)
  150. return 1;
  151. ugo[0] = true;
  152. part = 1;
  153. #ifdef HAVE_UMASK
  154. honor_umask = false;
  155. #endif
  156. break;
  157. case 'g':
  158. if (part == 2)
  159. {
  160. rwxXstugo[7] = true;
  161. part = 4;
  162. break;
  163. }
  164. if (part > 1)
  165. return 1;
  166. ugo[1] = true;
  167. part = 1;
  168. #ifdef HAVE_UMASK
  169. honor_umask = false;
  170. #endif
  171. break;
  172. case 'o':
  173. if (part == 2)
  174. {
  175. rwxXstugo[8] = true;
  176. part = 4;
  177. break;
  178. }
  179. if (part > 1)
  180. return 1;
  181. ugo[2] = true;
  182. part = 1;
  183. #ifdef HAVE_UMASK
  184. honor_umask = false;
  185. #endif
  186. break;
  187. /* Mode setting: =+-. */
  188. case '=':
  189. if (part > 2)
  190. {
  191. continue_clause = true;
  192. i--;
  193. part = 2;
  194. goto clause_done;
  195. }
  196. set_mode = 1;
  197. part = 2;
  198. break;
  199. case '-':
  200. if (part > 2)
  201. {
  202. continue_clause = true;
  203. i--;
  204. part = 2;
  205. goto clause_done;
  206. }
  207. set_mode = 2;
  208. part = 2;
  209. break;
  210. case '+':
  211. if (part > 2)
  212. {
  213. continue_clause = true;
  214. i--;
  215. part = 2;
  216. goto clause_done;
  217. }
  218. set_mode = 3;
  219. part = 2;
  220. break;
  221. /* Permissions: rwxXst - for ugo see above. */
  222. case 'r':
  223. if (part != 2 && part != 3)
  224. return 1;
  225. rwxXstugo[0] = true;
  226. part = 3;
  227. break;
  228. case 'w':
  229. if (part != 2 && part != 3)
  230. return 1;
  231. rwxXstugo[1] = true;
  232. part = 3;
  233. break;
  234. case 'x':
  235. if (part != 2 && part != 3)
  236. return 1;
  237. rwxXstugo[2] = true;
  238. part = 3;
  239. break;
  240. case 'X':
  241. if (part != 2 && part != 3)
  242. return 1;
  243. rwxXstugo[3] = true;
  244. part = 3;
  245. break;
  246. case 's':
  247. if (part != 2 && part != 3)
  248. return 1;
  249. rwxXstugo[4] = true;
  250. part = 3;
  251. break;
  252. case 't':
  253. if (part != 2 && part != 3)
  254. return 1;
  255. rwxXstugo[5] = true;
  256. part = 3;
  257. break;
  258. /* Tailing blanks are valid in Fortran. */
  259. case ' ':
  260. for (i++; i < mode_len; i++)
  261. if (mode[i] != ' ')
  262. break;
  263. if (i != mode_len)
  264. return 1;
  265. goto clause_done;
  266. case ',':
  267. goto clause_done;
  268. default:
  269. return 1;
  270. }
  271. }
  272. clause_done:
  273. if (part < 2)
  274. return 1;
  275. new_mode = 0;
  276. #ifdef __MINGW32__
  277. /* Read. */
  278. if (rwxXstugo[0] && (ugo[0] || honor_umask))
  279. new_mode |= _S_IREAD;
  280. /* Write. */
  281. if (rwxXstugo[1] && (ugo[0] || honor_umask))
  282. new_mode |= _S_IWRITE;
  283. #else
  284. /* Read. */
  285. if (rwxXstugo[0])
  286. {
  287. if (ugo[0] || honor_umask)
  288. new_mode |= S_IRUSR;
  289. if (ugo[1] || honor_umask)
  290. new_mode |= S_IRGRP;
  291. if (ugo[2] || honor_umask)
  292. new_mode |= S_IROTH;
  293. }
  294. /* Write. */
  295. if (rwxXstugo[1])
  296. {
  297. if (ugo[0] || honor_umask)
  298. new_mode |= S_IWUSR;
  299. if (ugo[1] || honor_umask)
  300. new_mode |= S_IWGRP;
  301. if (ugo[2] || honor_umask)
  302. new_mode |= S_IWOTH;
  303. }
  304. /* Execute. */
  305. if (rwxXstugo[2])
  306. {
  307. if (ugo[0] || honor_umask)
  308. new_mode |= S_IXUSR;
  309. if (ugo[1] || honor_umask)
  310. new_mode |= S_IXGRP;
  311. if (ugo[2] || honor_umask)
  312. new_mode |= S_IXOTH;
  313. }
  314. /* 'X' execute. */
  315. if (rwxXstugo[3]
  316. && (is_dir || (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
  317. new_mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
  318. /* 's'. */
  319. if (rwxXstugo[4])
  320. {
  321. if (ugo[0] || honor_umask)
  322. new_mode |= S_ISUID;
  323. if (ugo[1] || honor_umask)
  324. new_mode |= S_ISGID;
  325. }
  326. /* As original 'u'. */
  327. if (rwxXstugo[6])
  328. {
  329. if (ugo[1] || honor_umask)
  330. {
  331. if (file_mode & S_IRUSR)
  332. new_mode |= S_IRGRP;
  333. if (file_mode & S_IWUSR)
  334. new_mode |= S_IWGRP;
  335. if (file_mode & S_IXUSR)
  336. new_mode |= S_IXGRP;
  337. }
  338. if (ugo[2] || honor_umask)
  339. {
  340. if (file_mode & S_IRUSR)
  341. new_mode |= S_IROTH;
  342. if (file_mode & S_IWUSR)
  343. new_mode |= S_IWOTH;
  344. if (file_mode & S_IXUSR)
  345. new_mode |= S_IXOTH;
  346. }
  347. }
  348. /* As original 'g'. */
  349. if (rwxXstugo[7])
  350. {
  351. if (ugo[0] || honor_umask)
  352. {
  353. if (file_mode & S_IRGRP)
  354. new_mode |= S_IRUSR;
  355. if (file_mode & S_IWGRP)
  356. new_mode |= S_IWUSR;
  357. if (file_mode & S_IXGRP)
  358. new_mode |= S_IXUSR;
  359. }
  360. if (ugo[2] || honor_umask)
  361. {
  362. if (file_mode & S_IRGRP)
  363. new_mode |= S_IROTH;
  364. if (file_mode & S_IWGRP)
  365. new_mode |= S_IWOTH;
  366. if (file_mode & S_IXGRP)
  367. new_mode |= S_IXOTH;
  368. }
  369. }
  370. /* As original 'o'. */
  371. if (rwxXstugo[8])
  372. {
  373. if (ugo[0] || honor_umask)
  374. {
  375. if (file_mode & S_IROTH)
  376. new_mode |= S_IRUSR;
  377. if (file_mode & S_IWOTH)
  378. new_mode |= S_IWUSR;
  379. if (file_mode & S_IXOTH)
  380. new_mode |= S_IXUSR;
  381. }
  382. if (ugo[1] || honor_umask)
  383. {
  384. if (file_mode & S_IROTH)
  385. new_mode |= S_IRGRP;
  386. if (file_mode & S_IWOTH)
  387. new_mode |= S_IWGRP;
  388. if (file_mode & S_IXOTH)
  389. new_mode |= S_IXGRP;
  390. }
  391. }
  392. #endif /* __MINGW32__ */
  393. #ifdef HAVE_UMASK
  394. if (honor_umask)
  395. new_mode &= ~mode_mask;
  396. #endif
  397. if (set_mode == 1)
  398. {
  399. #ifdef __MINGW32__
  400. if (ugo[0] || honor_umask)
  401. file_mode = (file_mode & ~(_S_IWRITE | _S_IREAD))
  402. | (new_mode & (_S_IWRITE | _S_IREAD));
  403. #else
  404. /* Set '='. */
  405. if ((ugo[0] || honor_umask) && !rwxXstugo[6])
  406. file_mode = (file_mode & ~(S_ISUID | S_IRUSR | S_IWUSR | S_IXUSR))
  407. | (new_mode & (S_ISUID | S_IRUSR | S_IWUSR | S_IXUSR));
  408. if ((ugo[1] || honor_umask) && !rwxXstugo[7])
  409. file_mode = (file_mode & ~(S_ISGID | S_IRGRP | S_IWGRP | S_IXGRP))
  410. | (new_mode & (S_ISGID | S_IRGRP | S_IWGRP | S_IXGRP));
  411. if ((ugo[2] || honor_umask) && !rwxXstugo[8])
  412. file_mode = (file_mode & ~(S_IROTH | S_IWOTH | S_IXOTH))
  413. | (new_mode & (S_IROTH | S_IWOTH | S_IXOTH));
  414. #ifndef __VXWORKS__
  415. if (is_dir && rwxXstugo[5])
  416. file_mode |= S_ISVTX;
  417. else if (!is_dir)
  418. file_mode &= ~S_ISVTX;
  419. #endif
  420. #endif
  421. }
  422. else if (set_mode == 2)
  423. {
  424. /* Clear '-'. */
  425. file_mode &= ~new_mode;
  426. #if !defined( __MINGW32__) && !defined (__VXWORKS__)
  427. if (rwxXstugo[5] || !is_dir)
  428. file_mode &= ~S_ISVTX;
  429. #endif
  430. }
  431. else if (set_mode == 3)
  432. {
  433. file_mode |= new_mode;
  434. #if !defined (__MINGW32__) && !defined (__VXWORKS__)
  435. if (rwxXstugo[5] && is_dir)
  436. file_mode |= S_ISVTX;
  437. else if (!is_dir)
  438. file_mode &= ~S_ISVTX;
  439. #endif
  440. }
  441. }
  442. return chmod (file, file_mode);
  443. }
  444. extern void chmod_i4_sub (char *, char *, GFC_INTEGER_4 *,
  445. gfc_charlen_type, gfc_charlen_type);
  446. export_proto(chmod_i4_sub);
  447. void
  448. chmod_i4_sub (char *name, char *mode, GFC_INTEGER_4 * status,
  449. gfc_charlen_type name_len, gfc_charlen_type mode_len)
  450. {
  451. int val;
  452. val = chmod_func (name, mode, name_len, mode_len);
  453. if (status)
  454. *status = val;
  455. }
  456. extern void chmod_i8_sub (char *, char *, GFC_INTEGER_8 *,
  457. gfc_charlen_type, gfc_charlen_type);
  458. export_proto(chmod_i8_sub);
  459. void
  460. chmod_i8_sub (char *name, char *mode, GFC_INTEGER_8 * status,
  461. gfc_charlen_type name_len, gfc_charlen_type mode_len)
  462. {
  463. int val;
  464. val = chmod_func (name, mode, name_len, mode_len);
  465. if (status)
  466. *status = val;
  467. }
  468. #endif