1
/* SCCS Id: @(#)vmsfiles.c 3.4 1999/08/29 */
2
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3
/* NetHack 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
int FDECL(vms_open, (const char *,int,unsigned int));
17
boolean FDECL(same_dir, (const char *,const char *));
18
int FDECL(c__translate, (int));
19
char *FDECL(vms_basename, (const char *));
25
#define PSL$C_EXEC 1 /* executive mode, for priv'd logical name handling */
28
#ifndef C$$TRANSLATE /* don't rely on VAXCRTL's internal routine */
29
#define C$$TRANSLATE(status) (errno = EVMSERR, vaxc$errno = (status))
31
extern unsigned long sys$parse(), sys$search(), sys$enter(), sys$remove();
32
extern int VDECL(lib$match_cond, (int,int,...));
34
#define vms_success(sts) ((sts)&1) /* odd, */
35
#define vms_failure(sts) (!vms_success(sts)) /* even */
37
/* vms_link() -- create an additional directory for an existing file */
38
int vms_link(file, new)
39
const char *file, *new;
43
unsigned short fid[3];
44
char esa[NAM$C_MAXRSS];
46
fab = cc$rms_fab; /* set block ID and length, zero the rest */
47
fab.fab$l_fop = FAB$M_OFP;
48
fab.fab$l_fna = (char *) file;
49
fab.fab$b_fns = strlen(file);
53
nam.nam$b_ess = sizeof esa;
55
if (vms_success(sys$parse(&fab)) && vms_success(sys$search(&fab))) {
56
fid[0] = nam.nam$w_fid[0];
57
fid[1] = nam.nam$w_fid[1];
58
fid[2] = nam.nam$w_fid[2];
59
fab.fab$l_fna = (char *) new;
60
fab.fab$b_fns = strlen(new);
62
if (vms_success(sys$parse(&fab))) {
63
nam.nam$w_fid[0] = fid[0];
64
nam.nam$w_fid[1] = fid[1];
65
nam.nam$w_fid[2] = fid[2];
66
nam.nam$l_esa = nam.nam$l_name;
67
nam.nam$b_esl = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver;
69
(void) sys$enter(&fab);
73
if (vms_failure(fab.fab$l_sts)) {
74
C$$TRANSLATE(fab.fab$l_sts);
77
return 0; /* success */
81
vms_unlink() -- remove a directory entry for a file; should only be used
82
for files which have had extra directory entries added, not for deletion
83
(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.)
116
int vms_creat(file, mode)
120
if (index(file, ';')) {
121
/* assumes remove or delete, not vms_unlink */
127
return creat(file, mode, "shr=nil", "mbc=32", "mbf=2", "rop=wbh");
131
Similar substitute for open() -- if an open attempt fails due to being
132
locked by another user, retry it once (work-around for a limitation of
133
at least one NFS implementation).
136
int vms_open(file, flags, mode)
141
int fd = open(file, flags, mode, "mbc=32", "mbf=2", "rop=rah");
143
if (fd < 0 && errno == EVMSERR && lib$match_cond(vaxc$errno, RMS$_FLK)) {
145
fd = open(file, flags, mode, "mbc=32", "mbf=2", "rop=rah");
151
Determine whether two strings contain the same directory name.
152
Used for deciding whether installed privileges should be disabled
153
when HACKDIR is defined in the environment (or specified via -d on
154
the command line). This version doesn't handle Unix-style file specs.
160
if (!d1 || !*d1 || !d2 || !*d2)
162
else if (!strcmp(d1, d2)) /* strcmpi() would be better, but that leads */
163
return TRUE; /* to linking problems for the utilities */
168
f1 = f2 = cc$rms_fab; /* initialize file access block */
169
n1 = n2 = cc$rms_nam; /* initialize name block */
170
f1.fab$b_acmodes = PSL$C_EXEC << FAB$V_LNM_MODE;
171
f1.fab$b_fns = strlen( f1.fab$l_fna = (char *)d1 );
172
f2.fab$b_fns = strlen( f2.fab$l_fna = (char *)d2 );
173
f1.fab$l_nam = (genericptr_t)&n1; /* link nam to fab */
174
f2.fab$l_nam = (genericptr_t)&n2;
175
n1.nam$b_nop = n2.nam$b_nop = NAM$M_NOCONCEAL; /* want true device name */
177
return (vms_success(sys$parse(&f1)) && vms_success(sys$parse(&f2))
178
&& n1.nam$t_dvi[0] == n2.nam$t_dvi[0]
179
&& !strncmp(&n1.nam$t_dvi[1], &n2.nam$t_dvi[1], n1.nam$t_dvi[0])
180
&& !memcmp((genericptr_t)n1.nam$w_did,
181
(genericptr_t)n2.nam$w_did,
182
sizeof n1.nam$w_did)); /*{ short nam$w_did[3]; }*/
188
* c__translate -- substitute for VAXCRTL routine C$$TRANSLATE.
190
* Try to convert a VMS status code into its Unix equivalent,
191
* then set `errno' to that value; use EVMSERR if there's no
192
* appropriate translation; set `vaxc$errno' to the original
193
* status code regardless.
195
* These translations match only a subset of VAXCRTL's lookup
196
* table, but work even if the severity has been adjusted or
197
* the inhibit-message bit has been set.
202
/* #include <libdef.h> */
203
/* #include <mthdef.h> */
205
#define VALUE(U) trans = U; break
206
#define CASE1(V) case (V >> 3)
207
#define CASE2(V,W) CASE1(V): CASE1(W)
209
int c__translate(code)
214
switch ((code & 0x0FFFFFF8) >> 3) { /* strip upper 4 and bottom 3 bits */
215
CASE2(RMS$_PRV,SS$_NOPRIV):
216
VALUE(EPERM); /* not owner */
217
CASE2(RMS$_DNF,RMS$_DIR):
218
CASE2(RMS$_FNF,RMS$_FND):
219
CASE1(SS$_NOSUCHFILE):
220
VALUE(ENOENT); /* no such file or directory */
221
CASE2(RMS$_IFI,RMS$_ISI):
222
VALUE(EIO); /* i/o error */
224
CASE2(SS$_NOSUCHDEV,SS$_DEVNOTMOUNT):
225
VALUE(ENXIO); /* no such device or address codes */
227
/* CASE1(LIB$INSVIRMEM): */
228
CASE2(SS$_VASFULL,SS$_INSFWSL):
229
VALUE(ENOMEM); /* not enough core */
231
VALUE(EFAULT); /* bad address */
232
CASE2(RMS$_DNR,SS$_DEVASSIGN):
233
CASE2(SS$_DEVALLOC,SS$_DEVALRALLOC):
234
CASE2(SS$_DEVMOUNT,SS$_DEVACTIVE):
235
VALUE(EBUSY); /* mount device busy codes to name a few */
236
CASE2(RMS$_FEX,SS$_FILALRACC):
237
VALUE(EEXIST); /* file exists */
238
CASE2(RMS$_IDR,SS$_BADIRECTORY):
239
VALUE(ENOTDIR); /* not a directory */
241
VALUE(EMFILE); /* too many open files */
243
CASE2(SS$_DEVICEFULL,SS$_EXDISKQUOTA):
244
VALUE(ENOSPC); /* no space left on disk codes */
245
CASE2(RMS$_WLK,SS$_WRITLCK):
246
VALUE(EROFS); /* read-only file system */
253
return code; /* (not very useful) */
260
static char base_name[NAM$C_MAXRSS+1];
262
/* return a copy of the 'base' portion of a filename */
269
register const char *name_p;
271
/* skip directory/path */
272
if ((name_p = strrchr(name, ']')) != 0) name = name_p + 1;
273
if ((name_p = strrchr(name, '>')) != 0) name = name_p + 1;
274
if ((name_p = strrchr(name, ':')) != 0) name = name_p + 1;
275
if ((name_p = strrchr(name, '/')) != 0) name = name_p + 1;
276
if (!*name) name = "."; /* this should never happen */
278
/* find extension/version and derive length of basename */
279
if ((name_p = strchr(name, '.')) == 0 || name_p == name)
280
name_p = strchr(name, ';');
281
len = (name_p && name_p > name) ? name_p - name : strlen(name);
283
/* return a lowercase copy of the name in a private static buffer */
284
base = strncpy(base_name, name, len);
286
/* we don't use lcase() so that utilities won't need hacklib.c */
287
for (base_p = base; base_p < &base[len]; base_p++)
288
if (isupper(*base_p)) *base_p = tolower(*base_p);