~ubuntu-branches/ubuntu/natty/dnprogs/natty

« back to all changes in this revision

Viewing changes to dapfs/filenames.c

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Caulfield
  • Date: 2005-10-30 15:09:21 UTC
  • Revision ID: james.westby@ubuntu.com-20051030150921-h9yn20kzxtwmjh2a
Tags: 2.32
* fal removes [] from names as they could cause confusion.
* Fixed crash in libdap if a connection gets closed more than once.
* Fix libdnet's dnet_recv to cope with 0 being returned from recvmsg.
* Some minor manpage & packaging bugs fixed.
* Include dnlogin, a replacement for sethost.
* Include libvaxdata - a library of routines for converting between VAX.
  data formats and Unix ones. Contributed by Larry Baker of the 
  US Geological Survey.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************************************
 
2
    (c) 2005 P.J. Caulfield               patrick@tykepenguin.cix.co.uk
 
3
 
 
4
    This program is free software; you can redistribute it and/or modify
 
5
    it under the terms of the GNU General Public License as published by
 
6
    the Free Software Foundation; either version 2 of the License, or
 
7
    any later version.
 
8
 
 
9
    This program is distributed in the hope that it will be useful,
 
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
    GNU General Public License for more details.
 
13
 ******************************************************************************
 
14
 */
 
15
 
 
16
/* This code is lifted from FAL. */
 
17
#include <sys/socket.h>
 
18
#include <sys/stat.h>
 
19
#include <sys/param.h>
 
20
#include <sys/mman.h>
 
21
#include <assert.h>
 
22
#include <unistd.h>
 
23
#include <fcntl.h>
 
24
#include <stdio.h>
 
25
#include <stdlib.h>
 
26
#include <errno.h>
 
27
#include <ctype.h>
 
28
#include <syslog.h>
 
29
#include <pwd.h>
 
30
#include <grp.h>
 
31
#include <glob.h>
 
32
#include <regex.h>
 
33
#include <string.h>
 
34
#include <netdnet/dn.h>
 
35
#include <netdnet/dnetdb.h>
 
36
#include "filenames.h"
 
37
 
 
38
#define true 1
 
39
#define false 0
 
40
 
 
41
const char *sysdisk_name = "SYS$SYSDEVICE";
 
42
 
 
43
// A couple of general utility methods:
 
44
static void makelower(char *s)
 
45
{
 
46
        unsigned int i;
 
47
        for (i=0; i<strlen(s); i++) s[i] = tolower(s[i]);
 
48
}
 
49
 
 
50
static void makeupper(char *s)
 
51
{
 
52
        unsigned int i;
 
53
        for (i=0; i<strlen(s); i++) s[i] = toupper(s[i]);
 
54
}
 
55
 
 
56
// Convert a Unix-style filename to a VMS-style name
 
57
// No return code because this routine cannot fail :-)
 
58
void make_vms_filespec(const char *unixname, char *vmsname, int isdir)
 
59
{
 
60
    char        fullname[PATH_MAX];
 
61
    int         i;
 
62
    char       *lastslash;
 
63
    struct stat st;
 
64
 
 
65
    // Take a copy wwe can muck about with
 
66
    strcpy(fullname, unixname);
 
67
 
 
68
    // Find the last slash in the name
 
69
    lastslash = fullname + strlen(fullname);
 
70
    while (*(--lastslash) != '/') ;
 
71
 
 
72
    // If the filename has no extension then add one. VMS seems to
 
73
    // expect one as does dapfs.
 
74
    if (!strchr(lastslash, '.' && !isdir))
 
75
        strcat(fullname, ".");
 
76
 
 
77
    int slashes = 0;
 
78
 
 
79
    // Oh, also make it all upper case for VMS's benefit.
 
80
    for (i=0; i<(int)strlen(fullname); i++)
 
81
    {
 
82
        if (islower(fullname[i])) fullname[i] = toupper(fullname[i]);
 
83
        if (fullname[i] == '/')
 
84
        {
 
85
            slashes++;
 
86
        }
 
87
    }
 
88
 
 
89
    if (slashes == 1)
 
90
    {
 
91
            sprintf(vmsname, "[]%s", unixname+1);
 
92
            return;
 
93
    }
 
94
 
 
95
    int thisslash = 0;
 
96
    int v=0;
 
97
    for (i=0; i<=(int)strlen(fullname); i++)
 
98
    {
 
99
            if (i==0)
 
100
            {
 
101
                    vmsname[v++] = '[';
 
102
                    vmsname[v++] = '.';
 
103
                    thisslash++;
 
104
            }
 
105
            else
 
106
            {
 
107
                    if (fullname[i] == '/')
 
108
                    {
 
109
                            thisslash++;
 
110
                            if (thisslash == slashes)
 
111
                                    vmsname[v++] = ']';
 
112
                            else
 
113
                                    vmsname[v++] = '.';
 
114
                    }
 
115
                    else
 
116
                            vmsname[v++] = fullname[i];
 
117
            }
 
118
    }
 
119
}
 
120
 
 
121
// Split out the volume, directory and file portions of a VMS file spec
 
122
// We assume that the VMS name is (quite) well formed.
 
123
static void parse_vms_filespec(char *volume, char *directory, char *file)
 
