OSDN Git Service

shrink mine
[nethackexpress/trunk.git] / sys / vms / vmsfiles.c
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. */
4
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>
11
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 *));
20
21 #include <rms.h>
22 #if 0
23 #include <psldef.h>
24 #else
25 #define PSL$C_EXEC 1    /* executive mode, for priv'd logical name handling */
26 #endif
27 #include <errno.h>
28 #ifndef C$$TRANSLATE    /* don't rely on VAXCRTL's internal routine */
29 #define C$$TRANSLATE(status) (errno = EVMSERR,  vaxc$errno = (status))
30 #endif
31 extern unsigned long sys$parse(), sys$search(), sys$enter(), sys$remove();
32 extern int VDECL(lib$match_cond, (int,int,...));
33
34 #define vms_success(sts) ((sts)&1)              /* odd, */
35 #define vms_failure(sts) (!vms_success(sts))    /* even */
36
37 /* vms_link() -- create an additional directory for an existing file */
38 int vms_link(file, new)
39 const char *file, *new;
40 {
41     struct FAB fab;
42     struct NAM nam;
43     unsigned short fid[3];
44     char esa[NAM$C_MAXRSS];
45
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);
50     fab.fab$l_nam = &nam;
51     nam = cc$rms_nam;
52     nam.nam$l_esa = esa;
53     nam.nam$b_ess = sizeof esa;
54
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);
61
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;
68
69             (void) sys$enter(&fab);
70         }
71     }
72
73     if (vms_failure(fab.fab$l_sts)) {
74         C$$TRANSLATE(fab.fab$l_sts);
75         return -1;
76     }
77     return 0;   /* success */
78 }
79
80 /*
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!).
84  */
85 int vms_unlink(file)
86 const char *file;
87 {
88     struct FAB fab;
89     struct NAM nam;
90     char esa[NAM$C_MAXRSS];
91
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;
100
101     if (vms_failure(sys$parse(&fab)) || vms_failure(sys$remove(&fab))) {
102         C$$TRANSLATE(fab.fab$l_sts);
103         return -1;
104     }
105     return 0;
106 }
107
108 /*
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.)
114  */
115 #undef creat
116 int vms_creat(file, mode)
117 const char *file;
118 unsigned int mode;
119 {
120     if (index(file, ';')) {
121         /* assumes remove or delete, not vms_unlink */
122         if (!unlink(file)) {
123             (void)sleep(1);
124             (void)unlink(file);
125         }
126     }
127     return creat(file, mode, "shr=nil", "mbc=32", "mbf=2", "rop=wbh");
128 }
129
130 /*
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).
134  */
135 #undef open
136 int vms_open(file, flags, mode)
137 const char *file;
138 int flags;
139 unsigned int mode;
140 {
141     int fd = open(file, flags, mode, "mbc=32", "mbf=2", "rop=rah");
142
143     if (fd < 0 && errno == EVMSERR && lib$match_cond(vaxc$errno, RMS$_FLK)) {
144         (void)sleep(1);
145         fd = open(file, flags, mode, "mbc=32", "mbf=2", "rop=rah");
146     }
147     return fd;
148 }
149
150 /*
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.
155  */
156 boolean
157 same_dir(d1, d2)
158 const char *d1, *d2;
159 {
160     if (!d1 || !*d1 || !d2 || !*d2)
161         return FALSE;
162     else if (!strcmp(d1, d2))   /* strcmpi() would be better, but that leads */
163         return TRUE;            /* to linking problems for the utilities */
164     else {
165         struct FAB f1, f2;
166         struct NAM n1, n2;
167
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 */
176
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]; }*/
183     }
184 }
185
186
187 /*
188  * c__translate -- substitute for VAXCRTL routine C$$TRANSLATE.
189  *
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.
194  *
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.
198  */
199 #include <errno.h>
200 #include <ssdef.h>
201 #include <rmsdef.h>
202 /* #include <libdef.h> */
203 /* #include <mthdef.h> */
204
205 #define VALUE(U)        trans = U; break
206 #define CASE1(V)        case (V >> 3)
207 #define CASE2(V,W)      CASE1(V): CASE1(W)
208
209 int c__translate(code)
210     int code;
211 {
212     register int trans;
213
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 */
223         CASE1(RMS$_DEV):
224         CASE2(SS$_NOSUCHDEV,SS$_DEVNOTMOUNT):
225                                 VALUE(ENXIO);   /* no such device or address codes */
226         CASE1(RMS$_DME):
227      /* CASE1(LIB$INSVIRMEM): */
228         CASE2(SS$_VASFULL,SS$_INSFWSL):
229                                 VALUE(ENOMEM);  /* not enough core */
230         CASE1(SS$_ACCVIO):
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 */
240         CASE1(SS$_NOIOCHAN):
241                                 VALUE(EMFILE);  /* too many open files */
242         CASE1(RMS$_FUL):
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 */
247         default:
248                                 VALUE(EVMSERR);
249     };
250
251     errno = trans;
252     vaxc$errno = code;
253     return code;        /* (not very useful) */
254 }
255
256 #undef VALUE
257 #undef CASE1
258 #undef CASE2
259
260 static char base_name[NAM$C_MAXRSS+1];
261
262 /* return a copy of the 'base' portion of a filename */
263 char *
264 vms_basename(name)
265 const char *name;
266 {
267     unsigned len;
268     char *base, *base_p;
269     register const char *name_p;
270
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 */
277
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);
282
283     /* return a lowercase copy of the name in a private static buffer */
284     base = strncpy(base_name, name, len);
285     base[len] = '\0';
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);
289
290     return base;
291 }
292
293 /*vmsfiles.c*/