Bug Summary

File:obj-scan-build/isofs/../../isofs/inode.c
Location:line 314, column 7
Description:Access to field 'valid' results in a dereference of a null pointer (loaded from variable 'rr')

Annotated Source Code

1/*
2 Copyright (C) 1997, 1998, 2002, 2007 Free Software Foundation, Inc.
3 Written by Thomas Bushnell, n/BSG.
4
5 This file is part of the GNU Hurd.
6
7 The GNU Hurd is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
11
12 The GNU Hurd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 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, USA. */
20
21#include <string.h>
22#include <stdio.h>
23#include <time.h>
24#include "isofs.h"
25
26
27/* There is no such thing as an inode in this format, all such
28 information being recorded in the directory entry. So we report
29 inode numbers as absolute offsets from DISK_IMAGE. We use the directory
30 record for symlinks and zero length files, and file_start otherwise.
31 Only for hard links to zero length files we get extra inodes. */
32
33#define INOHSZ512 512
34#if ((INOHSZ512&(INOHSZ512-1)) == 0)
35#define INOHASH(ino)((ino>>8)&(512 -1)) ((ino>>8)&(INOHSZ512-1))
36#else
37#define INOHASH(ino)((ino>>8)&(512 -1)) (((unsigned)(ino>>8))%INOHSZ512)
38#endif
39
40struct node_cache
41{
42 struct dirrect *dr; /* somewhere in disk_image */
43 off_t file_start; /* start of file */
44
45 off_t id; /* UNIQUE identifier. */
46
47 struct node *np; /* if live */
48};
49
50static int node_cache_size = 0;
51static int node_cache_alloced = 0;
52struct node_cache *node_cache = 0;
53
54/* Forward */
55static error_t read_disknode (struct node *,
56 struct dirrect *, struct rrip_lookup *);
57
58
59/* See if node with identifier ID is in the cache. If so, return it,
60 with one additional reference. diskfs_node_refcnt_lock must be held
61 on entry to the call, and will be released iff the node was found
62 in the cache. */
63void
64inode_cache_find (off_t id, struct node **npp)
65{
66 int i;
67
68 for (i = 0; i < node_cache_size; i++)
69 if (node_cache[i].id == id
70 && node_cache[i].np)
71 {
72 *npp = node_cache[i].np;
73 (*npp)->references++;
74 pthread_spin_unlock (&diskfs_node_refcnt_lock);
75 pthread_mutex_lock (&(*npp)->lock);
76 return;
77 }
78 *npp = 0;
79}
80
81
82/* Determine if we use file_start or struct dirrect * as node id. */
83int
84use_file_start_id (struct dirrect *record, struct rrip_lookup *rr)
85{
86 /* If it is a symlink or a zero length file, don't use file_start. */
87 if (rr->valid & VALID_SL0x0004 || isonum_733 (record->size) == 0)
88 return 0;
89
90 return 1;
91}
92
93/* Enter NP into the cache. The directory entry we used is DR, the
94 cached Rock-Ridge info RR. diskfs_node_refcnt_lock must be held. */
95void
96cache_inode (struct node *np, struct dirrect *record,
97 struct rrip_lookup *rr)
98{
99 int i;
100 struct node_cache *c = 0;
101 off_t id;
102
103 if (use_file_start_id (record, rr))
104 id = np->dn->file_start << store->log2_block_size;
105 else
106 id = (off_t) ((void *) record - (void *) disk_image);
107
108 /* First see if there's already an entry. */
109 for (i = 0; i < node_cache_size; i++)
110 if (node_cache[i].id == id)
111 break;
112
113 if (i == node_cache_size)
114 {
115 if (node_cache_size >= node_cache_alloced)
116 {
117 if (!node_cache_alloced)
118 {
119 /* Initialize */
120 node_cache_alloced = 10;
121 node_cache = malloc (sizeof (struct node_cache) * 10);
122 }
123 else
124 {
125 node_cache_alloced *= 2;
126 node_cache = realloc (node_cache,
127 sizeof (struct node_cache)
128 * node_cache_alloced);
129 }
130 assert (node_cache)((node_cache) ? (void) (0) : __assert_fail ("node_cache", "../../isofs/inode.c"
, 130, __PRETTY_FUNCTION__))
;
131 }
132 node_cache_size++;
133 }
134
135 c = &node_cache[i];
136 c->id = id;
137 c->dr = record;
138 c->file_start = np->dn->file_start;
139 c->np = np;
140
141 /* PLUS 1 so that we don't store zero cache ID's (not allowed by diskfs) */
142 np->cache_id = i + 1;
143}
144
145/* Fetch inode with cache id ID; set *NPP to the node structure;
146 gain one user reference and lock the node. */
147error_t
148diskfs_cached_lookup (ino_t id, struct node **npp)
149{
150 struct node *np;
151 error_t err;
152
153 /* Cache ID's are incremented when presented to diskfs
154 to avoid presenting zero cache ID's. */
155 id--;
156
157 pthread_spin_lock (&diskfs_node_refcnt_lock);
158 assert (id < node_cache_size)((id < node_cache_size) ? (void) (0) : __assert_fail ("id < node_cache_size"
, "../../isofs/inode.c", 158, __PRETTY_FUNCTION__))
;
159
160 np = node_cache[id].np;
161
162 if (!np)
163 {
164 struct node_cache *c = &node_cache[id];
165 struct rrip_lookup rr;
166 struct disknode *dn;
167
168 rrip_lookup (node_cache[id].dr, &rr, 1);
169
170 /* We should never cache the wrong directory entry */
171 assert (!(rr.valid & VALID_CL))((!(rr.valid & 0x0010)) ? (void) (0) : __assert_fail ("!(rr.valid & 0x0010)"
, "../../isofs/inode.c", 171, __PRETTY_FUNCTION__))
;
172
173 dn = malloc (sizeof (struct disknode));
174 if (!dn)
175 {
176 pthread_spin_unlock (&diskfs_node_refcnt_lock);
177 release_rrip (&rr);
178 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
179 }
180 dn->fileinfo = 0;
181 dn->dr = c->dr;
182 dn->file_start = c->file_start;
183 np = diskfs_make_node (dn);
184 if (!np)
185 {
186 free (dn);
187 pthread_spin_unlock (&diskfs_node_refcnt_lock);
188 release_rrip (&rr);
189 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
190 }
191 np->cache_id = id + 1; /* see above for rationale for increment */
192 pthread_mutex_lock (&np->lock);
193 c->np = np;
194 pthread_spin_unlock (&diskfs_node_refcnt_lock);
195
196 err = read_disknode (np, node_cache[id].dr, &rr);
197 if (!err)
198 *npp = np;
199
200 release_rrip (&rr);
201
202 return err;
203 }
204
205
206 np->references++;
207 pthread_spin_unlock (&diskfs_node_refcnt_lock);
208 pthread_mutex_lock (&np->lock);
209 *npp = np;
210 return 0;
211}
212
213
214/* Return Epoch-based time from a seven byte according to 9.1.5 */
215char *
216isodate_915 (char *c, struct timespec *ts)
217{
218 struct tm tm;
219 signed char tz;
220
221 /* Copy into a struct TM. */
222 tm.tm_year = *c++;
223 tm.tm_mon = *c++ - 1;
224 tm.tm_mday = *c++;
225 tm.tm_hour = *c++;
226 tm.tm_min = *c++;
227 tm.tm_sec = *c++;
228 tz = *c++;
229
230 tm.tm_isdst = 0;
231 ts->tv_sec = timegm (&tm);
232 ts->tv_nsec = 0;
233
234 /* Only honor TZ offset if it makes sense */
235 if (-48 <= tz && tz <= 52)
236 ts->tv_sec -= 15 * 60 * tz; /* TZ is in fifteen minute chunks */
237
238 return c;
239}
240
241/* Return Epoch-based time from a seventeen byte according to 8.4.26.1 */
242char *
243isodate_84261 (char *c, struct timespec *ts)
244{
245 struct tm tm;
246 int hsec;
247 signed char tz;
248
249 sscanf (c, "%4d%2d%2d%2d%2d%2d%2d",
250 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
251 &tm.tm_hour, &tm.tm_min, &tm.tm_sec,
252 &hsec);
253
254 /* Convert to appropriate units */
255 ts->tv_nsec = hsec * 10000000;
256 tm.tm_year -= 1900;
257 tm.tm_mon--;
258
259 tm.tm_isdst = 0;
260 ts->tv_sec = timegm (&tm);
261
262 tz = c[16];
263
264 /* Only honor TZ offset if it makes sense */
265 if (-48 <= tz && tz <= 52)
266 ts->tv_sec -= 15 * 60 * tz; /* TZ is in fifteen minute chunks */
267
268 return c + 17;
269}
270
271/* Calculate the file start (in store blocks) of the file at RECORD. */
272error_t
273calculate_file_start (struct dirrect *record, off_t *file_start,
274 struct rrip_lookup *rr)
275{
276 error_t err;
277
278 if (rr && (rr->valid & VALID_CL0x0010))
2
Assuming pointer value is null
279 {
280 *file_start = (void *) rr->realdirent - (void *)disk_image;
281 *file_start >>= store->log2_block_size;
282 }
283 else if (rr && (rr->valid & VALID_PL0x0020))
284 *file_start = rr->realfilestart;
285 else
286 {
287 err = diskfs_catch_exception ()({ struct disk_image_user *diu = __builtin_alloca (sizeof *diu
); error_t err; diu->next = diskfs_exception_diu; err = _setjmp
(diu->env); if (err == 0) diskfs_exception_diu = diu; err
; })
;
288 if (err)
3
Taking false branch
289 return err;
290
291 *file_start = ((isonum_733 (record->extent) + record->ext_attr_len)
292 * (logical_block_size / store->block_size));
293
294 diskfs_end_catch_exception ()({ struct disk_image_user *diu = diskfs_exception_diu; diskfs_exception_diu
= diu->next; })
;
295 }
296 return 0;
297}
298
299
300/* Load the inode with directory entry RECORD and cached Rock-Ridge
301 info RR into NP. The directory entry is at OFFSET in BLOCK. */
302error_t
303load_inode (struct node **npp, struct dirrect *record,
304 struct rrip_lookup *rr)
305{
306 error_t err;
307 off_t file_start;
308 struct disknode *dn;
309 struct node *np;
310
311 err = calculate_file_start (record, &file_start, rr);
1
Calling 'calculate_file_start'
4
Returning from 'calculate_file_start'
312 if (err)
5
Taking false branch
313 return err;
314 if (rr->valid & VALID_CL0x0010)
6
Access to field 'valid' results in a dereference of a null pointer (loaded from variable 'rr')
315 record = rr->realdirent;
316
317 pthread_spin_lock (&diskfs_node_refcnt_lock);
318
319 /* First check the cache */
320 if (use_file_start_id (record, rr))
321 inode_cache_find (file_start << store->log2_block_size, npp);
322 else
323 inode_cache_find ((off_t) ((void *) record - (void *) disk_image), npp);
324
325 if (*npp)
326 {
327 pthread_spin_unlock (&diskfs_node_refcnt_lock);
328 return 0;
329 }
330
331 /* Create a new node */
332 dn = malloc (sizeof (struct disknode));
333 if (!dn)
334 {
335 pthread_spin_unlock (&diskfs_node_refcnt_lock);
336 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
337 }
338 dn->fileinfo = 0;
339 dn->dr = record;
340 dn->file_start = file_start;
341
342 np = diskfs_make_node (dn);
343 if (!np)
344 {
345 free (dn);
346 pthread_spin_unlock (&diskfs_node_refcnt_lock);
347 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
348 }
349
350 pthread_mutex_lock (&np->lock);
351
352 cache_inode (np, record, rr);
353 pthread_spin_unlock (&diskfs_node_refcnt_lock);
354
355 err = read_disknode (np, record, rr);
356 *npp = np;
357 return err;
358}
359
360
361/* Read stat information from the directory entry at DR and the
362 contents of RL. */
363static error_t
364read_disknode (struct node *np, struct dirrect *dr,
365 struct rrip_lookup *rl)
366{
367 error_t err;
368 struct stat *st = &np->dn_stat;
369 st->st_fstype = FSTYPE_ISO96600x0000001a;
370 st->st_fsid = getpid ();
371 if (use_file_start_id (dr, rl))
372 st->st_ino = (ino_t) np->dn->file_start << store->log2_block_size;
373 else
374 st->st_ino = (ino_t) ((void *) dr - (void *) disk_image);
375 st->st_gen = 0;
376 st->st_rdev = 0;
377
378 err = diskfs_catch_exception ()({ struct disk_image_user *diu = __builtin_alloca (sizeof *diu
); error_t err; diu->next = diskfs_exception_diu; err = _setjmp
(diu->env); if (err == 0) diskfs_exception_diu = diu; err
; })
;
379 if (err)
380 return err;
381
382 if (rl->valid & VALID_PX0x0001)
383 {
384 if ((rl->valid & VALID_MD0x0400) == 0)
385 st->st_mode = rl->mode;
386 st->st_nlink = rl->nlink;
387 st->st_uid = rl->uid;
388 st->st_gid = rl->gid;
389 }
390 else
391 {
392 if ((rl->valid & VALID_MD0x0400) == 0)
393 {
394 /* If there are no periods, it's a directory. */
395 if (((rl->valid & VALID_NM0x0008) && !index (rl->name, '.'))
396 || (!(rl->valid & VALID_NM0x0008) && !memchr (dr->name, '.',
397 dr->namelen)))
398 st->st_mode = S_IFDIR0040000 | 0777;
399 else
400 st->st_mode = S_IFREG0100000 | 0666;
401 }
402 st->st_nlink = 1;
403 st->st_uid = 0;
404 st->st_gid = 0;
405 }
406
407 if (rl->valid & VALID_MD0x0400)
408 st->st_mode = rl->allmode;
409
410 if (rl->valid & VALID_AU0x0100)
411 st->st_author = rl->author;
412 else
413 st->st_author = st->st_gid;
414
415 st->st_size = isonum_733 (dr->size);
416
417 if ((rl->valid & VALID_PN0x0002)
418 && (S_ISCHR (st->st_mode)((((st->st_mode)) & 0170000) == (0020000)) || S_ISBLK (st->st_mode)((((st->st_mode)) & 0170000) == (0060000))))
419 st->st_rdev = rl->rdev;
420 else
421 st->st_rdev = 0;
422
423 if (dr->ileave)
424 /* XXX ??? */
425 st->st_size = 0;
426
427 /* Calculate these if we'll need them */
428 if (!(rl->valid & VALID_TF0x0040)
429 || ((rl->tfflags & (TF_CREATION0x01|TF_ACCESS0x04|TF_MODIFY0x02))
430 != (TF_CREATION0x01|TF_ACCESS0x04|TF_MODIFY0x02)))
431 {
432 struct timespec ts;
433 isodate_915 ((char *) dr->date, &ts);
434 st->st_ctim = st->st_mtim = st->st_atim = ts;
435 }
436
437 /* Override what we have better info for */
438 if (rl->valid & VALID_TF0x0040)
439 {
440 if (rl->tfflags & TF_CREATION0x01)
441 st->st_ctim = rl->ctime;
442
443 if (rl->tfflags & TF_ACCESS0x04)
444 st->st_atim = rl->atime;
445
446 if (rl->tfflags & TF_MODIFY0x02)
447 st->st_mtim = rl->mtime;
448 }
449
450 st->st_blksize = logical_block_size;
451 st->st_blocks = (st->st_size - 1) / 512 + 1;
452
453 if (rl->valid & VALID_FL0x0800)
454 st->st_flags = rl->flags;
455 else
456 st->st_flags = 0;
457
458 if (S_ISLNK (st->st_mode)((((st->st_mode)) & 0170000) == (0120000)))
459 {
460 if (rl->valid & VALID_SL0x0004)
461 {
462 np->dn->link_target = rl->target;
463 rl->target = 0;
464 st->st_size = strlen (np->dn->link_target);
465 }
466 else
467 {
468 st->st_mode &= ~S_IFMT0170000;
469 st->st_mode |= S_IFREG0100000;
470 }
471 }
472
473 if (rl->valid & VALID_TR0x0200)
474 {
475 st->st_mode |= S_IPTRANS000010000000;
476 np->dn->translen = rl->translen;
477 np->dn->translator = rl->trans;
478 rl->trans = 0;
479 }
480 else
481 {
482 np->dn->translator = 0;
483 np->dn->translen = 0;
484 }
485
486 diskfs_end_catch_exception ()({ struct disk_image_user *diu = diskfs_exception_diu; diskfs_exception_diu
= diu->next; })
;
487
488 return 0;
489}
490
491/* Symlink targets are never stored in files, so always use this. */
492static error_t
493read_symlink_hook (struct node *np, char *buf)
494{
495 bcopy (np->dn->link_target, buf, np->dn_stat.st_size);
496 return 0;
497}
498error_t (*diskfs_read_symlink_hook) (struct node *, char *)
499 = read_symlink_hook;
500
501
502/* The last reference to NP has gone away; drop it from the cache
503 and clean all state in the dn structure. */
504void
505diskfs_node_norefs (struct node *np)
506{
507 assert (node_cache[np->cache_id - 1].np == np)((node_cache[np->cache_id - 1].np == np) ? (void) (0) : __assert_fail
("node_cache[np->cache_id - 1].np == np", "../../isofs/inode.c"
, 507, __PRETTY_FUNCTION__))
;
508 node_cache[np->cache_id - 1].np = 0;
509
510 if (np->dn->translator)
511 free (np->dn->translator);
512
513 assert (!np->dn->fileinfo)((!np->dn->fileinfo) ? (void) (0) : __assert_fail ("!np->dn->fileinfo"
, "../../isofs/inode.c", 513, __PRETTY_FUNCTION__))
;
514 free (np->dn);
515 free (np);
516}
517
518/* The last hard reference to a node has gone away; arrange to have
519 all the weak references dropped that can be. */
520void
521diskfs_try_dropping_softrefs (struct node *np)
522{
523 drop_pager_softrefs (np);
524}
525
526void
527diskfs_lost_hardrefs (struct node *np)
528{
529}
530
531void
532diskfs_new_hardrefs (struct node *np)
533{
534 allow_pager_softrefs (np);
535}
536
537error_t
538diskfs_truncate (struct node *np, off_t length)
539{
540 return EROFS((0x10 << 26) | ((30) & 0x3fff));
541}
542
543error_t
544diskfs_grow (struct node *np, off_t end, struct protid *cred)
545{
546 return EROFS((0x10 << 26) | ((30) & 0x3fff));
547}
548
549error_t
550diskfs_set_translator (struct node *np,
551 const char *name, u_int namelen,
552 struct protid *cred)
553{
554 return EROFS((0x10 << 26) | ((30) & 0x3fff));
555}
556
557error_t
558diskfs_get_translator (struct node *np, char **namep, u_int *namelen)
559{
560 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
561}
562
563void
564diskfs_shutdown_soft_ports ()
565{
566 /* Should initiate termination of internally held pager ports
567 (the only things that should be soft) XXX */
568}
569
570error_t
571diskfs_node_reload (struct node *node)
572{
573 /* Never necessary on a read-only medium */
574 return 0;
575}
576
577error_t
578diskfs_validate_author_change (struct node *np, uid_t author)
579{
580 return EROFS((0x10 << 26) | ((30) & 0x3fff));
581}
582
583error_t
584diskfs_node_iterate (error_t (*fun)(struct node *))
585{
586 /* We never actually have to do anything, because this function
587 is only used for things that have to do with read-write media. */
588 return 0;
589}
590
591void
592diskfs_write_disknode (struct node *np, int wait)
593{
594}
595
596error_t
597diskfs_set_statfs (struct statfs *st)
598{
599 /* There is no easy way to determine the number of files on an
600 ISO 9660 filesystem. */
601 bzero (st, sizeof *st);
602 st->f_type = FSTYPE_ISO96600x0000001a;
603 st->f_bsize = logical_block_size;
604 st->f_blocks = isonum_733 (sblock->vol_sp_size);
605 st->f_fsid = getpid ();
606 st->f_frsize = logical_block_size;
607 return 0;
608}
609
610error_t
611diskfs_S_file_get_storage_info (struct protid *cred,
612 mach_port_t **ports,
613 mach_msg_type_name_t *ports_type,
614 mach_msg_type_number_t *num_ports,
615 int **ints, mach_msg_type_number_t *num_ints,
616 off_t **offsets,
617 mach_msg_type_number_t *num_offsets,
618 char **data, mach_msg_type_number_t *data_len)
619{
620 /* XXX */
621 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
622}
623
624void
625diskfs_free_node (struct node *no, mode_t mode)
626{
627 abort ();
628}
629
630error_t
631diskfs_alloc_node (struct node *dp, mode_t mode, struct node **np)
632{
633 return EROFS((0x10 << 26) | ((30) & 0x3fff));
634}