Bug Summary

File:obj-scan-build/isofs/../../isofs/lookup.c
Location:line 142, column 7
Description:Dereference of null pointer (loaded from variable 'npp')

Annotated Source Code

1/*
2 Copyright (C) 1997,98,99,2001,02 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 <stdlib.h>
23#include <dirent.h>
24#include "isofs.h"
25
26/* From inode.c */
27int use_file_start_id (struct dirrect *record, struct rrip_lookup *rr);
28
29/* Forward */
30static error_t dirscanblock (void *, const char *, size_t,
31 struct dirrect **, struct rrip_lookup *);
32
33static int
34isonamematch (const char *dirname, size_t dnamelen,
35 const char *username, size_t unamelen)
36{
37 /* Special representations for `.' and `..' */
38 if (dnamelen == 1 && dirname[0] == '\0')
39 return unamelen == 1 && username[0] == '.';
40
41 if (dnamelen == 1 && dirname[0] == '\1')
42 return unamelen == 2 && username[0] == '.' && username[1] == '.';
43
44 if (unamelen > dnamelen)
45 return 0;
46
47 if (!strncasecmp (dirname, username, unamelen))
48 {
49 /* A prefix has matched. Check if it's acceptable. */
50 if (dnamelen == unamelen)
51 return 1;
52
53 /* User has omitted the version number */
54 if (dirname[unamelen] == ';')
55 return 1;
56
57 /* User has omitted an empty extension */
58 if (dirname[unamelen] == '.'
59 && (dirname[unamelen+1] == '\0' || dirname[unamelen+1] == ';'))
60 return 1;
61 }
62
63 return 0;
64}
65
66/* Implement the diskfs_lookup callback from the diskfs library. See
67 <hurd/diskfs.h> for the interface specification. */
68error_t
69diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type,
70 struct node **npp, struct dirstat *ds, struct protid *cred)
71{
72 error_t err = 0;
73 struct dirrect *record;
74 int namelen;
75 int spec_dotdot;
76 void *buf;
77 void *blockaddr;
78 struct rrip_lookup rr;
79
80 if ((type == REMOVE) || (type == RENAME))
1
Assuming 'type' is not equal to REMOVE
2
Assuming 'type' is not equal to RENAME
3
Taking false branch
81 assert (npp)((npp) ? (void) (0) : __assert_fail ("npp", "../../isofs/lookup.c"
, 81, __PRETTY_FUNCTION__))
;
82
83 if (npp)
4
Assuming 'npp' is null
5
Taking false branch
84 *npp = 0;
85
86 spec_dotdot = type & SPEC_DOTDOT0x10000000;
87 type &= ~SPEC_DOTDOT0x10000000;
88
89 namelen = strlen (name);
90
91 /* This error is constant, but the errors for CREATE and REMOVE depend
92 on whether NAME exists. */
93 if (type == RENAME)
6
Assuming 'type' is not equal to RENAME
7
Taking false branch
94 return EROFS((0x10 << 26) | ((30) & 0x3fff));
95
96 buf = disk_image + (dp->dn->file_start << store->log2_block_size);
97
98 for (blockaddr = buf;
8
Loop condition is false. Execution continues on line 111
99 blockaddr < buf + dp->dn_stat.st_size;
100 blockaddr += logical_sector_size2048)
101 {
102 err = dirscanblock (blockaddr, name, namelen, &record, &rr);
103
104 if (!err)
105 break;
106
107 if (err != ENOENT((0x10 << 26) | ((2) & 0x3fff)))
108 return err;
109 }
110
111 if ((!err && type == REMOVE)
9
Assuming 'type' is not equal to REMOVE
112 || (err == ENOENT((0x10 << 26) | ((2) & 0x3fff)) && type == CREATE))
113 err = EROFS((0x10 << 26) | ((30) & 0x3fff));
114
115 if (err)
10
Taking false branch
116 return err;
117
118 /* Load the inode */
119 if (namelen == 2 && name[0] == '.' && name[1] == '.')
11
Assuming 'namelen' is not equal to 2
120 {
121 if (dp == diskfs_root_node)
122 err = EAGAIN((0x10 << 26) | ((35) & 0x3fff));
123 else if (spec_dotdot)
124 {
125 /* renames and removes can't get this far. */
126 assert (type == LOOKUP)((type == LOOKUP) ? (void) (0) : __assert_fail ("type == LOOKUP"
, "../../isofs/lookup.c", 126, __PRETTY_FUNCTION__))
;
127 diskfs_nput (dp);
128 err = load_inode (npp, record, &rr);
129 }
130 else
131 {
132 /* We don't have to do the normal rigamarole, because
133 we are permanently read-only, so things are necessarily
134 quiescent. Just be careful to honor the locking order. */
135 pthread_mutex_unlock (&dp->lock);
136 err = load_inode (npp, record, &rr);
137 pthread_mutex_lock (&dp->lock);
138 }
139 }
140 else if (namelen == 1 && name[0] == '.')
12
Assuming 'namelen' is equal to 1
13
Taking true branch
141 {
142 *npp = dp;
14
Dereference of null pointer (loaded from variable 'npp')
143 diskfs_nref (dp);
144 }
145 else
146 err = load_inode (npp, record, &rr);
147
148 release_rrip (&rr);
149 return err;
150}
151
152
153/* Scan one logical sector of directory contents (at address BLKADDR)
154 for NAME of length NAMELEN. Return its address in *RECORD. */
155static error_t
156dirscanblock (void *blkaddr, const char *name, size_t namelen,
157 struct dirrect **record, struct rrip_lookup *rr)
158{
159 struct dirrect *entry;
160 void *currentoff;
161 size_t reclen;
162 size_t entry_namelen;
163 int matchrr;
164 int matchnormal;
165
166 for (currentoff = blkaddr;
167 currentoff < blkaddr + logical_sector_size2048;
168 currentoff += reclen)
169 {
170 entry = (struct dirrect *) currentoff;
171
172 reclen = entry->len;
173
174 /* Validate reclen */
175 if (reclen == 0
176 || reclen < sizeof (struct dirrect)
177 || currentoff + reclen > blkaddr + logical_sector_size2048)
178 break;
179
180 entry_namelen = entry->namelen;
181
182 /* More validation */
183 if (reclen < sizeof (struct dirrect) + entry_namelen)
184 break;
185
186 /* Check to see if the name matches the directory entry. */
187 if (isonamematch ((const char *) entry->name, entry_namelen, name, namelen))
188 matchnormal = 1;
189 else
190 matchnormal = 0;
191
192 /* Now scan for RRIP fields */
193 matchrr = rrip_match_lookup (entry, name, namelen, rr);
194
195 /* Ignore RE entries */
196 if (rr->valid & VALID_RE0x0080)
197 {
198 release_rrip (rr);
199 continue;
200 }
201
202 /* See if the name matches */
203 if (((rr->valid & VALID_NM0x0008) && matchrr)
204 || (!(rr->valid & VALID_NM0x0008) && matchnormal))
205 {
206 /* We've got it. Return success */
207 *record = entry;
208 return 0;
209 }
210
211 release_rrip (rr);
212 }
213
214 /* Wasn't there. */
215 *record = 0;
216 return ENOENT((0x10 << 26) | ((2) & 0x3fff));
217}
218
219error_t
220diskfs_get_directs (struct node *dp,
221 int entry,
222 int nentries,
223 char **data,
224 size_t *datacnt,
225 vm_size_t bufsiz,
226 int *amt)
227{
228 volatile vm_size_t allocsize;
229 struct dirrect *ep;
230 struct dirent *userp;
231 int i;
232 void *dirbuf, *bufp;
233 char *datap;
234 volatile int ouralloc = 0;
235 error_t err;
236
237 /* Allocate some space to hold the returned data. */
238 allocsize = bufsiz ? round_page (bufsiz)((((vm_offset_t) (bufsiz) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
: vm_page_size * 4;
239 if (allocsize > *datacnt)
240 {
241 *data = mmap (0, allocsize, PROT_READ0x04|PROT_WRITE0x02, MAP_ANON0x0002, 0, 0);
242 ouralloc = 1;
243 }
244
245 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
; })
;
246 if (err)
247 {
248 if (ouralloc)
249 munmap (*data, allocsize);
250 return err;
251 }
252
253 /* Skip to ENTRY */
254 dirbuf = disk_image + (dp->dn->file_start << store->log2_block_size);
255 bufp = dirbuf;
256 for (i = 0; i < entry; i ++)
257 {
258 struct rrip_lookup rr;
259
260 ep = (struct dirrect *) bufp;
261 rrip_lookup (ep, &rr, 0);
262
263 /* Ignore and skip RE entries */
264 if (rr.valid & VALID_RE0x0080)
265 i--;
266 else
267 {
268 if (bufp - dirbuf >= dp->dn_stat.st_size)
269 {
270 /* Not that many entries in the directory; return nothing. */
271 release_rrip (&rr);
272 if (allocsize > *datacnt)
273 munmap (data, allocsize);
274 *datacnt = 0;
275 *amt = 0;
276 return 0;
277 }
278 }
279 bufp = bufp + ep->len;
280 release_rrip (&rr);
281
282 /* If BUFP points at a null, then we have hit the last
283 record in this logical sector. In that case, skip up to
284 the next logical sector. */
285 if (*(char *)bufp == '\0')
286 bufp = (void *) (((long) bufp & ~(logical_sector_size2048 - 1))
287 + logical_sector_size2048);
288 }
289
290 /* Now copy entries one at a time */
291 i = 0;
292 datap = *data;
293 while (((nentries == -1) || (i < nentries))
294 && (!bufsiz || datap - *data < bufsiz)
295 && ((void *) bufp - dirbuf < dp->dn_stat.st_size))
296 {
297 struct rrip_lookup rr;
298 const char *name;
299 size_t namlen, reclen;
300
301 ep = (struct dirrect *) bufp;
302
303 /* Fetch Rock-Ridge information for this file */
304 rrip_lookup (ep, &rr, 0);
305
306 /* Ignore and skip RE entries */
307 if (! (rr.valid & VALID_RE0x0080))
308 {
309 /* See if there's room to hold this one */
310 name = rr.valid & VALID_NM0x0008 ? rr.name : (char *) ep->name;
311 namlen = rr.valid & VALID_NM0x0008 ? strlen (name) : ep->namelen;
312
313 /* Name frobnication */
314 if (!(rr.valid & VALID_NM0x0008))
315 {
316 if (namlen == 1 && name[0] == '\0')
317 {
318 name = ".";
319 namlen = 1;
320 }
321 else if (namlen == 1 && name[0] == '\1')
322 {
323 name = "..";
324 namlen = 2;
325 }
326 /* Perhaps downcase it too? */
327 }
328
329 reclen = sizeof (struct dirent) + namlen;
330 reclen = (reclen + 3) & ~3;
331
332 /* Expand buffer if necessary */
333 if (datap - *data + reclen > allocsize)
334 {
335 vm_address_t newdata;
336
337 vm_allocate (mach_task_self ()((__mach_task_self_ + 0)), &newdata,
338 (ouralloc
339 ? (allocsize *= 2)
340 : (allocsize = vm_page_size * 2)), 1);
341 bcopy ((void *) *data, (void *)newdata, datap - *data);
342
343 if (ouralloc)
344 munmap (*data, allocsize / 2);
345
346 datap = (char *) newdata + (datap - *data);
347 *data = (char *) newdata;
348 ouralloc = 1;
349 }
350
351 userp = (struct dirent *) datap;
352
353 /* Fill in entry */
354
355 if (use_file_start_id (ep, &rr))
356 {
357 off_t file_start;
358
359 err = calculate_file_start (ep, &file_start, &rr);
360 if (err)
361 {
362 release_rrip (&rr);
363 diskfs_end_catch_exception ()({ struct disk_image_user *diu = diskfs_exception_diu; diskfs_exception_diu
= diu->next; })
;
364 if (ouralloc)
365 munmap (*data, allocsize);
366 return err;
367 }
368
369 userp->d_filenod_ino = file_start << store->log2_block_size;
370 }
371 else
372 userp->d_filenod_ino = (ino_t) ((void *) ep - (void *) disk_image);
373
374 userp->d_type = DT_UNKNOWNDT_UNKNOWN;
375 userp->d_reclen = reclen;
376 userp->d_namlen = namlen;
377 bcopy (name, userp->d_name, namlen);
378 userp->d_name[namlen] = '\0';
379
380 /* And move along */
381 datap = datap + reclen;
382 i++;
383 }
384
385 release_rrip (&rr);
386 bufp = bufp + ep->len;
387
388 /* If BUFP points at a null, then we have hit the last
389 record in this logical sector. In that case, skip up to
390 the next logical sector. */
391 if (*(char *)bufp == '\0')
392 bufp = (void *) (((long) bufp & ~(logical_sector_size2048 - 1))
393 + logical_sector_size2048);
394 }
395
396 diskfs_end_catch_exception ()({ struct disk_image_user *diu = diskfs_exception_diu; diskfs_exception_diu
= diu->next; })
;
397
398 /* If we didn't use all the pages of a buffer we allocated, free
399 the excess. */
400 if (ouralloc
401 && round_page (datap - *data)((((vm_offset_t) (datap - *data) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
< round_page (allocsize)((((vm_offset_t) (allocsize) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
)
402 munmap ((caddr_t) round_page (datap)((((vm_offset_t) (datap) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
,
403 round_page (allocsize)((((vm_offset_t) (allocsize) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
- round_page (datap - *data)((((vm_offset_t) (datap - *data) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
);
404
405 /* Return */
406 *amt = i;
407 *datacnt = datap - *data;
408 return 0;
409}
410
411/* We have no dirstats at all. */
412const size_t diskfs_dirstat_size = 0;
413
414void
415diskfs_null_dirstat (struct dirstat *ds)
416{
417}
418
419error_t
420diskfs_drop_dirstat (struct node *dp, struct dirstat *ds)
421{
422 return 0;
423}
424
425/* These should never be called. */
426
427error_t
428diskfs_direnter_hard(struct node *dp,
429 const char *name,
430 struct node *np,
431 struct dirstat *ds,
432 struct protid *cred)
433{
434 abort ();
435}
436
437error_t
438diskfs_dirremove_hard(struct node *dp,
439 struct dirstat *ds)
440{
441 abort ();
442}
443
444error_t
445diskfs_dirrewrite_hard(struct node *dp,
446 struct node *np,
447 struct dirstat *ds)
448{
449 abort ();
450}
451
452int
453diskfs_dirempty(struct node *dp,
454 struct protid *cred)
455{
456 abort ();
457}