Bug Summary

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