|
|
1.1 root 1: #include <linux/sched.h>
2: #include <linux/kernel.h>
3: #include <asm/segment.h>
4:
5: #include <string.h>
6: #include <fcntl.h>
7: #include <errno.h>
8: #include <const.h>
9: #include <sys/stat.h>
10:
11: #define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
12:
13: /*
14: * comment out this line if you want names > NAME_LEN chars to be
15: * truncated. Else they will be disallowed.
16: */
17: /* #define NO_TRUNCATE */
18:
19: #define MAY_EXEC 1
20: #define MAY_WRITE 2
21: #define MAY_READ 4
22:
23: /*
24: * permission()
25: *
26: * is used to check for read/write/execute permissions on a file.
27: * I don't know if we should look at just the euid or both euid and
28: * uid, but that should be easily changed.
29: */
30: static int permission(struct m_inode * inode,int mask)
31: {
32: int mode = inode->i_mode;
33:
34: /* special case: not even root can read/write a deleted file */
35: if (inode->i_dev && !inode->i_nlinks)
36: return 0;
37: if (!(current->uid && current->euid))
38: mode=0777;
39: else if (current->uid==inode->i_uid || current->euid==inode->i_uid)
40: mode >>= 6;
41: else if (current->gid==inode->i_gid || current->egid==inode->i_gid)
42: mode >>= 3;
43: return mode & mask & 0007;
44: }
45:
46: /*
47: * ok, we cannot use strncmp, as the name is not in our data space.
48: * Thus we'll have to use match. No big problem. Match also makes
49: * some sanity tests.
50: *
51: * NOTE! unlike strncmp, match returns 1 for success, 0 for failure.
52: */
53: static int match(int len,const char * name,struct dir_entry * de)
54: {
55: register int same __asm__("ax");
56:
57: if (!de || !de->inode || len > NAME_LEN)
58: return 0;
59: if (len < NAME_LEN && de->name[len])
60: return 0;
61: __asm__("cld\n\t"
62: "fs ; repe ; cmpsb\n\t"
63: "setz %%al"
64: :"=a" (same)
65: :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
1.1.1.2 ! root 66: /*:"cx","di","si"*/);
1.1 root 67: return same;
68: }
69:
70: /*
71: * find_entry()
72: *
73: * finds and entry in the specified directory with the wanted name. It
74: * returns the cache buffer in which the entry was found, and the entry
75: * itself (as a parameter - res_dir). It does NOT read the inode of the
76: * entry - you'll have to do that yourself if you want to.
77: */
78: static struct buffer_head * find_entry(struct m_inode * dir,
79: const char * name, int namelen, struct dir_entry ** res_dir)
80: {
81: int entries;
82: int block,i;
83: struct buffer_head * bh;
84: struct dir_entry * de;
85:
86: #ifdef NO_TRUNCATE
87: if (namelen > NAME_LEN)
88: return NULL;
89: #else
90: if (namelen > NAME_LEN)
91: namelen = NAME_LEN;
92: #endif
93: entries = dir->i_size / (sizeof (struct dir_entry));
94: *res_dir = NULL;
95: if (!namelen)
96: return NULL;
97: if (!(block = dir->i_zone[0]))
98: return NULL;
99: if (!(bh = bread(dir->i_dev,block)))
100: return NULL;
101: i = 0;
102: de = (struct dir_entry *) bh->b_data;
103: while (i < entries) {
104: if ((char *)de >= BLOCK_SIZE+bh->b_data) {
105: brelse(bh);
106: bh = NULL;
107: if (!(block = bmap(dir,i/DIR_ENTRIES_PER_BLOCK)) ||
108: !(bh = bread(dir->i_dev,block))) {
109: i += DIR_ENTRIES_PER_BLOCK;
110: continue;
111: }
112: de = (struct dir_entry *) bh->b_data;
113: }
114: if (match(namelen,name,de)) {
115: *res_dir = de;
116: return bh;
117: }
118: de++;
119: i++;
120: }
121: brelse(bh);
122: return NULL;
123: }
124:
125: /*
126: * add_entry()
127: *
128: * adds a file entry to the specified directory, using the same
129: * semantics as find_entry(). It returns NULL if it failed.
130: *
131: * NOTE!! The inode part of 'de' is left at 0 - which means you
132: * may not sleep between calling this and putting something into
133: * the entry, as someone else might have used it while you slept.
134: */
135: static struct buffer_head * add_entry(struct m_inode * dir,
136: const char * name, int namelen, struct dir_entry ** res_dir)
137: {
138: int block,i;
139: struct buffer_head * bh;
140: struct dir_entry * de;
141:
142: *res_dir = NULL;
143: #ifdef NO_TRUNCATE
144: if (namelen > NAME_LEN)
145: return NULL;
146: #else
147: if (namelen > NAME_LEN)
148: namelen = NAME_LEN;
149: #endif
150: if (!namelen)
151: return NULL;
152: if (!(block = dir->i_zone[0]))
153: return NULL;
154: if (!(bh = bread(dir->i_dev,block)))
155: return NULL;
156: i = 0;
157: de = (struct dir_entry *) bh->b_data;
158: while (1) {
159: if ((char *)de >= BLOCK_SIZE+bh->b_data) {
160: brelse(bh);
161: bh = NULL;
162: block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK);
163: if (!block)
164: return NULL;
165: if (!(bh = bread(dir->i_dev,block))) {
166: i += DIR_ENTRIES_PER_BLOCK;
167: continue;
168: }
169: de = (struct dir_entry *) bh->b_data;
170: }
171: if (i*sizeof(struct dir_entry) >= dir->i_size) {
172: de->inode=0;
173: dir->i_size = (i+1)*sizeof(struct dir_entry);
174: dir->i_dirt = 1;
175: dir->i_ctime = CURRENT_TIME;
176: }
177: if (!de->inode) {
178: dir->i_mtime = CURRENT_TIME;
179: for (i=0; i < NAME_LEN ; i++)
180: de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
181: bh->b_dirt = 1;
182: *res_dir = de;
183: return bh;
184: }
185: de++;
186: i++;
187: }
188: brelse(bh);
189: return NULL;
190: }
191:
192: /*
193: * get_dir()
194: *
195: * Getdir traverses the pathname until it hits the topmost directory.
196: * It returns NULL on failure.
197: */
198: static struct m_inode * get_dir(const char * pathname)
199: {
200: char c;
201: const char * thisname;
202: struct m_inode * inode;
203: struct buffer_head * bh;
204: int namelen,inr,idev;
205: struct dir_entry * de;
206:
207: if (!current->root || !current->root->i_count)
208: panic("No root inode");
209: if (!current->pwd || !current->pwd->i_count)
210: panic("No cwd inode");
211: if ((c=get_fs_byte(pathname))=='/') {
212: inode = current->root;
213: pathname++;
214: } else if (c)
215: inode = current->pwd;
216: else
217: return NULL; /* empty name is bad */
218: inode->i_count++;
219: while (1) {
220: thisname = pathname;
221: if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) {
222: iput(inode);
223: return NULL;
224: }
225: for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++)
226: /* nothing */ ;
227: if (!c)
228: return inode;
229: if (!(bh = find_entry(inode,thisname,namelen,&de))) {
230: iput(inode);
231: return NULL;
232: }
233: inr = de->inode;
234: idev = inode->i_dev;
235: brelse(bh);
236: iput(inode);
237: if (!(inode = iget(idev,inr)))
238: return NULL;
239: }
240: }
241:
242: /*
243: * dir_namei()
244: *
245: * dir_namei() returns the inode of the directory of the
246: * specified name, and the name within that directory.
247: */
248: static struct m_inode * dir_namei(const char * pathname,
249: int * namelen, const char ** name)
250: {
251: char c;
252: const char * basename;
253: struct m_inode * dir;
254:
255: if (!(dir = get_dir(pathname)))
256: return NULL;
257: basename = pathname;
1.1.1.2 ! root 258: while ((c=get_fs_byte(pathname++)))
1.1 root 259: if (c=='/')
260: basename=pathname;
261: *namelen = pathname-basename-1;
262: *name = basename;
263: return dir;
264: }
265:
266: /*
267: * namei()
268: *
269: * is used by most simple commands to get the inode of a specified name.
270: * Open, link etc use their own routines, but this is enough for things
271: * like 'chmod' etc.
272: */
273: struct m_inode * namei(const char * pathname)
274: {
275: const char * basename;
276: int inr,dev,namelen;
277: struct m_inode * dir;
278: struct buffer_head * bh;
279: struct dir_entry * de;
280:
281: if (!(dir = dir_namei(pathname,&namelen,&basename)))
282: return NULL;
283: if (!namelen) /* special case: '/usr/' etc */
284: return dir;
285: bh = find_entry(dir,basename,namelen,&de);
286: if (!bh) {
287: iput(dir);
288: return NULL;
289: }
290: inr = de->inode;
291: dev = dir->i_dev;
292: brelse(bh);
293: iput(dir);
294: dir=iget(dev,inr);
295: if (dir) {
296: dir->i_atime=CURRENT_TIME;
297: dir->i_dirt=1;
298: }
299: return dir;
300: }
301:
302: /*
303: * open_namei()
304: *
305: * namei for open - this is in fact almost the whole open-routine.
306: */
307: int open_namei(const char * pathname, int flag, int mode,
308: struct m_inode ** res_inode)
309: {
310: const char * basename;
311: int inr,dev,namelen;
312: struct m_inode * dir, *inode;
313: struct buffer_head * bh;
314: struct dir_entry * de;
315:
316: if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
317: flag |= O_WRONLY;
318: mode &= 0777 & ~current->umask;
319: mode |= I_REGULAR;
320: if (!(dir = dir_namei(pathname,&namelen,&basename)))
321: return -ENOENT;
322: if (!namelen) { /* special case: '/usr/' etc */
323: if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
324: *res_inode=dir;
325: return 0;
326: }
327: iput(dir);
328: return -EISDIR;
329: }
330: bh = find_entry(dir,basename,namelen,&de);
331: if (!bh) {
332: if (!(flag & O_CREAT)) {
333: iput(dir);
334: return -ENOENT;
335: }
336: if (!permission(dir,MAY_WRITE)) {
337: iput(dir);
338: return -EACCES;
339: }
340: inode = new_inode(dir->i_dev);
341: if (!inode) {
342: iput(dir);
343: return -ENOSPC;
344: }
345: inode->i_mode = mode;
346: inode->i_dirt = 1;
347: bh = add_entry(dir,basename,namelen,&de);
348: if (!bh) {
349: inode->i_nlinks--;
350: iput(inode);
351: iput(dir);
352: return -ENOSPC;
353: }
354: de->inode = inode->i_num;
355: bh->b_dirt = 1;
356: brelse(bh);
357: iput(dir);
358: *res_inode = inode;
359: return 0;
360: }
361: inr = de->inode;
362: dev = dir->i_dev;
363: brelse(bh);
364: iput(dir);
365: if (flag & O_EXCL)
366: return -EEXIST;
367: if (!(inode=iget(dev,inr)))
368: return -EACCES;
369: if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
370: permission(inode,ACC_MODE(flag))!=ACC_MODE(flag)) {
371: iput(inode);
372: return -EPERM;
373: }
374: inode->i_atime = CURRENT_TIME;
375: if (flag & O_TRUNC)
376: truncate(inode);
377: *res_inode = inode;
378: return 0;
379: }
380:
381: int sys_mkdir(const char * pathname, int mode)
382: {
383: const char * basename;
384: int namelen;
385: struct m_inode * dir, * inode;
386: struct buffer_head * bh, *dir_block;
387: struct dir_entry * de;
388:
389: if (current->euid && current->uid)
390: return -EPERM;
391: if (!(dir = dir_namei(pathname,&namelen,&basename)))
392: return -ENOENT;
393: if (!namelen) {
394: iput(dir);
395: return -ENOENT;
396: }
397: if (!permission(dir,MAY_WRITE)) {
398: iput(dir);
399: return -EPERM;
400: }
401: bh = find_entry(dir,basename,namelen,&de);
402: if (bh) {
403: brelse(bh);
404: iput(dir);
405: return -EEXIST;
406: }
407: inode = new_inode(dir->i_dev);
408: if (!inode) {
409: iput(dir);
410: return -ENOSPC;
411: }
412: inode->i_size = 32;
413: inode->i_dirt = 1;
414: inode->i_mtime = inode->i_atime = CURRENT_TIME;
415: if (!(inode->i_zone[0]=new_block(inode->i_dev))) {
416: iput(dir);
417: inode->i_nlinks--;
418: iput(inode);
419: return -ENOSPC;
420: }
421: inode->i_dirt = 1;
422: if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) {
423: iput(dir);
424: free_block(inode->i_dev,inode->i_zone[0]);
425: inode->i_nlinks--;
426: iput(inode);
427: return -ERROR;
428: }
429: de = (struct dir_entry *) dir_block->b_data;
430: de->inode=inode->i_num;
431: strcpy(de->name,".");
432: de++;
433: de->inode = dir->i_num;
434: strcpy(de->name,"..");
435: inode->i_nlinks = 2;
436: dir_block->b_dirt = 1;
437: brelse(dir_block);
438: inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask);
439: inode->i_dirt = 1;
440: bh = add_entry(dir,basename,namelen,&de);
441: if (!bh) {
442: iput(dir);
443: free_block(inode->i_dev,inode->i_zone[0]);
444: inode->i_nlinks=0;
445: iput(inode);
446: return -ENOSPC;
447: }
448: de->inode = inode->i_num;
449: bh->b_dirt = 1;
450: dir->i_nlinks++;
451: dir->i_dirt = 1;
452: iput(dir);
453: iput(inode);
454: brelse(bh);
455: return 0;
456: }
457:
458: /*
459: * routine to check that the specified directory is empty (for rmdir)
460: */
461: static int empty_dir(struct m_inode * inode)
462: {
463: int nr,block;
464: int len;
465: struct buffer_head * bh;
466: struct dir_entry * de;
467:
468: len = inode->i_size / sizeof (struct dir_entry);
469: if (len<2 || !inode->i_zone[0] ||
470: !(bh=bread(inode->i_dev,inode->i_zone[0]))) {
471: printk("warning - bad directory on dev %04x\n",inode->i_dev);
472: return 0;
473: }
474: de = (struct dir_entry *) bh->b_data;
475: if (de[0].inode != inode->i_num || !de[1].inode ||
476: strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
477: printk("warning - bad directory on dev %04x\n",inode->i_dev);
478: return 0;
479: }
480: nr = 2;
481: de += 2;
482: while (nr<len) {
483: if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
484: brelse(bh);
485: block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK);
486: if (!block) {
487: nr += DIR_ENTRIES_PER_BLOCK;
488: continue;
489: }
490: if (!(bh=bread(inode->i_dev,block)))
491: return 0;
492: de = (struct dir_entry *) bh->b_data;
493: }
494: if (de->inode) {
495: brelse(bh);
496: return 0;
497: }
498: de++;
499: nr++;
500: }
501: brelse(bh);
502: return 1;
503: }
504:
505: int sys_rmdir(const char * name)
506: {
507: const char * basename;
508: int namelen;
509: struct m_inode * dir, * inode;
510: struct buffer_head * bh;
511: struct dir_entry * de;
512:
513: if (current->euid && current->uid)
514: return -EPERM;
515: if (!(dir = dir_namei(name,&namelen,&basename)))
516: return -ENOENT;
517: if (!namelen) {
518: iput(dir);
519: return -ENOENT;
520: }
521: bh = find_entry(dir,basename,namelen,&de);
522: if (!bh) {
523: iput(dir);
524: return -ENOENT;
525: }
526: if (!permission(dir,MAY_WRITE)) {
527: iput(dir);
528: brelse(bh);
529: return -EPERM;
530: }
531: if (!(inode = iget(dir->i_dev, de->inode))) {
532: iput(dir);
533: brelse(bh);
534: return -EPERM;
535: }
536: if (inode == dir) { /* we may not delete ".", but "../dir" is ok */
537: iput(inode);
538: iput(dir);
539: brelse(bh);
540: return -EPERM;
541: }
542: if (!S_ISDIR(inode->i_mode)) {
543: iput(inode);
544: iput(dir);
545: brelse(bh);
546: return -ENOTDIR;
547: }
548: if (!empty_dir(inode)) {
549: iput(inode);
550: iput(dir);
551: brelse(bh);
552: return -ENOTEMPTY;
553: }
554: if (inode->i_nlinks != 2)
555: printk("empty directory has nlink!=2 (%d)",inode->i_nlinks);
556: de->inode = 0;
557: bh->b_dirt = 1;
558: brelse(bh);
559: inode->i_nlinks=0;
560: inode->i_dirt=1;
561: dir->i_nlinks--;
562: dir->i_ctime = dir->i_mtime = CURRENT_TIME;
563: dir->i_dirt=1;
564: iput(dir);
565: iput(inode);
566: return 0;
567: }
568:
569: int sys_unlink(const char * name)
570: {
571: const char * basename;
572: int namelen;
573: struct m_inode * dir, * inode;
574: struct buffer_head * bh;
575: struct dir_entry * de;
576:
577: if (!(dir = dir_namei(name,&namelen,&basename)))
578: return -ENOENT;
579: if (!namelen) {
580: iput(dir);
581: return -ENOENT;
582: }
583: if (!permission(dir,MAY_WRITE)) {
584: iput(dir);
585: return -EPERM;
586: }
587: bh = find_entry(dir,basename,namelen,&de);
588: if (!bh) {
589: iput(dir);
590: return -ENOENT;
591: }
592: inode = iget(dir->i_dev, de->inode);
593: if (!inode) {
594: printk("iget failed in delete (%04x:%d)",dir->i_dev,de->inode);
595: iput(dir);
596: brelse(bh);
597: return -ENOENT;
598: }
599: if (!S_ISREG(inode->i_mode)) {
600: iput(inode);
601: iput(dir);
602: brelse(bh);
603: return -EPERM;
604: }
605: if (!inode->i_nlinks) {
606: printk("Deleting nonexistent file (%04x:%d), %d\n",
607: inode->i_dev,inode->i_num,inode->i_nlinks);
608: inode->i_nlinks=1;
609: }
610: de->inode = 0;
611: bh->b_dirt = 1;
612: brelse(bh);
613: inode->i_nlinks--;
614: inode->i_dirt = 1;
615: inode->i_ctime = CURRENT_TIME;
616: iput(inode);
617: iput(dir);
618: return 0;
619: }
620:
621: int sys_link(const char * oldname, const char * newname)
622: {
623: struct dir_entry * de;
624: struct m_inode * oldinode, * dir;
625: struct buffer_head * bh;
626: const char * basename;
627: int namelen;
628:
629: oldinode=namei(oldname);
630: if (!oldinode)
631: return -ENOENT;
632: if (!S_ISREG(oldinode->i_mode)) {
633: iput(oldinode);
634: return -EPERM;
635: }
636: dir = dir_namei(newname,&namelen,&basename);
637: if (!dir) {
638: iput(oldinode);
639: return -EACCES;
640: }
641: if (!namelen) {
642: iput(oldinode);
643: iput(dir);
644: return -EPERM;
645: }
646: if (dir->i_dev != oldinode->i_dev) {
647: iput(dir);
648: iput(oldinode);
649: return -EXDEV;
650: }
651: if (!permission(dir,MAY_WRITE)) {
652: iput(dir);
653: iput(oldinode);
654: return -EACCES;
655: }
656: bh = find_entry(dir,basename,namelen,&de);
657: if (bh) {
658: brelse(bh);
659: iput(dir);
660: iput(oldinode);
661: return -EEXIST;
662: }
663: bh = add_entry(dir,basename,namelen,&de);
664: if (!bh) {
665: iput(dir);
666: iput(oldinode);
667: return -ENOSPC;
668: }
669: de->inode = oldinode->i_num;
670: bh->b_dirt = 1;
671: brelse(bh);
672: iput(dir);
673: oldinode->i_nlinks++;
674: oldinode->i_ctime = CURRENT_TIME;
675: oldinode->i_dirt = 1;
676: iput(oldinode);
677: return 0;
678: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.