|
|
1.1 root 1: /*
2: * linux/fs/minix/namei.c
3: *
4: * (C) 1991 Linus Torvalds
5: */
6:
7: #include <linux/sched.h>
8: #include <linux/minix_fs.h>
9: #include <linux/kernel.h>
10: #include <asm/segment.h>
11:
12: #include <string.h>
13: #include <fcntl.h>
14: #include <errno.h>
15: #include <const.h>
16: #include <sys/stat.h>
17:
18: extern int permission(struct inode * inode,int mask);
19: extern struct inode * _namei(const char * filename, struct inode * base,
20: int follow_links);
21:
22: /*
23: * comment out this line if you want names > MINIX_NAME_LEN chars to be
24: * truncated. Else they will be disallowed.
25: */
26: /* #define NO_TRUNCATE */
27:
28: /*
29: * ok, we cannot use strncmp, as the name is not in our data space.
30: * Thus we'll have to use minix_match. No big problem. Match also makes
31: * some sanity tests.
32: *
33: * NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure.
34: */
35: static int minix_match(int len,const char * name,struct minix_dir_entry * de)
36: {
37: register int same __asm__("ax");
38:
39: if (!de || !de->inode || len > MINIX_NAME_LEN)
40: return 0;
41: /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
42: if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
43: return 1;
44: if (len < MINIX_NAME_LEN && de->name[len])
45: return 0;
46: __asm__("cld\n\t"
47: "fs ; repe ; cmpsb\n\t"
48: "setz %%al"
49: :"=a" (same)
50: :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
51: :"cx","di","si");
52: return same;
53: }
54:
55: /*
56: * minix_find_entry()
57: *
58: * finds an entry in the specified directory with the wanted name. It
59: * returns the cache buffer in which the entry was found, and the entry
60: * itself (as a parameter - res_dir). It does NOT read the inode of the
61: * entry - you'll have to do that yourself if you want to.
62: */
63: static struct buffer_head * minix_find_entry(struct inode * dir,
64: const char * name, int namelen, struct minix_dir_entry ** res_dir)
65: {
66: int entries;
67: int block,i;
68: struct buffer_head * bh;
69: struct minix_dir_entry * de;
70:
71: *res_dir = NULL;
72: if (!dir)
73: return NULL;
74: #ifdef NO_TRUNCATE
75: if (namelen > MINIX_NAME_LEN)
76: return NULL;
77: #else
78: if (namelen > MINIX_NAME_LEN)
79: namelen = MINIX_NAME_LEN;
80: #endif
81: entries = dir->i_size / (sizeof (struct minix_dir_entry));
82: if (!(block = dir->i_data[0]))
83: return NULL;
84: if (!(bh = bread(dir->i_dev,block)))
85: return NULL;
86: i = 0;
87: de = (struct minix_dir_entry *) bh->b_data;
88: while (i < entries) {
89: if ((char *)de >= BLOCK_SIZE+bh->b_data) {
90: brelse(bh);
91: bh = NULL;
92: if (!(block = bmap(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK)) ||
93: !(bh = bread(dir->i_dev,block))) {
94: i += MINIX_DIR_ENTRIES_PER_BLOCK;
95: continue;
96: }
97: de = (struct minix_dir_entry *) bh->b_data;
98: }
99: if (minix_match(namelen,name,de)) {
100: *res_dir = de;
101: return bh;
102: }
103: de++;
104: i++;
105: }
106: brelse(bh);
107: return NULL;
108: }
109:
110: struct inode * minix_follow_link(struct inode * dir, struct inode * inode)
111: {
112: unsigned short fs;
113: struct buffer_head * bh;
114:
115: if (!dir) {
116: dir = current->root;
117: dir->i_count++;
118: }
119: if (!inode) {
120: iput(dir);
121: return NULL;
122: }
123: if (!S_ISLNK(inode->i_mode)) {
124: iput(dir);
125: return inode;
126: }
127: __asm__("mov %%fs,%0":"=r" (fs));
128: if ((current->link_count > 5) || !inode->i_data[0] ||
129: !(bh = bread(inode->i_dev, inode->i_data[0]))) {
130: iput(dir);
131: iput(inode);
132: return NULL;
133: }
134: iput(inode);
135: __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
136: current->link_count++;
137: inode = _namei(bh->b_data,dir,1);
138: current->link_count--;
139: __asm__("mov %0,%%fs"::"r" (fs));
140: brelse(bh);
141: return inode;
142: }
143:
144: int minix_lookup(struct inode * dir,const char * name, int len,
145: struct inode ** result)
146: {
147: int ino;
148: struct minix_dir_entry * de;
149: struct buffer_head * bh;
150:
151: *result = NULL;
152: if (!dir)
153: return -ENOENT;
154: if (!S_ISDIR(dir->i_mode)) {
155: iput(dir);
156: return -ENOENT;
157: }
158: if (!(bh = minix_find_entry(dir,name,len,&de))) {
159: iput(dir);
160: return -ENOENT;
161: }
162: ino = de->inode;
163: brelse(bh);
164: if (!(*result = iget(dir->i_dev,ino))) {
165: iput(dir);
166: return -EACCES;
167: }
168: iput(dir);
169: return 0;
170: }
171:
172: /*
173: * minix_add_entry()
174: *
175: * adds a file entry to the specified directory, using the same
176: * semantics as minix_find_entry(). It returns NULL if it failed.
177: *
178: * NOTE!! The inode part of 'de' is left at 0 - which means you
179: * may not sleep between calling this and putting something into
180: * the entry, as someone else might have used it while you slept.
181: */
182: static struct buffer_head * minix_add_entry(struct inode * dir,
183: const char * name, int namelen, struct minix_dir_entry ** res_dir)
184: {
185: int block,i;
186: struct buffer_head * bh;
187: struct minix_dir_entry * de;
188:
189: *res_dir = NULL;
190: if (!dir)
191: return NULL;
192: #ifdef NO_TRUNCATE
193: if (namelen > MINIX_NAME_LEN)
194: return NULL;
195: #else
196: if (namelen > MINIX_NAME_LEN)
197: namelen = MINIX_NAME_LEN;
198: #endif
199: if (!namelen)
200: return NULL;
201: if (!(block = dir->i_data[0]))
202: return NULL;
203: if (!(bh = bread(dir->i_dev,block)))
204: return NULL;
205: i = 0;
206: de = (struct minix_dir_entry *) bh->b_data;
207: while (1) {
208: if ((char *)de >= BLOCK_SIZE+bh->b_data) {
209: brelse(bh);
210: bh = NULL;
211: block = minix_create_block(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK);
212: if (!block)
213: return NULL;
214: if (!(bh = bread(dir->i_dev,block))) {
215: i += MINIX_DIR_ENTRIES_PER_BLOCK;
216: continue;
217: }
218: de = (struct minix_dir_entry *) bh->b_data;
219: }
220: if (i*sizeof(struct minix_dir_entry) >= dir->i_size) {
221: de->inode=0;
222: dir->i_size = (i+1)*sizeof(struct minix_dir_entry);
223: dir->i_dirt = 1;
224: dir->i_ctime = CURRENT_TIME;
225: }
226: if (!de->inode) {
227: dir->i_mtime = CURRENT_TIME;
228: for (i=0; i < MINIX_NAME_LEN ; i++)
229: de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
230: bh->b_dirt = 1;
231: *res_dir = de;
232: return bh;
233: }
234: de++;
235: i++;
236: }
237: brelse(bh);
238: return NULL;
239: }
240:
241: int minix_create(struct inode * dir,const char * name, int len, int mode,
242: struct inode ** result)
243: {
244: struct inode * inode;
245: struct buffer_head * bh;
246: struct minix_dir_entry * de;
247:
248: *result = NULL;
249: if (!dir)
250: return -ENOENT;
251: inode = minix_new_inode(dir->i_dev);
252: if (!inode) {
253: iput(dir);
254: return -ENOSPC;
255: }
256: inode->i_mode = mode;
257: inode->i_dirt = 1;
258: bh = minix_add_entry(dir,name,len,&de);
259: if (!bh) {
260: inode->i_nlink--;
261: iput(inode);
262: iput(dir);
263: return -ENOSPC;
264: }
265: de->inode = inode->i_ino;
266: bh->b_dirt = 1;
267: brelse(bh);
268: iput(dir);
269: *result = inode;
270: return 0;
271: }
272:
273: int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
274: {
275: struct inode * inode;
276: struct buffer_head * bh;
277: struct minix_dir_entry * de;
278:
279: if (!dir)
280: return -ENOENT;
281: bh = minix_find_entry(dir,name,len,&de);
282: if (bh) {
283: brelse(bh);
284: iput(dir);
285: return -EEXIST;
286: }
287: inode = minix_new_inode(dir->i_dev);
288: if (!inode) {
289: iput(dir);
290: return -ENOSPC;
291: }
292: inode->i_uid = current->euid;
293: inode->i_mode = mode;
294: if (S_ISBLK(mode) || S_ISCHR(mode))
295: inode->i_rdev = rdev;
296: inode->i_mtime = inode->i_atime = CURRENT_TIME;
297: inode->i_dirt = 1;
298: bh = minix_add_entry(dir,name,len,&de);
299: if (!bh) {
300: inode->i_nlink--;
301: iput(inode);
302: iput(dir);
303: return -ENOSPC;
304: }
305: de->inode = inode->i_ino;
306: bh->b_dirt = 1;
307: brelse(bh);
308: iput(dir);
309: iput(inode);
310: return 0;
311: }
312:
313: int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
314: {
315: struct inode * inode;
316: struct buffer_head * bh, *dir_block;
317: struct minix_dir_entry * de;
318:
319: bh = minix_find_entry(dir,name,len,&de);
320: if (bh) {
321: brelse(bh);
322: iput(dir);
323: return -EEXIST;
324: }
325: inode = minix_new_inode(dir->i_dev);
326: if (!inode) {
327: iput(dir);
328: return -ENOSPC;
329: }
330: inode->i_size = 32;
331: inode->i_dirt = 1;
332: inode->i_mtime = inode->i_atime = CURRENT_TIME;
333: if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) {
334: iput(dir);
335: inode->i_nlink--;
336: iput(inode);
337: return -ENOSPC;
338: }
339: inode->i_dirt = 1;
340: if (!(dir_block = bread(inode->i_dev,inode->i_data[0]))) {
341: iput(dir);
342: inode->i_nlink--;
343: iput(inode);
344: return -ERROR;
345: }
346: de = (struct minix_dir_entry *) dir_block->b_data;
347: de->inode=inode->i_ino;
348: strcpy(de->name,".");
349: de++;
350: de->inode = dir->i_ino;
351: strcpy(de->name,"..");
352: inode->i_nlink = 2;
353: dir_block->b_dirt = 1;
354: brelse(dir_block);
355: inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask);
356: inode->i_dirt = 1;
357: bh = minix_add_entry(dir,name,len,&de);
358: if (!bh) {
359: iput(dir);
360: inode->i_nlink=0;
361: iput(inode);
362: return -ENOSPC;
363: }
364: de->inode = inode->i_ino;
365: bh->b_dirt = 1;
366: dir->i_nlink++;
367: dir->i_dirt = 1;
368: iput(dir);
369: iput(inode);
370: brelse(bh);
371: return 0;
372: }
373:
374: /*
375: * routine to check that the specified directory is empty (for rmdir)
376: */
377: static int empty_dir(struct inode * inode)
378: {
379: int nr,block;
380: int len;
381: struct buffer_head * bh;
382: struct minix_dir_entry * de;
383:
384: len = inode->i_size / sizeof (struct minix_dir_entry);
385: if (len<2 || !inode->i_data[0] ||
386: !(bh=bread(inode->i_dev,inode->i_data[0]))) {
387: printk("warning - bad directory on dev %04x\n",inode->i_dev);
388: return 0;
389: }
390: de = (struct minix_dir_entry *) bh->b_data;
391: if (de[0].inode != inode->i_ino || !de[1].inode ||
392: strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
393: printk("warning - bad directory on dev %04x\n",inode->i_dev);
394: return 0;
395: }
396: nr = 2;
397: de += 2;
398: while (nr<len) {
399: if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
400: brelse(bh);
401: block=bmap(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK);
402: if (!block) {
403: nr += MINIX_DIR_ENTRIES_PER_BLOCK;
404: continue;
405: }
406: if (!(bh=bread(inode->i_dev,block)))
407: return 0;
408: de = (struct minix_dir_entry *) bh->b_data;
409: }
410: if (de->inode) {
411: brelse(bh);
412: return 0;
413: }
414: de++;
415: nr++;
416: }
417: brelse(bh);
418: return 1;
419: }
420:
421: int minix_rmdir(struct inode * dir, const char * name, int len)
422: {
423: int retval;
424: struct inode * inode;
425: struct buffer_head * bh;
426: struct minix_dir_entry * de;
427:
428: inode = NULL;
429: bh = minix_find_entry(dir,name,len,&de);
430: retval = -ENOENT;
431: if (!bh)
432: goto end_rmdir;
433: retval = -EPERM;
434: if (!(inode = iget(dir->i_dev, de->inode)))
435: goto end_rmdir;
436: if ((dir->i_mode & S_ISVTX) && current->euid &&
437: inode->i_uid != current->euid)
438: goto end_rmdir;
439: if (inode->i_dev != dir->i_dev)
440: goto end_rmdir;
441: if (inode == dir) /* we may not delete ".", but "../dir" is ok */
442: goto end_rmdir;
443: if (!S_ISDIR(inode->i_mode)) {
444: retval = -ENOTDIR;
445: goto end_rmdir;
446: }
447: if (!empty_dir(inode)) {
448: retval = -ENOTEMPTY;
449: goto end_rmdir;
450: }
451: if (inode->i_count > 1) {
452: retval = -EBUSY;
453: goto end_rmdir;
454: }
455: if (inode->i_nlink != 2)
456: printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
457: de->inode = 0;
458: bh->b_dirt = 1;
459: inode->i_nlink=0;
460: inode->i_dirt=1;
461: dir->i_nlink--;
462: dir->i_ctime = dir->i_mtime = CURRENT_TIME;
463: dir->i_dirt=1;
464: retval = 0;
465: end_rmdir:
466: iput(dir);
467: iput(inode);
468: brelse(bh);
469: return retval;
470: }
471:
472: int minix_unlink(struct inode * dir, const char * name, int len)
473: {
474: int retval;
475: struct inode * inode;
476: struct buffer_head * bh;
477: struct minix_dir_entry * de;
478:
479: retval = -ENOENT;
480: inode = NULL;
481: bh = minix_find_entry(dir,name,len,&de);
482: if (!bh)
483: goto end_unlink;
484: if (!(inode = iget(dir->i_dev, de->inode)))
485: goto end_unlink;
486: retval = -EPERM;
487: if ((dir->i_mode & S_ISVTX) && !suser() &&
488: current->euid != inode->i_uid &&
489: current->euid != dir->i_uid)
490: goto end_unlink;
491: if (S_ISDIR(inode->i_mode))
492: goto end_unlink;
493: if (!inode->i_nlink) {
494: printk("Deleting nonexistent file (%04x:%d), %d\n",
495: inode->i_dev,inode->i_ino,inode->i_nlink);
496: inode->i_nlink=1;
497: }
498: de->inode = 0;
499: bh->b_dirt = 1;
500: inode->i_nlink--;
501: inode->i_dirt = 1;
502: inode->i_ctime = CURRENT_TIME;
503: retval = 0;
504: end_unlink:
505: brelse(bh);
506: iput(inode);
507: iput(dir);
508: return retval;
509: }
510:
511: int minix_symlink(struct inode * dir, const char * name, int len, const char * symname)
512: {
513: struct minix_dir_entry * de;
514: struct inode * inode = NULL;
515: struct buffer_head * bh = NULL, * name_block = NULL;
516: int i;
517: char c;
518:
519: if (!(inode = minix_new_inode(dir->i_dev))) {
520: iput(dir);
521: return -ENOSPC;
522: }
523: inode->i_mode = S_IFLNK | 0777;
524: inode->i_dirt = 1;
525: if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) {
526: iput(dir);
527: inode->i_nlink--;
528: iput(inode);
529: return -ENOSPC;
530: }
531: inode->i_dirt = 1;
532: if (!(name_block = bread(inode->i_dev,inode->i_data[0]))) {
533: iput(dir);
534: inode->i_nlink--;
535: iput(inode);
536: return -ERROR;
537: }
538: i = 0;
539: while (i < 1023 && (c=get_fs_byte(symname++)))
540: name_block->b_data[i++] = c;
541: name_block->b_data[i] = 0;
542: name_block->b_dirt = 1;
543: brelse(name_block);
544: inode->i_size = i;
545: inode->i_dirt = 1;
546: bh = minix_find_entry(dir,name,len,&de);
547: if (bh) {
548: inode->i_nlink--;
549: iput(inode);
550: brelse(bh);
551: iput(dir);
552: return -EEXIST;
553: }
554: bh = minix_add_entry(dir,name,len,&de);
555: if (!bh) {
556: inode->i_nlink--;
557: iput(inode);
558: iput(dir);
559: return -ENOSPC;
560: }
561: de->inode = inode->i_ino;
562: bh->b_dirt = 1;
563: brelse(bh);
564: iput(dir);
565: iput(inode);
566: return 0;
567: }
568:
569: int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
570: {
571: struct minix_dir_entry * de;
572: struct buffer_head * bh;
573:
574: if (S_ISDIR(oldinode->i_mode)) {
575: iput(oldinode);
576: iput(dir);
577: return -EPERM;
578: }
579: bh = minix_find_entry(dir,name,len,&de);
580: if (bh) {
581: brelse(bh);
582: iput(dir);
583: iput(oldinode);
584: return -EEXIST;
585: }
586: bh = minix_add_entry(dir,name,len,&de);
587: if (!bh) {
588: iput(dir);
589: iput(oldinode);
590: return -ENOSPC;
591: }
592: de->inode = oldinode->i_ino;
593: bh->b_dirt = 1;
594: brelse(bh);
595: iput(dir);
596: oldinode->i_nlink++;
597: oldinode->i_ctime = CURRENT_TIME;
598: oldinode->i_dirt = 1;
599: iput(oldinode);
600: return 0;
601: }
602:
603: static int subdir(struct inode * new, struct inode * old)
604: {
605: unsigned short fs;
606: int ino;
607: int result;
608:
609: __asm__("mov %%fs,%0":"=r" (fs));
610: __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
611: new->i_count++;
612: result = 0;
613: for (;;) {
614: if (new == old) {
615: result = 1;
616: break;
617: }
618: if (new->i_dev != old->i_dev)
619: break;
620: ino = new->i_ino;
621: if (minix_lookup(new,"..",2,&new))
622: break;
623: if (new->i_ino == ino)
624: break;
625: }
626: iput(new);
627: __asm__("mov %0,%%fs"::"r" (fs));
628: return result;
629: }
630:
631: #define PARENT_INO(buffer) \
632: (((struct minix_dir_entry *) (buffer))[1].inode)
633:
634: #define PARENT_NAME(buffer) \
635: (((struct minix_dir_entry *) (buffer))[1].name)
636:
637: /*
638: * rename uses retrying to avoid race-conditions: at least they should be minimal.
639: * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
640: * checks fail, it tries to restart itself again. Very practical - no changes
641: * are done until we know everything works ok.. and then all the changes can be
642: * done in one fell swoop when we have claimed all the buffers needed.
643: *
644: * Anybody can rename anything with this: the permission checks are left to the
645: * higher-level routines.
646: */
647: static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
648: struct inode * new_dir, const char * new_name, int new_len)
649: {
650: struct inode * old_inode, * new_inode;
651: struct buffer_head * old_bh, * new_bh, * dir_bh;
652: struct minix_dir_entry * old_de, * new_de;
653: int retval;
654:
655: goto start_up;
656: try_again:
657: brelse(old_bh);
658: brelse(new_bh);
659: brelse(dir_bh);
660: iput(old_inode);
661: iput(new_inode);
662: current->counter = 0;
663: schedule();
664: start_up:
665: old_inode = new_inode = NULL;
666: old_bh = new_bh = dir_bh = NULL;
667: old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de);
668: retval = -ENOENT;
669: if (!old_bh)
670: goto end_rename;
671: old_inode = iget(old_dir->i_dev, old_de->inode);
672: if (!old_inode)
673: goto end_rename;
674: new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
675: if (new_bh) {
676: new_inode = iget(new_dir->i_dev, new_de->inode);
677: if (!new_inode) {
678: brelse(new_bh);
679: new_bh = NULL;
680: }
681: }
682: if (new_inode == old_inode) {
683: retval = 0;
684: goto end_rename;
685: }
686: if (S_ISDIR(old_inode->i_mode)) {
687: retval = -EEXIST;
688: if (new_bh)
689: goto end_rename;
690: retval = -EACCES;
691: if (!permission(old_inode, MAY_WRITE))
692: goto end_rename;
693: retval = -EINVAL;
694: if (subdir(new_dir, old_inode))
695: goto end_rename;
696: retval = -EIO;
697: if (!old_inode->i_data[0])
698: goto end_rename;
699: if (!(dir_bh = bread(old_inode->i_dev, old_inode->i_data[0])))
700: goto end_rename;
701: if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
702: goto end_rename;
703: }
704: if (!new_bh)
705: new_bh = minix_add_entry(new_dir,new_name,new_len,&new_de);
706: retval = -ENOSPC;
707: if (!new_bh)
708: goto end_rename;
709: /* sanity checking before doing the rename - avoid races */
710: if (new_inode && (new_de->inode != new_inode->i_ino))
711: goto try_again;
712: if (new_de->inode && !new_inode)
713: goto try_again;
714: if (old_de->inode != old_inode->i_ino)
715: goto try_again;
716: /* ok, that's it */
717: old_de->inode = 0;
718: new_de->inode = old_inode->i_ino;
719: if (new_inode)
720: new_inode->i_nlink--;
721: old_bh->b_dirt = 1;
722: new_bh->b_dirt = 1;
723: if (dir_bh) {
724: PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
725: dir_bh->b_dirt = 1;
726: old_dir->i_nlink--;
727: new_dir->i_nlink++;
728: old_dir->i_dirt = 1;
729: new_dir->i_dirt = 1;
730: }
731: retval = 0;
732: end_rename:
733: brelse(dir_bh);
734: brelse(old_bh);
735: brelse(new_bh);
736: iput(old_inode);
737: iput(new_inode);
738: iput(old_dir);
739: iput(new_dir);
740: return retval;
741: }
742:
743: /*
744: * Ok, rename also locks out other renames, as they can change the parent of
745: * a directory, and we don't want any races. Other races are checked for by
746: * "do_rename()", which restarts if there are inconsistencies.
747: *
748: * Note that there is no race between different filesystems: it's only within
749: * the same device that races occur: many renames can happen at once, as long
750: * as they are on different partitions.
751: */
752: int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
753: struct inode * new_dir, const char * new_name, int new_len)
754: {
755: static struct task_struct * wait = NULL;
756: static int lock = 0;
757: int result;
758:
759: while (lock)
760: sleep_on(&wait);
761: lock = 1;
762: result = do_minix_rename(old_dir, old_name, old_len,
763: new_dir, new_name, new_len);
764: lock = 0;
765: wake_up(&wait);
766: return result;
767: }
768:
769: int minix_readlink(struct inode * inode, char * buffer, int buflen)
770: {
771: struct buffer_head * bh;
772: int i;
773: char c;
774:
775: if (!S_ISLNK(inode->i_mode)) {
776: iput(inode);
777: return -EINVAL;
778: }
779: if (buflen > 1023)
780: buflen = 1023;
781: if (inode->i_data[0])
782: bh = bread(inode->i_dev, inode->i_data[0]);
783: else
784: bh = NULL;
785: iput(inode);
786: if (!bh)
787: return 0;
788: i = 0;
789: while (i<buflen && (c = bh->b_data[i])) {
790: i++;
791: put_fs_byte(c,buffer++);
792: }
793: brelse(bh);
794: return i;
795: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.