dirent.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*!
  2. \file lib/db/dbmi_base/dirent.c
  3. \brief DBMI Library (base) - directory entities management
  4. (C) 1999-2010 by the GRASS Development Team
  5. This program is free software under the GNU General Public License
  6. (>=v2). Read the file COPYING that comes with GRASS for details.
  7. \author Joel Jones (CERL/UIUC)
  8. \author Upgraded to GRASS 5.7 by Radim Blazek
  9. */
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include <unistd.h>
  13. #include <grass/dbmi.h>
  14. /* NOTE: these should come from <unistd.h> or from <sys/file.h> */
  15. #define R_OK 4
  16. #define W_OK 2
  17. #define X_OK 1
  18. #include <sys/types.h>
  19. #ifdef USE_DIRECT
  20. # include <sys/dir.h>
  21. typedef struct direct dir_entry;
  22. #else
  23. # include <dirent.h>
  24. typedef struct dirent dir_entry;
  25. #endif
  26. extern DIR *opendir();
  27. extern dir_entry *readdir();
  28. static int cmp_dirent(const void *, const void *);
  29. static int get_perm(char *);
  30. static void sort_dirent(dbDirent *, int);
  31. /*!
  32. \brief Read directory and build an array of dbDirent's
  33. Append one entry with name = NULL to mark end of array
  34. \param dirname directory name
  35. \param[out] n number of entities
  36. \return pointer to dbDirent
  37. \return NULL on error
  38. */
  39. dbDirent *db_dirent(const char *dirname, int *n)
  40. {
  41. DIR *dp;
  42. dir_entry *entry;
  43. dbDirent *dirent;
  44. int i, count;
  45. char *path;
  46. int len, max;
  47. db_clear_error();
  48. *n = 0;
  49. dp = opendir(dirname);
  50. if (dp == NULL) {
  51. db_syserror(dirname);
  52. return (dbDirent *) NULL;
  53. }
  54. /* count the number of entries and get the strlen of the longest name */
  55. count = 0;
  56. max = 0;
  57. while ((entry = readdir(dp))) {
  58. count++;
  59. len = strlen(entry->d_name);
  60. if (len > max)
  61. max = len;
  62. }
  63. rewinddir(dp);
  64. path = db_malloc(strlen(dirname) + max + 2); /* extra 2 for / and NULL */
  65. if (path == NULL) {
  66. closedir(dp);
  67. return (dbDirent *) NULL;
  68. }
  69. dirent = db_alloc_dirent_array(count);
  70. if (dirent == NULL) {
  71. closedir(dp);
  72. return (dbDirent *) NULL;
  73. }
  74. *n = count;
  75. for (i = 0; i < count; i++) {
  76. entry = readdir(dp);
  77. if (entry == NULL) /* this shouldn't happen */
  78. break;
  79. if (DB_OK != db_set_string(&dirent[i].name, entry->d_name))
  80. break;
  81. sprintf(path, "%s/%s", dirname, entry->d_name);
  82. dirent[i].perm = get_perm(path);
  83. dirent[i].isdir = (db_isdir(path) == DB_OK);
  84. }
  85. closedir(dp);
  86. db_free(path);
  87. sort_dirent(dirent, *n);
  88. return dirent;
  89. }
  90. /*!
  91. \brief Free dbDirent
  92. \param dirent pointer to dbDirent
  93. \param count number of entities in the array
  94. */
  95. void db_free_dirent_array(dbDirent * dirent, int count)
  96. {
  97. int i;
  98. if (dirent) {
  99. for (i = 0; i < count; i++)
  100. db_free_string(&dirent[i].name);
  101. db_free(dirent);
  102. }
  103. }
  104. static int get_perm(char *path)
  105. {
  106. int perm;
  107. perm = 0;
  108. if (access(path, R_OK) == 0)
  109. perm |= DB_PERM_R;
  110. if (access(path, W_OK) == 0)
  111. perm |= DB_PERM_W;
  112. if (access(path, X_OK) == 0)
  113. perm |= DB_PERM_X;
  114. return perm;
  115. }
  116. static int cmp_dirent(const void *aa, const void *bb)
  117. {
  118. const dbDirent *a = aa;
  119. const dbDirent *b = bb;
  120. return strcmp(db_get_string((dbString *) & a->name),
  121. db_get_string((dbString *) & b->name));
  122. }
  123. static void sort_dirent(dbDirent * a, int n)
  124. {
  125. qsort(a, n, sizeof(dbDirent), cmp_dirent);
  126. }
  127. /*!
  128. \brief Allocate dirent array
  129. \param count number of entities in the array
  130. \return pointer to dbDirent array
  131. \return NULL on failure
  132. */
  133. dbDirent *db_alloc_dirent_array(int count)
  134. {
  135. int i;
  136. dbDirent *dirent;
  137. dirent = (dbDirent *) db_calloc(count, sizeof(dbDirent));
  138. if (dirent == NULL)
  139. return dirent;
  140. for (i = 0; i < count; i++)
  141. db_init_string(&dirent[i].name);
  142. return dirent;
  143. }