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);