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