~ubuntu-branches/ubuntu/hardy/silo/hardy-updates

« back to all changes in this revision

Viewing changes to second/fs/isofs.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio M. Di Nitto
  • Date: 2007-10-25 09:28:08 UTC
  • mfrom: (15.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20071025092808-1yhj12t7s4zqsfu5
Tags: 1.4.13a+git20070930-1ubuntu1
* Merge from debian unstable, remaining changes:
  - Build with -fno-stack-protector.
  - Change silo.postinst to automatically update the boot block without
    invoking siloconfig and keep asking questions on upgrades.
  - Convert silo.conf to use /dev/disk/by-uuid.
  - Ubuntu maintainer foobar.
  - Fix debian/rules call to dh_installdocs.
  - Drop the requirement of gcc-4.1 and start using default gcc.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ISO9660 (CDROM) Interface for SILO filesystem access routines
 
2
   
 
3
   Copyright (C) 1999 Jakub Jelinek
 
4
                 1992,1993 Eric Youngdale
 
5
                 2001 Ben Collins
 
6
   
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 2 of the License, or
 
10
   (at your option) any later version.
 
11
   
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
 
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program; if not, write to the Free Software
 
19
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
 
20
   USA.  */
 
21
 
 
22
#include <ctype.h>
 
23
#include <sys/types.h>
 
24
#include <errno.h>
 
25
#include <linux/iso_fs.h>
 
26
#include <silo.h>
 
27
#include <file.h>
 
28
#include <stringops.h>
 
29
#include <rock.h>
 
30
 
 
31
/* Reuse and abuse */
 
32
typedef ext2_filsys isofs_filsys;
 
33
 
 
34
struct isofs_inode {
 
35
        unsigned int extent;
 
36
        unsigned int size;
 
37
};
 
38
 
 
39
 
 
40
static struct isofs_inode inode, root_inode;
 
41
static int link_count = 0;
 
42
 
 
43
void *alloca(size_t);
 
44
static int isofs_lookup (isofs_filsys, struct isofs_inode *,
 
45
                         const char *, int, struct isofs_inode *);
 
46
static int open_namei(isofs_filsys, const char *, struct isofs_inode *,
 
47
                      struct isofs_inode *);
 
48
 
 
49
static int ino_size_isofs (void)
 
50
{
 
51
    return inode.size;
 
52
}
 
53
 
 
54
static int ls_isofs (void)
 
55
{
 
56
    link_count = 0;
 
57
    return isofs_lookup (fs, &inode, "", 0, NULL);
 
58
}
 
59
 
 
60
static int isonum_731 (char * p)
 
61
{
 
62
        return ((p[0] & 0xff)
 
63
                | ((p[1] & 0xff) << 8)
 
64
                | ((p[2] & 0xff) << 16)
 
65
                | ((p[3] & 0xff) << 24));
 
66
}
 
67
 
 
68
#define isonum_733(p) isonum_731(p)
 
69
 
 
70
static int isofs_read_super(io_channel io)
 
71
{
 
72
    int i;
 
73
    struct iso_primary_descriptor iso;
 
74
    
 
75
    for (i = 16; i < 100; i++) {
 
76
        if (io_channel_read_blk (io, i, -2048, (char *)&iso))
 
77
            return -1;
 
78
        if (!strncmp (iso.id, ISO_STANDARD_ID, sizeof (iso.id)))
 
79
            break;
 
80
    }
 
81
    
 
82
    if (i == 100)
 
83
            return -1;
 
84
 
 
85
    root_inode.extent = isonum_733 (((struct iso_directory_record *)
 
86
                            (iso.root_directory_record))->extent);
 
87
    root_inode.size = isonum_733 (((struct iso_directory_record *)
 
88
                            (iso.root_directory_record))->size);
 
89
 
 
90
    return 0;
 
91
}
 
92
 
 
93
static int open_isofs (char *device)
 
94
{
 
95
    fs = (isofs_filsys) malloc (sizeof (struct struct_ext2_filsys));
 
96
    if (!fs)
 
97
        return 0;
 
98
 
 
99
    if (((struct struct_io_manager *)(silo_io_manager))->open (device, 0, &fs->io))
 
100
        return 0;
 
101
 
 
102
    io_channel_set_blksize (fs->io, 2048);
 
103
 
 
104
    if (isofs_read_super(fs->io))
 
105
        return 0;
 
106
 
 
107
    return 1;
 
108
}
 
109
 
 
110
static int iso_date(char * p, int flag)
 
111
{
 
112
    int year, month, day, hour, minute, second, tz;
 
113
    int crtime, days, i;
 
114
 
 
115
    year = p[0] - 70;
 
116
    month = p[1];
 
117
    day = p[2];
 
118
    hour = p[3];
 
119
    minute = p[4];
 
120
    second = p[5];
 
121
    if (flag == 0) tz = p[6]; /* High sierra has no time zone */
 
122
    else tz = 0;
 
123
 
 
124
    if (year < 0) {
 
125
        crtime = 0;
 
126
    } else {
 
127
        int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
 
128
 
 
129
        days = year * 365;
 
130
        if (year > 2)
 
131
            days += (year+1) / 4;
 
132
        for (i = 1; i < month; i++)
 
133
            days += monlen[i-1];
 
134
        if (((year+2) % 4) == 0 && month > 2)
 
135
            days++;
 
136
        days += day - 1;
 
137
        crtime = ((((days * 24) + hour) * 60 + minute) * 60)
 
138
            + second;
 
139
 
 
140
        /* sign extend */
 
141
        if (tz & 0x80)
 
142
            tz |= (-1 << 8);
 
143
 
 
144
        if (-52 <= tz && tz <= 52)
 
145
            crtime -= tz * 15 * 60;
 
146
    }
 
147
    return crtime;
 
148
}
 
149
 
 
150
 
 
151
static void parse_rr (isofs_filsys fs, unsigned char *chr, unsigned char *end,
 
152
                      char *name, char *symlink, struct silo_inode *sino)
 
153
{
 
154
    int cont_extent = 0, cont_offset = 0, cont_size = 0;
 
155
    struct rock_ridge *rr;
 
156
    int cnt, sig;
 
157
    int truncate = 0;
 
158
    int symlink_len = 0;
 
159
    int rootflag;
 
160
 
 
161
    *name = 0;
 
162
 
 
163
    while (chr < end) {
 
164
        rr = (struct rock_ridge *) chr;
 
165
        if (rr->len == 0) goto out;
 
166
        sig = (chr[0] << 8) + chr[1];
 
167
        chr += rr->len;
 
168
 
 
169
        switch(sig){
 
170
            case SIG('R','R'):
 
171
                if((rr->u.RR.flags[0] &
 
172
                    (RR_PX | RR_TF | RR_SL | RR_CL | RR_NM | RR_PX | RR_TF)) == 0)
 
173
                    goto out;
 
174
                break;
 
175
            case SIG('N','M'):
 
176
                if (truncate) break;
 
177
                if (rr->u.NM.flags & 6) break;
 
178
                if (rr->u.NM.flags & ~1) {
 
179
                    printf ("Unsupported NM flag settings (%d)\n",rr->u.NM.flags);
 
180
                    break;
 
181
                }
 
182
                if((strlen(name) + rr->len - 5) >= 254) {
 
183
                    truncate = 1;
 
184
                    break;
 
185
                }
 
186
                strncat(name, rr->u.NM.name, rr->len - 5);
 
187
                break;
 
188
            case SIG('S','L'):
 
189
                {
 
190
                    int slen;
 
191
                    struct SL_component * slp;
 
192
                    struct SL_component * oldslp;
 
193
                    slen = rr->len - 5;
 
194
                    slp = &rr->u.SL.link;
 
195
                    sino->size = symlink_len;
 
196
 
 
197
                    while (slen > 1) {
 
198
                        rootflag = 0;
 
199
                        switch(slp->flags &~1) {
 
200
                            case 0:
 
201
                                sino->size += slp->len;
 
202
                                strncat (symlink, slp->text, slp->len);
 
203
                                break;
 
204
                            case 2:
 
205
                                sino->size += 1;
 
206
                                strcat (symlink, ".");
 
207
                                break;
 
208
                            case 4:
 
209
                                sino->size += 2;
 
210
                                strcat (symlink, "..");
 
211
                                break;
 
212
                            case 8:
 
213
                                rootflag = 1;
 
214
                                sino->size += 1;
 
215
                                strcat (symlink, "/");
 
216
                                break;
 
217
                            default:
 
218
                                printf("Symlink component flag not implemented\n");
 
219
                        }
 
220
                        slen -= slp->len + 2;
 
221
                        oldslp = slp;
 
222
                        slp = (struct SL_component *) (((char *) slp) + slp->len + 2);
 
223
 
 
224
                        if (slen < 2) {
 
225
                            if(((rr->u.SL.flags & 1) != 0)
 
226
                                    && ((oldslp->flags & 1) == 0) ) sino->size += 1;
 
227
                            break;
 
228
                        }
 
229
 
 
230
                        /*
 
231
                         * If this component record isn't continued, then append a '/'.
 
232
                         */
 
233
                        if (!rootflag && (oldslp->flags & 1) == 0) {
 
234
                            strcat (symlink, "/");
 
235
                            sino->size += 1;
 
236
                        }
 
237
 
 
238
                    }
 
239
                }
 
240
                symlink_len = sino->size;
 
241
                break;
 
242
            case SIG('C','E'):
 
243
                CHECK_CE;
 
244
                break;
 
245
            case SIG('P','X'):
 
246
                sino->mode = isonum_733(rr->u.PX.mode);
 
247
                sino->uid  = isonum_733(rr->u.PX.uid);
 
248
                sino->gid  = isonum_733(rr->u.PX.gid);
 
249
                break;
 
250
            case SIG('T','F'):
 
251
                cnt = 0;
 
252
                if(rr->u.TF.flags & TF_CREATE)
 
253
                    cnt++;
 
254
                if(rr->u.TF.flags & TF_MODIFY)
 
255
                    sino->mtime = iso_date(rr->u.TF.times[cnt++].time, 0);
 
256
                break;
 
257
        }
 
258
        if (chr >= end && cont_extent) {
 
259
            char *sect = alloca (2048);
 
260
            if (io_channel_read_blk (fs->io, cont_extent, 1, sect))
 
261
                return;
 
262
            parse_rr (fs, (unsigned char *)(&sect[cont_offset]),
 
263
                      (unsigned char *)(&sect[cont_offset + cont_size - 3]),
 
264
                      name, symlink, sino);
 
265
        }
 
266
    }
 
267
out:
 
268
    return;
 
269
}
 
270
 
 
271
static int isofs_lookup (isofs_filsys fs, struct isofs_inode *dir,
 
272
                       const char *name, int len, struct isofs_inode *result)
 
273
{
 
274
    char buffer [2048];
 
275
    char namebuf [512];
 
276
    char symlink [512];
 
277
    int block, size, i;
 
278
    struct iso_directory_record *idr;
 
279
    unsigned char *rr;
 
280
    struct silo_inode sino;
 
281
 
 
282
    size = dir->size;
 
283
    block = dir->extent;
 
284
 
 
285
    while (size > 0) {
 
286
        if (io_channel_read_blk (fs->io, block, 1, buffer)) {
 
287
            printf ("Could not read directory\n");
 
288
            return -1;
 
289
        }
 
290
 
 
291
        size -= 2048;
 
292
        block++;
 
293
 
 
294
        for (i = 0;;) {
 
295
            idr = (struct iso_directory_record *) (buffer + i);
 
296
            if (!idr->length[0])
 
297
                break;
 
298
 
 
299
            i += (unsigned char)idr->length[0];
 
300
            strncpy(namebuf, idr->name, (unsigned char)idr->name_len[0]);
 
301
            namebuf[(unsigned char)idr->name_len[0]] = 0;
 
302
 
 
303
            rr = (unsigned char *)(idr + 1);
 
304
            rr += ((unsigned char)idr->name_len[0]) - sizeof(idr->name);
 
305
 
 
306
            if (!(idr->name_len[0] & 1))
 
307
                rr++;
 
308
 
 
309
            *symlink = 0;
 
310
            memset(&sino, 0, sizeof(struct silo_inode));
 
311
            parse_rr (fs, rr, (unsigned char *)(&buffer[i-3]), namebuf, symlink, &sino);
 
312
 
 
313
            if (idr->name_len[0] == 1 && !idr->name[0])
 
314
                strcpy(namebuf, ".");
 
315
            else if (idr->name_len[0] == 1 && idr->name[0] == 1)
 
316
                strcpy(namebuf, "..");
 
317
 
 
318
            if (result == NULL) {
 
319
                /* We aren't returning a result inode, so we must be
 
320
                 * iterating...  */
 
321
                register_silo_inode(sino.mtime, sino.size?:isonum_733(idr->size),
 
322
                                    sino.mode, sino.uid, sino.gid, namebuf,
 
323
                                    *symlink ? symlink : NULL);
 
324
            } else if ((!len && namebuf[0] == '.' && !namebuf[1]) || 
 
325
                (strlen(namebuf) == len && !memcmp(namebuf, name, len))) {
 
326
                if (*symlink) {
 
327
                    int error;
 
328
                    if (link_count > 5) {
 
329
                        printf ("Symlink loop, stopping.\n");
 
330
                        return -1; /* Loop */
 
331
                    }
 
332
                    link_count++;
 
333
                    error = open_namei (fs, symlink, result, dir);
 
334
                    link_count--;
 
335
                    return error;
 
336
                }
 
337
                result->extent = isonum_733 (idr->extent);
 
338
                result->size = isonum_733 (idr->size);
 
339
                return 0;
 
340
            }
 
341
 
 
342
            if (i >= 2048 - sizeof(struct iso_directory_record) + sizeof(idr->name))
 
343
                break;
 
344
        }
 
345
    }
 
346
    if (result == NULL)
 
347
        return 0;
 
348
    else
 
349
        return -1;
 
350
}
 
351
 
 
352
static int dir_namei(isofs_filsys fs, const char *pathname, int *namelen, 
 
353
                     const char **name, struct isofs_inode *base,
 
354
                     struct isofs_inode *res_inode)
 
355
{
 
356
    char c;
 
357
    const char *thisname;
 
358
    int len;
 
359
    struct isofs_inode inode;
 
360
 
 
361
    if ((c = *pathname) == '/') {
 
362
        base = &root_inode;
 
363
        pathname++;
 
364
    }
 
365
    while (1) {
 
366
        thisname = pathname;
 
367
        for(len=0;(c = *(pathname++))&&(c != '/');len++);
 
368
        if (!c) break;
 
369
        if (isofs_lookup (fs, base, thisname, len, &inode)) return -1;
 
370
        base = &inode;
 
371
    }
 
372
    *name = thisname;
 
373
    *namelen = len;
 
374
    *res_inode = *base;
 
375
    return 0;
 
376
}
 
377
 
 
378
static int open_namei(isofs_filsys fs, const char *pathname, 
 
379
                      struct isofs_inode *res_inode,
 
380
                      struct isofs_inode *base)
 
381
{
 
382
    const char *basename;
 
383
    int namelen;
 
384
    struct isofs_inode dir, inode;
 
385
 
 
386
    if (dir_namei(fs, pathname, &namelen, &basename, base, &dir)) return -1;
 
387
    if (!namelen) {                     /* special case: '/usr/' etc */
 
388
        *res_inode=dir;
 
389
        return 0;
 
390
    }
 
391
    if (isofs_lookup (fs, &dir, basename, namelen, &inode)) return -1;
 
392
    *res_inode = inode;
 
393
    return 0;
 
394
}
 
395
 
 
396
struct fs_ops iso_fs_ops;
 
397
 
 
398
static int isofs_namei (const char *filename)
 
399
{
 
400
    int ret;
 
401
    link_count = 0;
 
402
 
 
403
    ret = open_namei (fs, filename, &inode, &root_inode);
 
404
    iso_fs_ops.have_inode = (ret) ? 0 : 1;
 
405
 
 
406
    return ret;
 
407
}
 
408
 
 
409
static void isofs_close(void)
 
410
{
 
411
    free (fs->io);
 
412
    free (fs);
 
413
}
 
414
 
 
415
static int isofs_block_iterate(void)
 
416
{
 
417
    int i;
 
418
    blk_t nr;
 
419
    int size;
 
420
 
 
421
    nr = inode.extent;
 
422
    size = (inode.size + 2047) / 2048;
 
423
    for (i = 0; i < size; i++, nr++) {
 
424
        switch (dump_block (&nr, i)) {
 
425
            case BLOCK_ABORT:
 
426
            case BLOCK_ERROR:
 
427
                return 0;
 
428
        }
 
429
    }
 
430
    return dump_finish();
 
431
}
 
432
 
 
433
static void print_error_isofs (int error_val) {
 
434
    printf("Unknown isofs error");
 
435
}
 
436
 
 
437
struct fs_ops iso_fs_ops = {
 
438
    name:               "ISO-9660 CDROM",
 
439
    open:               open_isofs,
 
440
    ls:                 ls_isofs,
 
441
    dump:               isofs_block_iterate,
 
442
    close:              isofs_close,
 
443
    ino_size:           ino_size_isofs,
 
444
    print_error:        print_error_isofs,
 
445
    namei_follow:       isofs_namei,
 
446
    have_inode:         0,
 
447
};