_stat.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*
  2. Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
  3. See the accompanying file LICENSE, version 1999-Oct-05 or later
  4. (the contents of which are also included in zip.h) for terms of use.
  5. If, for some reason, both of these files are missing, the Info-ZIP license
  6. also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
  7. */
  8. #pragma library
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <errno.h>
  12. #include <string.h>
  13. #include <sc.h>
  14. #include <peek.h>
  15. #include <lub.h>
  16. #include <fdb.h>
  17. #include <fsa.h>
  18. #include "theos/stat.h"
  19. /* replacement for standard library functions stat and fstat */
  20. int _stat_(struct stat* st, struct fdb* fdb);
  21. int _dstat_(struct stat* st);
  22. #define peekucb() peeknuc()
  23. /* map THEOS protection code to Unix modes */
  24. unsigned short _tm2um_(char protect)
  25. {
  26. unsigned short umask = 0;
  27. if (!(protect & _FDB_READ_PROTECT))
  28. umask = S_IRUSR|S_IRGRP;
  29. if (!(protect & _FDB_WRITE_PROTECT))
  30. umask |= S_IWUSR|S_IWGRP;
  31. if (!(protect & _FDB_EXECUTE_PROTECT))
  32. umask |= S_IXUSR|S_IXGRP;
  33. if (!(protect & _FDB_ERASE_PROTECT))
  34. umask |= S_IEUSR|S_IEGRP;
  35. if (!(protect & _FDB_SHARED_READ_PROTECT)) {
  36. if (_osmajor > 3)
  37. umask |= S_IROTH|S_IXOTH;
  38. else
  39. umask |= S_IROTH;
  40. }
  41. if (!(protect & _FDB_SHARED_WRITE_PROTECT))
  42. umask |= S_IWOTH;
  43. if (!(protect & _FDB_MODIFIED)) {
  44. if (_osmajor > 3)
  45. umask |= S_IMODF;
  46. else
  47. umask |= S_IXOTH;
  48. }
  49. if (protect & _FDB_NOT_HIDDEN)
  50. umask |= S_INHID;
  51. return umask;
  52. }
  53. /* map Unix modes to THEOS protections */
  54. char _um2tm_(unsigned short mask)
  55. {
  56. char protect = 0;
  57. if (!(mask & (S_IRUSR|S_IRGRP)))
  58. protect |= _FDB_READ_PROTECT;
  59. if (!(mask & (S_IWUSR|S_IWGRP)))
  60. protect |= _FDB_WRITE_PROTECT;
  61. if (!(mask & (S_IXUSR|S_IXGRP)))
  62. protect |= _FDB_EXECUTE_PROTECT;
  63. if (!(mask & (S_IEUSR|S_IEGRP)))
  64. protect |= _FDB_ERASE_PROTECT;
  65. if (_osmajor < 4) {
  66. if (!(mask & S_IROTH))
  67. protect |= _FDB_SHARED_READ_PROTECT;
  68. } else {
  69. if (!(mask & (S_IROTH|S_IXOTH)))
  70. protect |= _FDB_SHARED_READ_PROTECT;
  71. }
  72. if (!(mask & S_IWOTH))
  73. protect |= _FDB_SHARED_WRITE_PROTECT;
  74. if (mask & S_IMODF && _osmajor > 3)
  75. protect |= _FDB_MODIFIED;
  76. if (mask & S_INHID && _osmajor > 3)
  77. protect |= _FDB_NOT_HIDDEN;
  78. return protect;
  79. }
  80. /* root directory stat */
  81. static int rdirstat(const char* fn, struct stat *st)
  82. {
  83. register char* p = strchr(fn, ':');
  84. char drive;
  85. drive = p ? p[1] : 'S';
  86. if (drive >= 'a' && drive <= 'Z')
  87. drive -= 0x40;
  88. memset(st, 0, sizeof(struct stat));
  89. if (getlub(drive - 'A') != 255) {
  90. st->st_org = _FDB_STAT_DIRECTORY;
  91. st->st_mode = S_IFDIR|S_IRUSR|S_IWUSR|S_IROTH|S_IWOTH;
  92. st->st_nlink = 1;
  93. st->st_dev = st->st_rdev = drive - 'A';
  94. st->st_uid = st->st_gid = getuid();
  95. st->st_protect = _FDB_ERASE_PROTECT;
  96. return 0;
  97. }
  98. errno = _errnum = ENOENT;
  99. _errarg = fn;
  100. return -1;
  101. }
  102. #ifdef LOCATE_BUG
  103. /* locate fails when stating a file in root dir from a directory with a
  104. * relative path. Workaround by setting directory to root dir
  105. * getting the file directory block, then restoring the current directory.
  106. */
  107. struct fdb* __locate(const char* fn, char* buf, short* drv)
  108. {
  109. struct fdb* fdb;
  110. char buf2[FILENAME_MAX];
  111. char cwd[FILENAME_MAX];
  112. char drive[3];
  113. char* p;
  114. char* q;
  115. /* return if file found */
  116. if (fdb = _locate(fn, buf, drv))
  117. return fdb;
  118. /* if file name does not contain a path delimiter it really does not exist.
  119. */
  120. strcpy(buf2, fn);
  121. if ((p = strrchr(buf2, '/')) == NULL)
  122. return NULL;
  123. /* get drive name from file path */
  124. q = strrchr(buf2, ':');
  125. /* cat drive name if any to directory path */
  126. if (q) {
  127. strncpy(drive, q, 2);
  128. drive[2] = '\0';
  129. strcpy(p, q);
  130. } else
  131. *p = '\0';
  132. /* save current directory */
  133. getcwd(cwd, FILENAME_MAX);
  134. /* chdir to directory path */
  135. chdir(buf2);
  136. /* get File Directory Block */
  137. p = strrchr(fn, '/');
  138. fdb = _locate(p + 1, buf, drv);
  139. /* restore current directory */
  140. chdir(cwd);
  141. return fdb;
  142. }
  143. #undef _locate
  144. #define _locate() __locate()
  145. /* same cause, same consequence for fopen and open.
  146. */
  147. FILE* _fopen(const char* fn, const char* mode)
  148. {
  149. FILE* fp;
  150. char buf[FILENAME_MAX];
  151. short drv;
  152. /* prepend a path to current dir to avoid use of default library */
  153. if (*fn != '.' && *fn != '/') {
  154. strcpy(buf, "./");
  155. strcat(buf, fn);
  156. return fopen(buf, mode);
  157. }
  158. if (fp = fopen(fn, mode))
  159. return fp;
  160. /* see comment for _locate */
  161. if (_locate(fn, buf, &drv)) {
  162. fn = strrchr(fn, '/');
  163. return fopen(fn, mode);
  164. }
  165. return NULL;
  166. }
  167. #undef open
  168. int open(const char*, int, ...);
  169. int __open(const char* fn, int mode)
  170. {
  171. int fd;
  172. char buf[FILENAME_MAX];
  173. short drv;
  174. /* prepend a path to current dir to avoid use of default library */
  175. if (*fn != '.' && *fn != '/') {
  176. strcpy(buf, "./");
  177. strcat(buf, fn);
  178. return open(buf, mode);
  179. }
  180. if ((fd = open(fn, mode)) != EOF)
  181. return fd;
  182. /* see comment for _locate */
  183. if (_locate(fn, buf, &drv)) {
  184. fn = strrchr(fn, '/');
  185. if (fn)
  186. return open(fn, mode);
  187. }
  188. return EOF;
  189. }
  190. #endif
  191. /* replacement for standard file stat */
  192. int _stat(const char *_fn, struct stat *st)
  193. {
  194. char buf[FILENAME_MAX], buf2[FILENAME_MAX], buf3[FILENAME_MAX];
  195. register struct fdb* fdb;
  196. register char* p;
  197. register char* fn;
  198. fn = strcpy(buf3, _fn);
  199. if (p = strrchr(fn, ':'))
  200. *p = 0;
  201. /* on current drive ./:d and .:m point to current dir
  202. * on another drive to root directory, workaround to avoid it */
  203. if (! strcmp(fn, "/") || ! strcmp(fn, ".") || ! strcmp(fn, "./")) {
  204. if (p == NULL) {
  205. /* current dir on current drive */
  206. fn = getcwd(buf2, FILENAME_MAX);
  207. /* getcwd returns NULL on root dir on drive S */
  208. if (fn == NULL)
  209. fn = strcpy(buf2, "/:S");
  210. /* getcwd returns /:d on root dir on any other drive */
  211. if (fn[1] == ':')
  212. return rdirstat(fn, st);
  213. } else {
  214. *p = ':';
  215. return rdirstat(fn, st);
  216. }
  217. if (p)
  218. *p = ':';
  219. } else {
  220. if (p)
  221. *p = ':';
  222. if (*fn != '.' && *fn != '/') {
  223. strcpy(buf2, "./");
  224. fn = strcat(buf2, fn);
  225. }
  226. }
  227. if (buf2 != fn)
  228. strcpy(buf2, fn);
  229. /* remove trailing slash before optional disk name */
  230. if (p = strrchr(buf2, '/')) {
  231. if (p[1] == ':') {
  232. *p = p[1];
  233. p[1] = p[2];
  234. p[2] = p[3];
  235. } else if (p[1] == '\0')
  236. *p = '\0';
  237. }
  238. /* if fn is a file get file directory block structure and device */
  239. if (fdb = _locate(buf2, buf, &st->st_dev)) {
  240. /* is it a file from another user... */
  241. if (strchr(buf2, '\\')
  242. /* a public system file... */
  243. || fdb->fileowner == 0
  244. /* or a file from the current user account ? */
  245. || fdb->fileowner == getuid())
  246. /* yes, return stat */
  247. return _stat_(st, fdb);
  248. else {
  249. /* no, say file doesn't exist */
  250. errno = _errnum = ENOENT;
  251. _errarg = fn;
  252. return -1;
  253. }
  254. }
  255. /* else should be a device, get device number from device name */
  256. st->st_rdev = st->st_dev = _lub_name(*fn == ':' ? fn+1 : fn);
  257. /* if it is really a device return device status */
  258. if (st->st_dev != -1 && getlub(st->st_dev) != 255)
  259. return _dstat_(st);
  260. /* neither an existing file or a device name, return EOF */
  261. st->st_rdev = st->st_dev = 0;
  262. errno = _errnum = ENOENT;
  263. _errarg = fn;
  264. return -1;
  265. }
  266. /* replacement for fstat */
  267. int _fstat(int fd, struct stat *st)
  268. {
  269. unsigned short fsanum;
  270. struct fsa fsa;
  271. register FILE *fp;
  272. int status;
  273. register int i;
  274. register char *p;
  275. if (fd < FOPEN_MAX) {
  276. fp = &stdin[fd];
  277. /* get File Save Area number */
  278. if (_fcntl(fp,1,0) & 0x80) {
  279. fsanum = (unsigned short) _fcntl(fp,83,0);
  280. st->st_dev = (unsigned short) _fcntl(fp,5,0);
  281. if (st->st_dev >= A_DISK && st->st_dev <= Z_DISK) {
  282. /* if opened file is a disk file */
  283. /* copy far fsa in protected segment to local fsa */
  284. for (i = 0, fsanum *= sizeof(fsa), p = (char *) &fsa;
  285. i < (sizeof(fsa));
  286. i++, fsanum++, p++)
  287. *p = _peekfsa((char *) fsanum);
  288. /* build stat structure from fsa */
  289. status = _stat_(st, (struct fdb*) &fsa);
  290. /* get blocksize */
  291. if ((st->st_blksize = _fcntl(fp,817,0)) == 0)
  292. st->st_blksize = BUFSIZ;
  293. return status;
  294. }
  295. /* return device status */
  296. return _dstat_(st);
  297. }
  298. }
  299. errno = _errnum = EBADF;
  300. return -1;
  301. }
  302. static int _isprt(int dev)
  303. {
  304. return IS_PRT_LUB(dev);
  305. }
  306. /* device stat */
  307. int _dstat_(st)
  308. register struct stat* st;
  309. {
  310. register struct ucb* ucb;
  311. ucb = getucb(st->st_dev);
  312. st->st_ino = 0;
  313. if (st->st_dev <= Z_DISK
  314. || (st->st_dev >= TAPE1 && st->st_dev <= TAPE4)) {
  315. st->st_mode = S_IFBLK | S_IWUSR | S_IRUSR;
  316. if (peekucb(&ucb->devowner) == 255)
  317. st->st_mode |= S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH;
  318. } else {
  319. st->st_mode = S_IFCHR | S_IWUSR;
  320. if (_isprt(st->st_dev))
  321. st->st_mode |= S_IRUSR;
  322. if (peekucb(&ucb->devowner) == 255) {
  323. st->st_mode |= S_IWGRP | S_IWOTH;
  324. if (_isprt(st->st_dev))
  325. st->st_mode |= S_IRGRP | S_IROTH;
  326. }
  327. }
  328. st->st_nlink = 1;
  329. st->st_uid = st->st_gid = getuid();
  330. st->st_size = 0;
  331. st->st_atime = st->st_mtime = st->st_ctime = 0;
  332. st->st_rlen = 0;
  333. st->st_klen = 0;
  334. st->st_grow = 0;
  335. st->st_blksize = 0;
  336. return 0;
  337. }
  338. /* regular file stat */
  339. int _stat_(st, fdb)
  340. register struct stat* st;
  341. register struct fdb* fdb;
  342. {
  343. st->st_rdev = st->st_dev;
  344. st->st_ino = 0;
  345. st->st_org = fdb->filestat;
  346. /* map fdb file status to stat mode */
  347. switch (fdb->filestat) {
  348. case _FDB_STAT_LIBRARY: st->st_mode = S_IFLIB; break;
  349. case _FDB_STAT_DIRECTORY: st->st_mode = S_IFDIR; break;
  350. case _FDB_STAT_STREAM: st->st_mode = S_IFREG; break;
  351. case _FDB_STAT_RELATIVE: st->st_mode = S_IFREL; break;
  352. case _FDB_STAT_KEYED: st->st_mode = S_IFKEY; break;
  353. case _FDB_STAT_INDEXED: st->st_mode = S_IFIND; break;
  354. case _FDB_STAT_RANDOM: st->st_mode = S_IFRND; break;
  355. case _FDB_STAT_PROGRAM: st->st_mode = S_IFR16; break;
  356. case _FDB_STAT_16_BIT_PROGRAM: st->st_mode = S_IFP16; break;
  357. case _FDB_STAT_32_BIT_PROGRAM: st->st_mode = S_IFP32; break;
  358. }
  359. /* map theos file protection codes to stat mode */
  360. st->st_mode |= _tm2um_(st->st_protect = fdb->protect);
  361. st->st_nlink = 1;
  362. st->st_uid = st->st_gid = fdb->fileowner;
  363. st->st_size = fdb->filesize;
  364. st->st_atime = st->st_mtime = st->st_ctime = getfiledate(fdb);
  365. st->st_blksize = 0;
  366. /* specific theos information */
  367. st->st_rlen = fdb->reclen;
  368. st->st_klen = fdb->keylen;
  369. st->st_grow = fdb->filegrow;
  370. return 0;
  371. }
  372. #include <direct.h>
  373. /* standard diropen fails on path endung with a '/', workaround */
  374. struct dirent* _opendir(const char* dirpath)
  375. {
  376. int l;
  377. char dirp[FILENAME_MAX];
  378. struct dirent* dir;
  379. if (dirpath && (l = strlen(dirpath))) {
  380. if (dirpath[l - 1] == '/') {
  381. strcpy(dirp, dirpath);
  382. dirp[l - 1] = '\0';
  383. return opendir(dirp);
  384. }
  385. }
  386. return opendir(dirpath);
  387. }