124
{
 
125
    char *colon = strchr(file, ':');
 
126
    char *ptr = file;
 
127
 
 
128
    volume[0] = '\0';
 
129
    directory[0] = '\0';
 
130
 
 
131
    if (colon) // We have a volume name
 
132
    {
 
133
        char saved = *(colon+1);
 
134
        *(colon+1) = '\0';
 
135
        strcpy(volume, file);
 
136
        ptr = colon+1;
 
137
        *ptr = saved;
 
138
    }
 
139
 
 
140
    char *enddir = strchr(ptr, ']');
 
141
 
 
142
    // Don't get caught out by concatenated filespecs
 
143
    // like dua0:[home.patrick.][test]
 
144
    if (enddir && enddir[1] == '[')
 
145
        enddir=strchr(enddir+1, ']');
 
146
 
 
147
    if (*ptr == '[' && enddir) // we have a directory
 
148
    {
 
149
        char saved = *(enddir+1);
 
150
 
 
151
        *(enddir+1) = '\0';
 
152
        strcpy(directory, ptr);
 
153
        ptr = enddir+1;
 
154
        *ptr = saved;
 
155
    }
 
156
 
 
157
    // Copy the rest of the filename using memmove 'cos it might overlap
 
158
    if (ptr != file)
 
159
        memmove(file, ptr, strlen(ptr)+1);
 
160
 
 
161
}
 
162
 
 
163
// Convert a VMS filespec into a Unix filespec
 
164
// volume names are turned into directories in the root directory
 
165
// (unless they are SYSDISK which is our pseudo name)
 
166
void make_unix_filespec(char *unixname, char *vmsname)
 
167
{
 
168
    char volume[PATH_MAX];
 
169
    char dir[PATH_MAX];
 
170
    char file[PATH_MAX];
 
171
    int  ptr;
 
172
    int  i;
 
173
 
 
174
    strcpy(file, vmsname);
 
175
 
 
176
    // Remove the trailing version number
 
177
    char *semi = strchr(file, ';');
 
178
    if (semi) *semi = '\0';
 
179
 
 
180
    // If the filename has a trailing dot them remove that too
 
181
    if (file[strlen(file)-1] == '.')
 
182
        file[strlen(file)-1] = '\0';
 
183
 
 
184
    unixname[0] = '\0';
 
185
 
 
186
    // Split it into its component parts
 
187
    parse_vms_filespec(volume, dir, file);
 
188
 
 
189
    // Remove the trailing colon from the volume name
 
190
    if (volume[strlen(volume)-1] == ':')
 
191
        volume[strlen(volume)-1] = '\0';
 
192
 
 
193
    // If the filename has the dummy SYSDISK volume then start from the
 
194
    // filesystem root
 
195
    if (strcasecmp(volume, sysdisk_name) == 0)
 
196
    {
 
197
        strcpy(unixname, "/");
 
198
    }
 
199
    else
 
200
    {
 
201
        if (volume[0] != '\0')
 
202
        {
 
203
            strcpy(unixname, "/");
 
204
            strcat(unixname, volume);
 
205
        }
 
206
    }
 
207
    ptr = strlen(unixname);
 
208
 
 
209
    // Copy the directory
 
210
    for (i=0; i< (int)strlen(dir); i++)
 
211
    {
 
212
        // If the directory name starts [. then it is relative to the
 
213
        // user's home directory and we lose the starting slash
 
214
        // If there is also a volume name present then it all falls
 
215
        // to bits but then it's pretty dodgy on VMS too.
 
216
        if (dir[i] == '[' &&
 
217
            dir[i+1] == '.')
 
218
        {
 
219
            i++;
 
220
            ptr = 0;
 
221
            continue;
 
222
        }
 
223
 
 
224
        if (dir[i] == '[' ||
 
225
            dir[i] == ']' ||
 
226
            dir[i] == '.')
 
227
        {
 
228
            unixname[ptr++] = '/';
 
229
        }
 
230
        else
 
231
        {
 
232
            // Skip root directory specs
 
233
            if (dir[i] == '0' && (strncmp(&dir[i], "000000", 6) == 0))
 
234
            {
 
235
                i += 5;
 
236
                continue;
 
237
            }
 
238
            if (dir[i] == '0' && (strncmp(&dir[i], "0,0", 3) == 0))
 
239
            {
 
240
                i += 2;
 
241
                continue;
 
242
            }
 
243
            unixname[ptr++] = dir[i];
 
244
        }
 
245
    }
 
246
    unixname[ptr++] = '\0'; // so that strcat will work properly
 
247
 
 
248
    // A special case (ugh!), if VMS sent us '*.*' (maybe as part of *.*;*)
 
249
    // then change it to just '*' so we get all the files.
 
250
    if (strcmp(file, "*.*") == 0) strcpy(file, "*");
 
251
 
 
252
    strcat(unixname, file);
 
253
 
 
254
    // Finally convert it all to lower case. This is not the greatest way to
 
255
    // cope with it but because VMS will upper-case everything anyway we
 
256
    // can't really distinguish case. I know samba does fancy stuff with
 
257
    // matching various combinations of case but I really can't be bothered.
 
258
    makelower(unixname);
 
259
 
 
260
    // If the name ends in .dir and there is a directory of that name without
 
261
    // the .dir then remove it (the .dir, not the directory!)
 
262
    if (strstr(unixname, ".dir") == unixname+strlen(unixname)-4)
 
263
    {
 
264
        char dirname[strlen(unixname)+1];
 
265
        struct stat st;
 
266
 
 
267
        strcpy(dirname, unixname);
 
268
        char *ext = strstr(dirname, ".dir");
 
269
        if (ext) *ext = '\0';
 
270
        if (stat(dirname, &st) == 0 &&
 
271
            S_ISDIR(st.st_mode))
 
272
        {
 
273
            char *ext = strstr(unixname, ".dir");
 
274
            if (ext) *ext = '\0';
 
275
        }
 
276
    }
 
277
}