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. */
6 * VMS-specific file manipulation routines to implement some missing
7 * routines or substitute for ones where we want behavior modification.
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));
23 #define PSL$C_EXEC 1 /* executive mode, for priv'd logical name handling */
26 #ifndef C$$TRANSLATE /* don't rely on VAXCRTL's internal routine */
27 #define C$$TRANSLATE(status) (errno = EVMSERR, vaxc$errno = (status))
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 */
38 const char *file
, *new;
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
);
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
);
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!).
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
);
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
);
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.)
117 vms_creat(file
, mode
)
121 char filnambuf
[BUFSIZ
]; /*(not BUFSZ)*/
123 if (index(file
, ';')) {
124 /* assumes remove or delete, not vms_unlink */
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).
143 vms_open(file
, flags
, mode
)
148 char filnambuf
[BUFSIZ
]; /*(not BUFSZ)*/
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
)) {
159 fd
= open(file
, flags
, mode
, "mbc=32", "mbf=2", "rop=rah");
164 /* do likewise for fopen() */
167 vms_fopen(file
, mode
)
168 const char *file
, *mode
;
170 char filnambuf
[BUFSIZ
]; /*(not BUFSZ)*/
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
)) {
181 fp
= fopen(file
, mode
, "mbc=32", "mbf=2", "rop=rah");
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.
196 if (!d1
|| !*d1
|| !d2
|| !*d2
)
198 else if (!strcmp(d1
, d2
)) /* strcmpi() would be better, but that leads */
199 return TRUE
; /* to linking problems for the utilities */
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],
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.
239 /* #include <libdef.h> */
240 /* #include <mthdef.h> */
245 #define CASE1(V) case (V >> 3)
246 #define CASE2(V, W) CASE1(V) : CASE1(W)
254 /* clang-format 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 */
266 CASE2(SS$_NOSUCHDEV
, SS$_DEVNOTMOUNT
):
267 VALUE(ENXIO
); /* no such device or address codes */
269 /* CASE1(LIB$INSVIRMEM): */
270 CASE2(SS$_VASFULL
, SS$_INSFWSL
):
271 VALUE(ENOMEM
); /* not enough core */
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 */
283 VALUE(EMFILE
); /* too many open files */
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 */
292 /* clang-format on */
297 return code
; /* (not very useful) */
304 static char base_name
[NAM$C_MAXRSS
+ 1];
306 /* return a copy of the 'base' portion of a filename */
313 register const char *name_p
;
315 /* skip directory/path */
316 if ((name_p
= strrchr(name
, ']')) != 0)
318 if ((name_p
= strrchr(name
, '>')) != 0)
320 if ((name_p
= strrchr(name
, ':')) != 0)
322 if ((name_p
= strrchr(name
, '/')) != 0)
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
);
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
);