NHDT->ANH, nethack->anethack, nhdat->anhdat
[aNetHack.git] / sys / vms / vmsfiles.c
blob1086446b617b7d75e4b7a6168411d1d41017542f
1 /* aNetHack 0.0.1 vmsfiles.c $ANH-Date: 1449801740 2015/12/11 02:42:20 $ $ANH-Branch: aNetHack-3.6.0 $:$ANH-Revision: 1.10 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* aNetHack may be freely redistributed. See license for details. */
5 /*
6 * VMS-specific file manipulation routines to implement some missing
7 * routines or substitute for ones where we want behavior modification.
8 */
9 #include "config.h"
10 #include <ctype.h>
12 /* lint supression due to lack of extern.h */
13 int FDECL(vms_link, (const char *, const char *));
14 int FDECL(vms_unlink, (const char *));
15 int FDECL(vms_creat, (const char *, unsigned int));
16 boolean FDECL(same_dir, (const char *, const char *));
17 int FDECL(c__translate, (int));
19 #include <rms.h>
20 #if 0
21 #include <psldef.h>
22 #else
23 #define PSL$C_EXEC 1 /* executive mode, for priv'd logical name handling */
24 #endif
25 #include <errno.h>
26 #ifndef C$$TRANSLATE /* don't rely on VAXCRTL's internal routine */
27 #define C$$TRANSLATE(status) (errno = EVMSERR, vaxc$errno = (status))
28 #endif
29 extern unsigned long sys$parse(), sys$search(), sys$enter(), sys$remove();
30 extern int VDECL(lib$match_cond, (int, int, ...));
32 #define vms_success(sts) ((sts) & 1) /* odd, */
33 #define vms_failure(sts) (!vms_success(sts)) /* even */
35 /* vms_link() -- create an additional directory for an existing file */
36 int
37 vms_link(file, new)
38 const char *file, *new;
40 struct FAB fab;
41 struct NAM nam;
42 unsigned short fid[3];
43 char esa[NAM$C_MAXRSS];
45 fab = cc$rms_fab; /* set block ID and length, zero the rest */
46 fab.fab$l_fop = FAB$M_OFP;
47 fab.fab$l_fna = (char *) file;
48 fab.fab$b_fns = strlen(file);
49 fab.fab$l_nam = &nam;
50 nam = cc$rms_nam;
51 nam.nam$l_esa = esa;
52 nam.nam$b_ess = sizeof esa;
54 if (vms_success(sys$parse(&fab)) && vms_success(sys$search(&fab))) {
55 fid[0] = nam.nam$w_fid[0];
56 fid[1] = nam.nam$w_fid[1];
57 fid[2] = nam.nam$w_fid[2];
58 fab.fab$l_fna = (char *) new;
59 fab.fab$b_fns = strlen(new);
61 if (vms_success(sys$parse(&fab))) {
62 nam.nam$w_fid[0] = fid[0];
63 nam.nam$w_fid[1] = fid[1];
64 nam.nam$w_fid[2] = fid[2];
65 nam.nam$l_esa = nam.nam$l_name;
66 nam.nam$b_esl = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver;
68 (void) sys$enter(&fab);
72 if (vms_failure(fab.fab$l_sts)) {
73 C$$TRANSLATE(fab.fab$l_sts);
74 return -1;
76 return 0; /* success */
80 vms_unlink() -- remove a directory entry for a file; should only be used
81 for files which have had extra directory entries added, not for deletion
82 (because the file won't be deleted, just made inaccessible!).
84 int
85 vms_unlink(file)
86 const char *file;
88 struct FAB fab;
89 struct NAM nam;
90 char esa[NAM$C_MAXRSS];
92 fab = cc$rms_fab; /* set block ID and length, zero the rest */
93 fab.fab$l_fop = FAB$M_DLT;
94 fab.fab$l_fna = (char *) file;
95 fab.fab$b_fns = strlen(file);
96 fab.fab$l_nam = &nam;
97 nam = cc$rms_nam;
98 nam.nam$l_esa = esa;
99 nam.nam$b_ess = sizeof esa;
101 if (vms_failure(sys$parse(&fab)) || vms_failure(sys$remove(&fab))) {
102 C$$TRANSLATE(fab.fab$l_sts);
103 return -1;
105 return 0;
109 Substitute creat() routine -- if trying to create a specific version,
110 explicitly remove an existing file of the same name. Since it's only
111 used when we expect exclusive access, add a couple RMS options for
112 optimization. (Don't allow sharing--eliminates coordination overhead,
113 and use 32 block buffer for faster throughput; ~30% speedup measured.)
115 #undef creat
117 vms_creat(file, mode)
118 const char *file;
119 unsigned int mode;
121 char filnambuf[BUFSIZ]; /*(not BUFSZ)*/
123 if (index(file, ';')) {
124 /* assumes remove or delete, not vms_unlink */
125 if (!unlink(file)) {
126 (void) sleep(1);
127 (void) unlink(file);
129 } else if (!index(file, '.')) {
130 /* force some punctuation to be present */
131 file = strcat(strcpy(filnambuf, file), ".");
133 return creat(file, mode, "shr=nil", "mbc=32", "mbf=2", "rop=wbh");
137 Similar substitute for open() -- if an open attempt fails due to being
138 locked by another user, retry it once (work-around for a limitation of
139 at least one NFS implementation).
141 #undef open
143 vms_open(file, flags, mode)
144 const char *file;
145 int flags;
146 unsigned int mode;
148 char filnambuf[BUFSIZ]; /*(not BUFSZ)*/
149 int fd;
151 if (!index(file, '.') && !index(file, ';')) {
152 /* force some punctuation to be present to make sure that
153 the file name can't accidentally match a logical name */
154 file = strcat(strcpy(filnambuf, file), ";0");
156 fd = open(file, flags, mode, "mbc=32", "mbf=2", "rop=rah");
157 if (fd < 0 && errno == EVMSERR && lib$match_cond(vaxc$errno, RMS$_FLK)) {
158 (void) sleep(1);
159 fd = open(file, flags, mode, "mbc=32", "mbf=2", "rop=rah");
161 return fd;
164 /* do likewise for fopen() */
165 #undef fopen
166 FILE *
167 vms_fopen(file, mode)
168 const char *file, *mode;
170 char filnambuf[BUFSIZ]; /*(not BUFSZ)*/
171 FILE *fp;
173 if (!index(file, '.') && !index(file, ';')) {
174 /* force some punctuation to be present to make sure that
175 the file name can't accidentally match a logical name */
176 file = strcat(strcpy(filnambuf, file), ";0");
178 fp = fopen(file, mode, "mbc=32", "mbf=2", "rop=rah");
179 if (!fp && errno == EVMSERR && lib$match_cond(vaxc$errno, RMS$_FLK)) {
180 (void) sleep(1);
181 fp = fopen(file, mode, "mbc=32", "mbf=2", "rop=rah");
183 return fp;
187 Determine whether two strings contain the same directory name.
188 Used for deciding whether installed privileges should be disabled
189 when HACKDIR is defined in the environment (or specified via -d on
190 the command line). This version doesn't handle Unix-style file specs.
192 boolean
193 same_dir(d1, d2)
194 const char *d1, *d2;
196 if (!d1 || !*d1 || !d2 || !*d2)
197 return FALSE;
198 else if (!strcmp(d1, d2)) /* strcmpi() would be better, but that leads */
199 return TRUE; /* to linking problems for the utilities */
200 else {
201 struct FAB f1, f2;
202 struct NAM n1, n2;
204 f1 = f2 = cc$rms_fab; /* initialize file access block */
205 n1 = n2 = cc$rms_nam; /* initialize name block */
206 f1.fab$b_acmodes = PSL$C_EXEC << FAB$V_LNM_MODE;
207 f1.fab$b_fns = strlen(f1.fab$l_fna = (char *) d1);
208 f2.fab$b_fns = strlen(f2.fab$l_fna = (char *) d2);
209 f1.fab$l_nam = (genericptr_t) &n1; /* link nam to fab */
210 f2.fab$l_nam = (genericptr_t) &n2;
211 /* want true device name */
212 n1.nam$b_nop = n2.nam$b_nop = NAM$M_NOCONCEAL;
214 return (vms_success(sys$parse(&f1)) && vms_success(sys$parse(&f2))
215 && n1.nam$t_dvi[0] == n2.nam$t_dvi[0]
216 && !strncmp(&n1.nam$t_dvi[1], &n2.nam$t_dvi[1],
217 n1.nam$t_dvi[0])
218 && !memcmp((genericptr_t) n1.nam$w_did,
219 (genericptr_t) n2.nam$w_did,
220 sizeof n1.nam$w_did)); /*{ short nam$w_did[3]; }*/
225 * c__translate -- substitute for VAXCRTL routine C$$TRANSLATE.
227 * Try to convert a VMS status code into its Unix equivalent,
228 * then set `errno' to that value; use EVMSERR if there's no
229 * appropriate translation; set `vaxc$errno' to the original
230 * status code regardless.
232 * These translations match only a subset of VAXCRTL's lookup
233 * table, but work even if the severity has been adjusted or
234 * the inhibit-message bit has been set.
236 #include <errno.h>
237 #include <ssdef.h>
238 #include <rmsdef.h>
239 /* #include <libdef.h> */
240 /* #include <mthdef.h> */
242 #define VALUE(U) \
243 trans = U; \
244 break
245 #define CASE1(V) case (V >> 3)
246 #define CASE2(V, W) CASE1(V) : CASE1(W)
249 c__translate(code)
250 int code;
252 register int trans;
254 /* clang-format off */
255 /* *INDENT-OFF* */
256 switch ((code & 0x0FFFFFF8) >> 3) { /* strip upper 4 and bottom 3 bits */
257 CASE2(RMS$_PRV, SS$_NOPRIV):
258 VALUE(EPERM); /* not owner */
259 CASE2(RMS$_DNF, RMS$_DIR):
260 CASE2(RMS$_FNF, RMS$_FND):
261 CASE1(SS$_NOSUCHFILE):
262 VALUE(ENOENT); /* no such file or directory */
263 CASE2(RMS$_IFI, RMS$_ISI):
264 VALUE(EIO); /* i/o error */
265 CASE1(RMS$_DEV):
266 CASE2(SS$_NOSUCHDEV, SS$_DEVNOTMOUNT):
267 VALUE(ENXIO); /* no such device or address codes */
268 CASE1(RMS$_DME):
269 /* CASE1(LIB$INSVIRMEM): */
270 CASE2(SS$_VASFULL, SS$_INSFWSL):
271 VALUE(ENOMEM); /* not enough core */
272 CASE1(SS$_ACCVIO):
273 VALUE(EFAULT); /* bad address */
274 CASE2(RMS$_DNR, SS$_DEVASSIGN):
275 CASE2(SS$_DEVALLOC, SS$_DEVALRALLOC):
276 CASE2(SS$_DEVMOUNT, SS$_DEVACTIVE):
277 VALUE(EBUSY); /* mount device busy codes to name a few */
278 CASE2(RMS$_FEX, SS$_FILALRACC):
279 VALUE(EEXIST); /* file exists */
280 CASE2(RMS$_IDR, SS$_BADIRECTORY):
281 VALUE(ENOTDIR); /* not a directory */
282 CASE1(SS$_NOIOCHAN):
283 VALUE(EMFILE); /* too many open files */
284 CASE1(RMS$_FUL):
285 CASE2(SS$_DEVICEFULL, SS$_EXDISKQUOTA):
286 VALUE(ENOSPC); /* no space left on disk codes */
287 CASE2(RMS$_WLK, SS$_WRITLCK):
288 VALUE(EROFS); /* read-only file system */
289 default:
290 VALUE(EVMSERR);
292 /* clang-format on */
293 /* *INDENT-ON* */
295 errno = trans;
296 vaxc$errno = code;
297 return code; /* (not very useful) */
300 #undef VALUE
301 #undef CASE1
302 #undef CASE2
304 static char base_name[NAM$C_MAXRSS + 1];
306 /* return a copy of the 'base' portion of a filename */
307 char *
308 vms_basename(name)
309 const char *name;
311 unsigned len;
312 char *base, *base_p;
313 register const char *name_p;
315 /* skip directory/path */
316 if ((name_p = strrchr(name, ']')) != 0)
317 name = name_p + 1;
318 if ((name_p = strrchr(name, '>')) != 0)
319 name = name_p + 1;
320 if ((name_p = strrchr(name, ':')) != 0)
321 name = name_p + 1;
322 if ((name_p = strrchr(name, '/')) != 0)
323 name = name_p + 1;
324 if (!*name)
325 name = "."; /* this should never happen */
327 /* find extension/version and derive length of basename */
328 if ((name_p = strchr(name, '.')) == 0 || name_p == name)
329 name_p = strchr(name, ';');
330 len = (name_p && name_p > name) ? name_p - name : strlen(name);
332 /* return a lowercase copy of the name in a private static buffer */
333 base = strncpy(base_name, name, len);
334 base[len] = '\0';
335 /* we don't use lcase() so that utilities won't need hacklib.c */
336 for (base_p = base; base_p < &base[len]; base_p++)
337 if (isupper(*base_p))
338 *base_p = tolower(*base_p);
340 return base;
343 /*vmsfiles.c*/