|
|
1.1 root 1: /*
2: * namei code for fs filesystem
3: */
4:
5: #include "sys/param.h"
6: #include "sys/systm.h"
7: #include "sys/inode.h"
8: #include "sys/buf.h"
9: #include "sys/filsys.h"
10: #include "sys/dir.h"
11: #include "sys/user.h"
12:
13: struct dent {
14: struct direct dir;
15: off_t off;
16: int nentry;
17: };
18:
19: fsnami(p, flagp, follow)
20: struct nx *p;
21: register struct argnamei *flagp;
22: {
23: register struct inode *dp;
24: register char *cp;
25: register struct buf *bp;
26: register struct inode *dip;
27: register int i;
28: struct dent dent;
29: struct inode *domkfile();
30: ino_t dsearch();
31:
32: cp = p->cp;
33: dp = p->dp;
34:
35: /*
36: * dp is the inode to search; cp is the pathname to find.
37: * dp must be a directory, with execute permissions.
38: * (this test is done too early; it forbids a filesystem
39: * consisting of a single file with i-number ROOTINO)
40: */
41: dirloop:
42: if((dp->i_mode&IFMT) != IFDIR) {
43: u.u_error = ENOTDIR;
44: goto outnull;
45: }
46: if (access(dp, IEXEC))
47: goto outnull;
48: for (i=0; *cp!='\0' && *cp!='/'; i++) {
49: if (i >= DIRSIZ) {
50: u.u_error = ENOENT;
51: goto outnull;
52: }
53: dent.dir.d_name[i] = *cp++;
54: }
55: while (i < DIRSIZ)
56: dent.dir.d_name[i++] = '\0';
57: while (*cp == '/')
58: cp++;
59: if (dent.dir.d_name[0] == '\0') { /* null name, e.g. "/" or "" */
60: if (flagp->flag != NI_SEARCH) {
61: u.u_error = ENOENT;
62: goto outnull;
63: }
64: /*
65: * should pass NI_CREAT too, but dp is known to be a directory
66: */
67: goto out;
68: }
69: u.u_segflg = SEGSYS; /* for various routines that write directories */
70: if (dsearch(dp, &dent) == 0) {
71: if (u.u_error)
72: goto outnull;
73: /*
74: * name not found
75: * if we wanted to create or link, that's OK
76: */
77: if (*cp == 0) switch (flagp->flag) {
78: case NI_CREAT:
79: case NI_NXCREAT:
80: case NI_MKDIR:
81: case NI_LINK:
82: dip = dp;
83: dp = domkfile(dip, flagp, &dent);
84: iput(dip);
85: goto out;
86: }
87: u.u_error = ENOENT;
88: goto outnull;
89: }
90: /*
91: * name found
92: * did we want to remove it?
93: * (do before ".." check)
94: */
95: if(flagp->flag == NI_DEL && *cp == 0) {
96: dormfile(dp, &dent);
97: goto outnull;
98: }
99: if(flagp->flag == NI_RMDIR && *cp == 0) {
100: dormdir(dp, &dent);
101: goto outnull;
102: }
103: /*
104: * special code for ".." in a root directory
105: */
106: if (dent.dir.d_name[0] == '.'
107: && dent.dir.d_name[1] == '.'
108: && dent.dir.d_name[2] == '\0') {
109: if (dp == rootdir || dp == u.u_rdir)
110: goto dirloop;
111: if (dent.dir.d_ino == ROOTINO && dp->i_number == ROOTINO) {
112: dip = dp->i_mpoint;
113: i = dp->i_fstyp;
114: iput(dp);
115: dp = dip;
116: plock(dp);
117: dp->i_count++;
118: while (*--cp == '/')
119: ;
120: cp--; /* skip over ".." and / */
121: if (dp->i_fstyp != i)
122: goto outmore;
123: goto dirloop;
124: }
125: }
126: /*
127: * fetch the inode for the filename we found
128: */
129: dip = dp;
130: prele(dip);
131: dp = iget(dip, dip->i_dev, dent.dir.d_ino);
132: if (dp == NULL) {
133: idec(dip);
134: goto out; /* sic */
135: }
136: if (dp->i_count == 1 && fsiread(dip, dp) < 0) {
137: idec(dip);
138: dp = NULL; /* fsiread iput it */
139: goto out;
140: }
141: if(dip->i_fstyp != dp->i_fstyp) {
142: idec(dip);
143: goto outmore;
144: }
145: /*
146: * symlink? If so and if wanted, follow.
147: */
148: if ((dp->i_mode&IFMT)==IFLNK && (follow || *cp!='\0')) {
149: char *ocp;
150:
151: ocp = cp;
152: while (*cp++)
153: ;
154: i = cp - ocp; /* strlen(ocp) + 1 for NUL */
155: if (dp->i_size > BSIZE(dp->i_dev)
156: || dp->i_size + 1 + i > p->nlen /* +1 for '/' */
157: || ++p->nlink>8) {
158: u.u_error = ELOOP;
159: idec(dip);
160: goto outnull;
161: }
162: cp = p->nbuf;
163: if (i == 1) /* empty pathname, just put NUL there */
164: cp[dp->i_size] = 0;
165: else {
166: bcopy(ocp, cp + dp->i_size + 1, i); /* remaining pathname */
167: cp[dp->i_size] = '/';
168: }
169: bp = bread(dp->i_dev, bmap(dp, (daddr_t)0, B_READ));
170: if (bp->b_flags & B_ERROR) {
171: brelse(bp);
172: idec(dip);
173: goto outnull;
174: }
175: bcopy(bp->b_un.b_addr, cp, dp->i_size); /* new prefix */
176: brelse(bp);
177: i = dp->i_fstyp;
178: iput(dp);
179: if (*cp != '/')
180: dp = dip;
181: else {
182: idec(dip);
183: while (*cp == '/')
184: cp++;
185: if ((dp = u.u_rdir) == NULL)
186: dp = rootdir;
187: plock(dp);
188: dp->i_count++;
189: }
190: if (i != dp->i_fstyp)
191: goto outmore;
192: goto dirloop;
193: }
194: idec(dip);
195: /*
196: * more pathname to walk?
197: */
198: if (*cp)
199: goto dirloop;
200: /*
201: * final checks before returning:
202: * -- some operations are in error if filename exists
203: * -- save last piece of filename for accounting
204: */
205: if (flagp->flag == NI_LINK || flagp->flag == NI_NXCREAT
206: || flagp->flag == NI_MKDIR) {
207: u.u_error = EEXIST;
208: goto outnull;
209: }
210: if(flagp->flag == NI_SEARCH && flagp->un.buf)
211: bcopy(dent.dir.d_name, flagp->un.buf,
212: MIN(flagp->len, sizeof(dent.dir.d_name)));
213:
214: /*
215: * here to return the inode in dp
216: */
217: out:
218: p->dp = dp;
219: return(0);
220:
221: /*
222: * here to discard dp and return NULL
223: */
224: outnull:
225: iput(dp);
226: p->dp = NULL;
227: return (0);
228:
229: /*
230: * here if we crossed into another filesystem's domain:
231: * return dp (the first inode in that filesystem)
232: * and cp (the remainder of the pathname)
233: * and value 1, so namei knows it should continue
234: */
235: outmore:
236: p->cp = cp;
237: p->dp = dp;
238: return (1);
239: }
240:
241: /*
242: * create a new file of some sort in directory dp
243: * name is in dent->d_name
244: * offset is in dent->d_off
245: * return inode if it is needed
246: */
247: struct inode *
248: domkfile(dp, flagp, dent)
249: register struct inode *dp;
250: struct argnamei *flagp;
251: struct dent *dent;
252: {
253: register struct inode *dip;
254: struct direct x[2];
255: register i;
256:
257: if(access(dp, IWRITE))
258: return(NULL);
259: if (dp->i_nlink == 0) {
260: u.u_error = EINVAL;
261: return (NULL);
262: }
263: u.u_count = sizeof(struct direct);
264: u.u_base = (caddr_t)&dent->dir;
265: u.u_offset = ltoL(dent->off);
266: switch(flagp->flag) {
267:
268: case NI_CREAT: /* create a new file */
269: case NI_NXCREAT:
270: dip = ialloc(dp);
271: if(dip == NULL)
272: return(NULL);
273: dip->i_flag |= IACC|IUPD|ICHG;
274: dip->i_mode = flagp->un.mode;
275: if((dip->i_mode & IFMT) == 0)
276: dip->i_mode |= IFREG;
277: dip->i_nlink = 1;
278: dip->i_uid = u.u_uid;
279: dip->i_gid = dp->i_mode & ISGID ? u.u_gid : dp->i_gid;
280: if (u.u_uid && !groupmember(dip->i_gid))
281: dip->i_mode &= ~ISGID;
282: fsiupdat(dip, &time, &time, 1);
283: dent->dir.d_ino = dip->i_number;
284: flagp->un.mode = ~flagp->un.mode;
285: writei(dp);
286: return(dip);
287:
288: case NI_MKDIR: /* make a new directory */
289: dip = ialloc(dp);
290: if(dip == NULL)
291: return(NULL);
292: dent->dir.d_ino = dip->i_number;
293: dip->i_mode = flagp->un.mode;
294: dip->i_nlink = 1;
295: dip->i_uid = u.u_uid;
296: dip->i_gid = dp->i_gid;
297: dip->i_flag |= IACC|IUPD|ICHG;
298: x[0].d_ino = dip->i_number;
299: x[1].d_ino = dp->i_number;
300: for(i = 0; i < DIRSIZ; i++)
301: x[0].d_name[i] = x[1].d_name[i] = 0;
302: x[0].d_name[0] = x[1].d_name[0] = x[1].d_name[1] = '.';
303: u.u_count = sizeof(x);
304: u.u_base = (caddr_t)x;
305: u.u_offset = ltoL(0);
306: u.u_segflg = SEGSYS;
307: writei(dip);
308: if (u.u_error) {
309: dip->i_nlink--;
310: iput(dip);
311: return(NULL);
312: }
313: dip->i_nlink++;
314: dp->i_nlink++;
315: fsiupdat(dip, &time, &time, 1);
316: u.u_count = sizeof(struct direct);
317: u.u_base = (caddr_t)&dent->dir;
318: u.u_offset = ltoL(dent->off);
319: writei(dp);
320: iput(dip);
321: return(NULL);
322:
323: case NI_LINK: /* make a link */
324: if(dp->i_dev != flagp->un.il->i_dev) {
325: u.u_error = EXDEV;
326: return(NULL);
327: }
328: dent->dir.d_ino = flagp->un.il->i_number;
329: writei(dp);
330: return(NULL);
331: }
332: panic("domkfile");
333: }
334:
335: /*
336: * delete a non-directory file
337: */
338: dormfile(dp, dent)
339: register struct inode *dp;
340: register struct dent *dent;
341: {
342: register struct inode *dip;
343:
344: if(access(dp, IWRITE))
345: return;
346: if(dp->i_number == dent->dir.d_ino) { /* for '.' */
347: dip = dp;
348: dp->i_count++;
349: } else {
350: dip = iget(dp, dp->i_dev, dent->dir.d_ino);
351: if (dip == NULL)
352: return;
353: if (dip->i_count == 1 && fsiread(dp, dip) < 0)
354: return;
355: }
356: if(dip->i_mpoint != dp->i_mpoint) {
357: u.u_error = EBUSY;
358: iput(dip);
359: return;
360: }
361: if((dip->i_mode&IFMT) == IFDIR && !suser()) {
362: iput(dip);
363: return;
364: }
365: if(dip->i_flag&ITEXT)
366: xrele(dip); /* free busy text */
367: u.u_base = (caddr_t)&dent->dir;
368: u.u_count = sizeof(struct direct);
369: u.u_offset = ltoL(dent->off);
370: dent->dir.d_ino = 0;
371: writei(dp); /* segflg already set*/
372: dip->i_nlink--;
373: dip->i_flag |= ICHG;
374: iput(dip);
375: }
376:
377: /*
378: * remove a directory (fsnami)
379: * dp is inode of containing directory
380: * dent->dir is the entry (which exists)
381: * u.u_offset is the offset in containing directory of this entry
382: */
383: dormdir(dp, dent)
384: register struct inode *dp;
385: register struct dent *dent;
386: {
387: register struct inode *dip;
388: register int nentry;
389: struct dent tdent;
390: ino_t dotino, dotdotino;
391: ino_t dsearch();
392:
393: if(access(dp, IWRITE))
394: return;
395: if(dp->i_number == dent->dir.d_ino
396: || strncmp(dent->dir.d_name, "..", DIRSIZ)==0) { /* gets "." and "" */
397: u.u_error = EINVAL;
398: return;
399: }
400: if((dip = iget(dp, dp->i_dev, dent->dir.d_ino)) == NULL)
401: return;
402: if(dip->i_number == ROOTINO) {
403: u.u_error = EINVAL;
404: iput(dip);
405: return;
406: }
407: if(dip->i_mpoint != dp->i_mpoint) {
408: u.u_error = EBUSY;
409: iput(dip);
410: return;
411: }
412: if (dip->i_count == 1 && fsiread(dp, dip) < 0)
413: return;
414: if((dip->i_mode & IFMT) != IFDIR) {
415: u.u_error = ENOTDIR;
416: iput(dip);
417: return;
418: }
419: /* search for ., .., other entries in dir */
420: cpdirent("/", &tdent); /* cannot be found; just count entries */
421: dsearch(dip, &tdent);
422: nentry = tdent.nentry;
423: tdent.dir.d_name[0] = '.';
424: if (dotino = dsearch(dip, &tdent))
425: nentry--;
426: tdent.dir.d_name[1] = '.';
427: if(dotdotino = dsearch(dip, &tdent))
428: nentry--;
429: if (nentry > 0) {
430: u.u_error = EHASF; /* removing nonempty directory */
431: iput(dip);
432: return;
433: }
434: if (dotino) {
435: if (dip->i_number == dotino)
436: dip->i_nlink--;
437: /* else error? */
438: }
439: if (dotdotino) {
440: if (dp->i_number == dotdotino)
441: dp->i_nlink--;
442: /* else error? */
443: }
444: u.u_base = (caddr_t)&dent->dir;
445: u.u_count = sizeof(struct direct);
446: u.u_offset = ltoL(dent->off);
447: dent->dir.d_ino = 0;
448: writei(dp);
449: dp->i_flag |= ICHG;
450: fsiupdat(dp, &time, &time, 1);
451: dip->i_nlink--;
452: dip->i_flag |= ICHG;
453: iput(dip);
454: }
455:
456: cpdirent(s, dent)
457: register char *s;
458: register struct dent *dent;
459: {
460: register char *dp = dent->dir.d_name;
461:
462: while (dp < &dent->dir.d_name[DIRSIZ]) {
463: *dp++ = *s;
464: if (*s)
465: s++;
466: }
467: }
468:
469: /*
470: * search directory ip for entry dent->dir.d_name
471: * success: return ino, leave dent->dir with copy of entry,
472: * dent->off pointing at entry
473: * dent->nentry with count of entries
474: * fail: return 0, leave dent->off pointing at empty slot
475: */
476: ino_t
477: dsearch(ip, dent)
478: struct inode *ip;
479: struct dent *dent;
480: {
481: register struct direct *dp, *dpe;
482: register char *nm;
483: register off_t off;
484: struct buf *bp;
485: register int bsize;
486: register daddr_t n, nblock;
487:
488: dent->dir.d_ino = 0;
489: nm = dent->dir.d_name;
490: bsize = BSIZE(ip->i_dev);
491: dent->nentry = 0;
492: bp = NULL;
493: dent->off = -1;
494: nblock = (ip->i_size+bsize-1) / bsize;
495:
496: for (n=0, off=0; n<nblock; n++) {
497: if (bp)
498: brelse(bp);
499: bp = bread(ip->i_dev, bmap(ip, n, B_READ));
500: if (bp->b_flags & B_ERROR) {
501: u.u_error = EIO;
502: goto out;
503: }
504: dp = (struct direct *)bp->b_un.b_addr;
505: dpe = &dp[min(bsize, ip->i_size-off) / sizeof(struct direct)];
506: for (; dp < dpe; dp++, off+=sizeof(struct direct)) {
507: if (dp->d_ino == 0) {
508: if (dent->off<0)
509: dent->off = off;
510: continue;
511: }
512: dent->nentry++;
513: if (nm[2]==dp->d_name[2] /* hash */
514: && strncmp(nm, dp->d_name, DIRSIZ) == 0) {
515: dent->off = off;
516: dent->dir.d_ino = dp->d_ino;
517: goto out;
518: }
519: }
520: }
521: out:
522: if (dent->off<0)
523: dent->off = off;
524: if (bp)
525: brelse(bp);
526: return(dent->dir.d_ino);
527: }
528:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.