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