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