Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libardir/ar-port.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 2002-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* *
20
***********************************************************************/
21
#pragma prototyped
22
/*
23
* portable archive format method
24
*/
25
26
#include <ardirlib.h>
27
#include <ctype.h>
28
#include <tm.h>
29
30
#define MAGIC "!<arch>\n"
31
#define MAGIC_SIZE 8
32
33
#define TERM_port '/'
34
#define FMAG_port_0 '`'
35
#define FMAG_port_1 '\n'
36
#define SYMDIR_port "(/[!/]|_______[0-9_][0-9_][0-9_]E[BL]E[BL]_)*"
37
#define SYMDIR_other "(._|_.|__.|___)*"
38
#define SYMDIR_age 5
39
40
#define TERM_rand ' '
41
#define SYMDIR_rand "(__.SYMDEF|__________E\?\?\?X)*"
42
#define SYMDIR_strict "__.SYMDEF SORTED*"
43
44
typedef struct Header_s
45
{
46
char ar_name[16];
47
char ar_date[12]; /* left-adj; decimal char*; blank fill */
48
char ar_uid[6]; /* " */
49
char ar_gid[6]; /* " */
50
char ar_mode[8]; /* left-adj; octal char*; blank fill */
51
char ar_size[10]; /* left-adj; decimal char*; blank fill */
52
char ar_fmag[2]; /* FMAG_port_[01] */
53
} Header_t;
54
55
typedef struct State_s /* method state */
56
{
57
off_t current; /* current dirent offset */
58
off_t offset; /* next dirent offset */
59
off_t patch; /* symdir time patch offset */
60
char* names; /* long name table */
61
char* name; /* local long name */
62
int size; /* local long name max size */
63
int touch; /* touch symbol table time */
64
int separator; /* alternate path separator */
65
Header_t header; /* current header */
66
char term[1]; /* trailing '\0' for header */
67
} State_t;
68
69
/*
70
* closef
71
*/
72
73
static int
74
portclose(Ardir_t* ar)
75
{
76
State_t* state;
77
int r;
78
char buf[sizeof(state->header.ar_date) + 1];
79
80
if (!ar || !(state = (State_t*)ar->data))
81
r = -1;
82
else
83
{
84
r = 0;
85
if (state->touch && state->patch >= 0)
86
{
87
if (lseek(ar->fd, state->patch, SEEK_SET) != state->patch)
88
r = -1;
89
else
90
{
91
sfsprintf(buf, sizeof(buf), "%-*lu", sizeof(buf) - 1, (unsigned long)time((time_t*)0) + 5);
92
if (write(ar->fd, buf, sizeof(buf) - 1) != (sizeof(buf) - 1))
93
r = -1;
94
}
95
}
96
if (state->names)
97
free(state->names);
98
if (state->name)
99
free(state->name);
100
free(state);
101
}
102
return r;
103
}
104
105
/*
106
* openf
107
*/
108
109
static int
110
portopen(Ardir_t* ar, char* buf, size_t n)
111
{
112
long size;
113
size_t i;
114
Header_t* hdr;
115
State_t* state;
116
char* name;
117
char* e;
118
119
if (n < (MAGIC_SIZE + sizeof(Header_t)))
120
return -1;
121
if (memcmp(buf, MAGIC, MAGIC_SIZE))
122
return -1;
123
124
/*
125
* check for a symbol directory
126
*/
127
128
hdr = (Header_t*)(buf + MAGIC_SIZE);
129
if (hdr->ar_fmag[0] != FMAG_port_0 || hdr->ar_fmag[1] != FMAG_port_1)
130
return -1;
131
#if __pdp11__ || pdp11
132
ar->error = ENOSYS;
133
return -1;
134
#else
135
if (!(state = newof(0, State_t, 1, 0)))
136
return -1;
137
ar->data = (void*)state;
138
state->offset = MAGIC_SIZE;
139
ar->truncate = 14;
140
name = hdr->ar_name;
141
if (name[0] == '#' && name[1] == '1' && name[2] == TERM_port)
142
{
143
i = strtol(name + 3, NiL, 10);
144
if (n < (MAGIC_SIZE + sizeof(Header_t) + i))
145
return -1;
146
name = (char*)(hdr + 1);
147
ar->truncate = 0;
148
}
149
if (strmatch(name, SYMDIR_port) || strmatch(name, SYMDIR_rand) && (ar->flags |= ARDIR_RANLIB))
150
{
151
if (sfsscanf(hdr->ar_size, "%ld", &size) != 1)
152
goto nope;
153
state->patch = MAGIC_SIZE + offsetof(Header_t, ar_date);
154
state->offset += sizeof(Header_t) + size + (size & 01);
155
if ((ar->flags & ARDIR_RANLIB) && (sfsscanf(hdr->ar_date, "%lu", &ar->symtime) != 1 || (unsigned long)ar->st.st_mtime > ar->symtime + (strmatch(name, SYMDIR_strict) ? 0 : SYMDIR_age)))
156
ar->symtime = 0;
157
if (!(ar->flags & ARDIR_RANLIB) && hdr->ar_uid[0] == ' ' && hdr->ar_gid[0] == ' ')
158
state->separator = '\\';
159
}
160
else
161
{
162
/*
163
* there is no symbol directory
164
*/
165
166
state->patch = -1;
167
hdr->ar_date[0] = 0;
168
if (strchr(name, TERM_port) && strmatch(name, SYMDIR_other))
169
ar->flags &= ~ARDIR_RANLIB;
170
else
171
ar->flags |= ARDIR_RANLIB;
172
}
173
if (lseek(ar->fd, state->offset, SEEK_SET) < 0)
174
goto nope;
175
hdr = &state->header;
176
while (read(ar->fd, (char*)hdr, sizeof(state->header)) == sizeof(state->header) && hdr->ar_name[0] == TERM_port)
177
{
178
if (sfsscanf(hdr->ar_size, "%ld", &size) != 1)
179
goto nope;
180
size += (size & 01);
181
if (!state->names && hdr->ar_name[1] == TERM_port && (hdr->ar_name[2] == ' ' || hdr->ar_name[2] == TERM_port && hdr->ar_name[3] == ' '))
182
{
183
/*
184
* long name string table
185
*/
186
187
if (!(state->names = newof(0, char, size, 0)) || read(ar->fd, state->names, size) != size)
188
goto nope;
189
ar->truncate = 0;
190
if (hdr->ar_name[1] == TERM_port)
191
for (e = (name = state->names) + size; name < e; name++)
192
if (*name == TERM_port && *(name + 1) == '\n')
193
*name = 0;
194
}
195
else if (isdigit(hdr->ar_name[1]))
196
break;
197
else if (lseek(ar->fd, (off_t)size, SEEK_CUR) < 0)
198
goto nope;
199
state->offset += sizeof(state->header) + size;
200
}
201
return 0;
202
#endif
203
nope:
204
portclose(ar);
205
return -1;
206
}
207
208
/*
209
* hpux 32 bit uid/gid workaround
210
*/
211
212
static int
213
ar_uid_gid(Ardir_t* ar, char* b, long* p)
214
{
215
int i;
216
long n;
217
218
if (b[5] != ' ')
219
{
220
n = 0;
221
for (i = 0; i < 5; i++)
222
{
223
n <<= 6;
224
n |= b[i] - ' ';
225
}
226
n <<= 2;
227
n |= b[i] - '@';
228
*p = n;
229
error(-1, "AHA ar_uid_gid '%s' => %lu\n", b, n);
230
}
231
else if (sfsscanf(b, "%ld", p) != 1)
232
{
233
ar->error = EINVAL;
234
return -1;
235
}
236
return 0;
237
}
238
239
/*
240
* nextf
241
*/
242
243
static Ardirent_t*
244
portnext(Ardir_t* ar)
245
{
246
State_t* state = (State_t*)ar->data;
247
long n;
248
ssize_t z;
249
char* s;
250
251
state->current = state->offset;
252
if (lseek(ar->fd, state->offset, SEEK_SET) != state->offset)
253
{
254
ar->error = errno;
255
return 0;
256
}
257
if (read(ar->fd, (char*)&state->header, sizeof(state->header)) != sizeof(state->header))
258
{
259
if ((z = read(ar->fd, (char*)&state->header, 1)) < 0)
260
ar->error = errno;
261
else if (z > 0)
262
ar->error = EINVAL;
263
return 0;
264
265
}
266
if (state->header.ar_fmag[0] != FMAG_port_0 || state->header.ar_fmag[1] != FMAG_port_1)
267
{
268
ar->error = EINVAL;
269
return 0;
270
}
271
if (sfsscanf(state->header.ar_date, "%ld", &n) != 1)
272
{
273
ar->error = EINVAL;
274
return 0;
275
}
276
ar->dirent.mtime = n;
277
ar->dirent.name = state->header.ar_name;
278
ar->dirent.name[sizeof(state->header.ar_name)] = 0;
279
if (state->names && (*ar->dirent.name == TERM_port || *ar->dirent.name == ' '))
280
ar->dirent.name = state->names + strtol(ar->dirent.name + 1, NiL, 10);
281
if (ar_uid_gid(ar, state->header.ar_uid, &n))
282
return 0;
283
ar->dirent.uid = n;
284
if (ar_uid_gid(ar, state->header.ar_gid, &n))
285
return 0;
286
ar->dirent.gid = n;
287
if (sfsscanf(state->header.ar_mode, "%lo", &n) != 1)
288
{
289
ar->error = EINVAL;
290
return 0;
291
}
292
ar->dirent.mode = n;
293
if (sfsscanf(state->header.ar_size, "%ld", &n) != 1)
294
{
295
ar->error = EINVAL;
296
return 0;
297
}
298
ar->dirent.offset = state->offset += sizeof(state->header);
299
ar->dirent.size = n;
300
state->offset += n + (n & 01);
301
if (ar->dirent.name[0] == '#' && ar->dirent.name[1] == '1' && ar->dirent.name[2] == TERM_port)
302
{
303
n = strtol(ar->dirent.name + 3, NiL, 10);
304
ar->dirent.size -= n;
305
if ((n + 1) >= state->size)
306
{
307
state->size = roundof(n + 1, 128);
308
if (!(state->name = newof(state->name, char, state->size, 0)))
309
{
310
ar->error = ENOMEM;
311
return 0;
312
}
313
}
314
if ((z = read(ar->fd, state->name, n)) < 0)
315
{
316
ar->error = errno;
317
return 0;
318
}
319
else if (z != n)
320
{
321
ar->error = EINVAL;
322
return 0;
323
}
324
state->name[n] = 0;
325
ar->dirent.name = state->name;
326
}
327
else
328
{
329
for (s = ar->dirent.name + strlen(ar->dirent.name); s > ar->dirent.name && (*(s - 1) == TERM_port || *(s - 1) == TERM_rand); s--);
330
*s = 0;
331
}
332
if (state->separator)
333
for (s = ar->dirent.name; s = strchr(s, state->separator); *s++ = '/');
334
return &ar->dirent;
335
}
336
337
/*
338
* changef
339
*/
340
341
static int
342
portchange(Ardir_t* ar, Ardirent_t* ent)
343
{
344
State_t* state = (State_t*)ar->data;
345
off_t o;
346
char buf[sizeof(state->header.ar_date) + 1];
347
348
o = state->current + offsetof(Header_t, ar_date);
349
if (lseek(ar->fd, o, SEEK_SET) != o)
350
{
351
ar->error = errno;
352
return -1;
353
}
354
sfsprintf(buf, sizeof(buf), "%-*lu", sizeof(buf) - 1, (unsigned long)ent->mtime);
355
if (write(ar->fd, buf, sizeof(buf) - 1) != (sizeof(buf) - 1))
356
{
357
ar->error = errno;
358
return -1;
359
}
360
state->touch = 1;
361
return 0;
362
}
363
364
Ardirmeth_t ar_port =
365
{
366
"portable",
367
"portable archive",
368
portopen,
369
portnext,
370
portchange,
371
0,
372
0,
373
portclose,
374
ar_port_next
375
};
376
377