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