|
|
1.1 root 1: /*
2: * linux/fs/msdos/namei.c
3: *
4: * Written 1992 by Werner Almesberger
5: */
6:
7: #include <asm/segment.h>
8:
9: #include <linux/sched.h>
10: #include <linux/msdos_fs.h>
11: #include <linux/kernel.h>
12: #include <linux/errno.h>
13: #include <linux/string.h>
14: #include <linux/stat.h>
15:
16: /* MS-DOS "device special files" */
17:
18: static char *reserved_names[] = {
19: "CON ","PRN ","NUL ","AUX ",
20: "LPT1 ","LPT2 ","LPT3 ","LPT4 ",
21: "COM1 ","COM2 ","COM3 ","COM4 ",
22: NULL };
23:
24:
25: /* Formats an MS-DOS file name. Rejects invalid names. */
26:
27: static int msdos_format_name(char conv,const char *name,int len,char *res)
28: {
29: char *walk,**reserved;
30: char c;
31: int space;
32:
33: if (get_fs_byte(name) == DELETED_FLAG) return -EINVAL;
34: if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 &&
35: get_fs_byte(name+1) == '.'))) {
36: memset(res+1,' ',10);
37: while (len--) *res++ = '.';
38: return 0;
39: }
40: space = 0; /* to make GCC happy */
41: c = 0;
42: for (walk = res; len && walk-res < 8; walk++) {
43: c = get_fs_byte(name++);
44: len--;
45: if (c == ' ' && conv != 'r') return -EINVAL;
46: if (c >= 'A' && c <= 'Z') {
47: if (conv != 'r') return -EINVAL;
48: c += 32;
49: }
50: if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
51: if (c == '.') break;
52: space = c == ' ';
53: *walk = c >= 'a' && c <= 'z' ? c-32 : c;
54: }
55: if (space) return -EINVAL;
56: if (conv == 's' && len && c != '.') {
57: c = get_fs_byte(name++);
58: len--;
59: if (c != '.') return -EINVAL;
60: }
61: while (c != '.' && len--) c = get_fs_byte(name++);
62: if (walk == res) return -EINVAL;
63: if (c == '.') {
64: while (walk-res < 8) *walk++ = ' ';
65: while (len > 0 && walk-res < MSDOS_NAME) {
66: c = get_fs_byte(name++);
67: len--;
68: if (c == ' ' && conv != 'r') return -EINVAL;
69: if (c < ' ' || c == ':' || c == '\\' || c == '.')
70: return -EINVAL;
71: if (c >= 'A' && c <= 'Z') {
72: if (conv != 'r') return -EINVAL;
73: c += 32;
74: }
75: space = c == ' ';
76: *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
77: }
78: if (space) return -EINVAL;
79: if (conv == 's' && len) return -EINVAL;
80: }
81: while (walk-res < MSDOS_NAME) *walk++ = ' ';
82: for (reserved = reserved_names; *reserved; reserved++)
83: if (!strncmp(res,*reserved,8)) return -EINVAL;
84: return 0;
85: }
86:
87:
88: /* Locates a directory entry. */
89:
90: static int msdos_find(struct inode *dir,const char *name,int len,
91: struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
92: {
93: char msdos_name[MSDOS_NAME];
94: int res;
95:
96: if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
97: msdos_name)) < 0) return res;
98: return msdos_scan(dir,msdos_name,bh,de,ino);
99: }
100:
101:
102: int msdos_lookup(struct inode *dir,const char *name,int len,
103: struct inode **result)
104: {
105: int ino,res;
106: struct msdos_dir_entry *de;
107: struct buffer_head *bh;
108: struct inode *next;
109:
110: *result = NULL;
111: if (!dir) return -ENOENT;
112: if (!S_ISDIR(dir->i_mode)) {
113: iput(dir);
114: return -ENOENT;
115: }
116: if (len == 1 && get_fs_byte(name) == '.') {
117: *result = dir;
118: return 0;
119: }
120: if (len == 2 && get_fs_byte(name) == '.' && get_fs_byte(name+1) == '.')
121: {
122: ino = msdos_parent_ino(dir,0);
123: iput(dir);
124: if (ino < 0) return ino;
125: if (!(*result = iget(dir->i_dev,ino))) return -EACCES;
126: return 0;
127: }
128: if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
129: iput(dir);
130: return res;
131: }
132: if (bh) brelse(bh);
133: /* printk("lookup: ino=%d\r\n",ino); */
134: if (!(*result = iget(dir->i_dev,ino))) {
135: iput(dir);
136: return -EACCES;
137: }
138: if ((*result)->i_data[D_BUSY]) { /* mkdir in progress */
139: iput(*result);
140: iput(dir);
141: return -ENOENT;
142: }
143: while ((*result)->i_data[D_OLD]) {
144: next = (struct inode *) ((*result)->i_data[D_OLD]);
145: iput(*result);
146: if (!(*result = iget(next->i_dev,next->i_ino)))
147: panic("msdos_lookup: Can't happen");
148: }
149: iput(dir);
150: return 0;
151: }
152:
153:
154: /* Creates a directory entry (name is already formatted). */
155:
156: static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
157: struct inode **result)
158: {
159: struct buffer_head *bh;
160: struct msdos_dir_entry *de;
161: int res,ino;
162:
163: if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) {
164: if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
165: if ((res = msdos_add_cluster(dir)) < 0) return res;
166: if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res;
167: }
168: memcpy(de->name,name,MSDOS_NAME);
169: de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
170: de->start = 0;
171: date_unix2dos(CURRENT_TIME,&de->time,&de->date);
172: de->size = 0;
173: bh->b_dirt = 1;
174: if (*result = iget(dir->i_dev,ino)) msdos_read_inode(*result);
175: brelse(bh);
176: if (!*result) return -EIO;
177: (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
178: CURRENT_TIME;
179: (*result)->i_dirt = 1;
180: return 0;
181: }
182:
183:
184: int msdos_create(struct inode *dir,const char *name,int len,int mode,
185: struct inode **result)
186: {
187: struct buffer_head *bh;
188: struct msdos_dir_entry *de;
189: char msdos_name[MSDOS_NAME];
190: int ino,res;
191:
192: if (!dir) return -ENOENT;
193: if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
194: msdos_name)) < 0) {
195: iput(dir);
196: return res;
197: }
198: lock_creation();
199: if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
200: unlock_creation();
201: brelse(bh);
202: iput(dir);
203: return -EEXIST;
204: }
205: res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),result);
206: unlock_creation();
207: iput(dir);
208: return res;
209: }
210:
211:
212: int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
213: {
214: struct buffer_head *bh;
215: struct msdos_dir_entry *de;
216: struct inode *inode,*dot;
217: char msdos_name[MSDOS_NAME];
218: int ino,res;
219:
220: if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
221: msdos_name)) < 0) {
222: iput(dir);
223: return res;
224: }
225: lock_creation();
226: if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
227: unlock_creation();
228: brelse(bh);
229: iput(dir);
230: return -EEXIST;
231: }
232: if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) {
233: unlock_creation();
234: iput(dir);
235: return res;
236: }
237: inode->i_data[D_BUSY] = 1; /* prevent lookups */
238: if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error;
239: if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0)
240: goto mkdir_error;
241: dot->i_size = inode->i_size;
242: dot->i_data[D_START] = inode->i_data[D_START];
243: dot->i_dirt = 1;
244: iput(dot);
245: if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0)
246: goto mkdir_error;
247: unlock_creation();
248: dot->i_size = dir->i_size;
249: dot->i_data[D_START] = dir->i_data[D_START];
250: dot->i_dirt = 1;
251: inode->i_data[D_BUSY] = 0;
252: iput(dot);
253: iput(inode);
254: iput(dir);
255: return 0;
256: mkdir_error:
257: iput(inode);
258: if (msdos_rmdir(dir,name,len) < 0) panic("rmdir in mkdir failed");
259: unlock_creation();
260: return res;
261: }
262:
263:
264: int msdos_rmdir(struct inode *dir,const char *name,int len)
265: {
266: int res,ino,pos;
267: struct buffer_head *bh,*dbh;
268: struct msdos_dir_entry *de,*dde;
269: struct inode *inode;
270:
271: bh = NULL;
272: inode = NULL;
273: res = -EINVAL;
274: if (len == 1 && get_fs_byte(name) == '.') goto rmdir_done;
275: if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
276: res = -ENOENT;
277: if (!(inode = iget(dir->i_dev,ino))) goto rmdir_done;
278: res = -ENOTDIR;
279: if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
280: res = -EBUSY;
281: if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
282: if (inode->i_count > 1) goto rmdir_done;
283: if (inode->i_data[D_START]) { /* may be zero in mkdir */
284: res = -ENOTEMPTY;
285: pos = 0;
286: dbh = NULL;
287: while (msdos_get_entry(inode,&pos,&dbh,&dde) > -1)
288: if (dde->name[0] && ((unsigned char *) dde->name)[0] !=
289: DELETED_FLAG && strncmp(dde->name,MSDOS_DOT,
290: MSDOS_NAME) && strncmp(dde->name,MSDOS_DOTDOT,
291: MSDOS_NAME)) goto rmdir_done;
292: if (dbh) brelse(dbh);
293: }
294: inode->i_nlink = 0;
295: dir->i_mtime = CURRENT_TIME;
296: inode->i_dirt = dir->i_dirt = 1;
297: de->name[0] = DELETED_FLAG;
298: bh->b_dirt = 1;
299: res = 0;
300: rmdir_done:
301: brelse(bh);
302: iput(dir);
303: iput(inode);
304: return res;
305: }
306:
307:
308: int msdos_unlink(struct inode *dir,const char *name,int len)
309: {
310: int res,ino;
311: struct buffer_head *bh;
312: struct msdos_dir_entry *de;
313: struct inode *inode;
314:
315: bh = NULL;
316: inode = NULL;
317: if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
318: goto unlink_done;
319: if (!(inode = iget(dir->i_dev,ino))) {
320: res = -ENOENT;
321: goto unlink_done;
322: }
323: if (!S_ISREG(inode->i_mode)) {
324: res = -EPERM;
325: goto unlink_done;
326: }
327: inode->i_nlink = 0;
328: inode->i_data[D_BUSY] = 1;
329: inode->i_dirt = 1;
330: de->name[0] = DELETED_FLAG;
331: bh->b_dirt = 1;
332: unlink_done:
333: brelse(bh);
334: iput(inode);
335: iput(dir);
336: return res;
337: }
338:
339:
340: static int rename_same_dir(struct inode *old_dir,char *old_name,
341: struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
342: struct msdos_dir_entry *old_de,int old_ino)
343: {
344: struct buffer_head *new_bh;
345: struct msdos_dir_entry *new_de;
346: struct inode *new_inode,*old_inode;
347: int new_ino;
348: int exists;
349:
350: if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0;
351: exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
352: if (*(unsigned char *) old_de->name == DELETED_FLAG) {
353: if (exists) brelse(new_bh);
354: return -ENOENT;
355: }
356: if (exists) {
357: if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
358: brelse(new_bh);
359: return -EIO;
360: }
361: if (S_ISDIR(new_inode->i_mode)) {
362: iput(new_inode);
363: brelse(new_bh);
364: return -EPERM;
365: }
366: new_inode->i_nlink = 0;
367: new_inode->i_data[D_BUSY] = 1;
368: new_inode->i_dirt = 1;
369: new_de->name[0] = DELETED_FLAG;
370: new_bh->b_dirt = 1;
371: iput(new_inode);
372: brelse(new_bh);
373: }
374: memcpy(old_de->name,new_name,MSDOS_NAME);
375: old_bh->b_dirt = 1;
376: if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */
377: if (old_inode = iget(old_dir->i_dev,old_ino)) {
378: msdos_read_inode(old_inode);
379: iput(old_inode);
380: }
381: return 0;
382: }
383:
384:
385: static int rename_diff_dir(struct inode *old_dir,char *old_name,
386: struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
387: struct msdos_dir_entry *old_de,int old_ino)
388: {
389: struct buffer_head *new_bh,*free_bh,*dotdot_bh;
390: struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
391: struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
392: int new_ino,free_ino,dotdot_ino;
393: int error,exists,ino;
394:
395: if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
396: if (old_ino == new_dir->i_ino) return -EINVAL;
397: if (!(walk = iget(new_dir->i_dev,new_dir->i_ino))) return -EIO;
398: while (walk->i_ino != MSDOS_ROOT_INO) {
399: ino = msdos_parent_ino(walk,1);
400: iput(walk);
401: if (ino < 0) return ino;
402: if (ino == old_ino) return -EINVAL;
403: if (!(walk = iget(new_dir->i_dev,ino))) return -EIO;
404: }
405: iput(walk);
406: if ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) < 0)
407: return error;
408: exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)
409: >= 0;
410: if (!(old_inode = iget(old_dir->i_dev,old_ino))) {
411: brelse(free_bh);
412: if (exists) brelse(new_bh);
413: return -EIO;
414: }
415: if (*(unsigned char *) old_de->name == DELETED_FLAG) {
416: iput(old_inode);
417: brelse(free_bh);
418: if (exists) brelse(new_bh);
419: return -ENOENT;
420: }
421: new_inode = NULL; /* to make GCC happy */
422: if (exists) {
423: if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
424: iput(old_inode);
425: brelse(new_bh);
426: return -EIO;
427: }
428: if (S_ISDIR(new_inode->i_mode)) {
429: iput(new_inode);
430: iput(old_inode);
431: brelse(new_bh);
432: return -EPERM;
433: }
434: new_inode->i_nlink = 0;
435: new_inode->i_data[D_BUSY] = 1;
436: new_inode->i_dirt = 1;
437: new_de->name[0] = DELETED_FLAG;
438: new_bh->b_dirt = 1;
439: }
440: memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
441: memcpy(free_de->name,new_name,MSDOS_NAME);
442: if (!(free_inode = iget(new_dir->i_dev,free_ino))) {
443: free_de->name[0] = DELETED_FLAG;
444: /* Don't mark free_bh as dirty. Both states are supposed to be equivalent. */
445: brelse(free_bh);
446: if (exists) {
447: iput(new_inode);
448: brelse(new_bh);
449: }
450: return -EIO;
451: }
452: msdos_read_inode(free_inode);
453: old_inode->i_data[D_BUSY] = 1;
454: old_inode->i_dirt = 1;
455: old_de->name[0] = DELETED_FLAG;
456: old_bh->b_dirt = 1;
457: free_bh->b_dirt = 1;
458: if (!exists) iput(free_inode);
459: else {
460: new_inode->i_data[D_DEPEND] = (int) free_inode;
461: free_inode->i_data[D_OLD] = (int) new_inode;
462: /* free_inode is put when putting new_inode */
463: iput(new_inode);
464: brelse(new_bh);
465: }
466: if (S_ISDIR(old_inode->i_mode)) {
467: if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
468: &dotdot_de,&dotdot_ino)) < 0) goto rename_done;
469: if (!(dotdot_inode = iget(old_inode->i_dev,dotdot_ino))) {
470: brelse(dotdot_bh);
471: error = -EIO;
472: goto rename_done;
473: }
474: dotdot_de->start = dotdot_inode->i_data[D_START] =
475: new_dir->i_data[D_START];
476: dotdot_inode->i_dirt = 1;
477: dotdot_bh->b_dirt = 1;
478: iput(dotdot_inode);
479: brelse(dotdot_bh);
480: }
481: error = 0;
482: rename_done:
483: brelse(free_bh);
484: iput(old_inode);
485: return error;
486: }
487:
488:
489: int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
490: struct inode *new_dir,const char *new_name,int new_len)
491: {
492: char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
493: struct buffer_head *old_bh;
494: struct msdos_dir_entry *old_de;
495: int old_ino,error;
496:
497: if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
498: old_name,old_len,old_msdos_name)) < 0) goto rename_done;
499: if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
500: new_name,new_len,new_msdos_name)) < 0) goto rename_done;
501: if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de,
502: &old_ino)) < 0) goto rename_done;
503: lock_creation();
504: if (old_dir == new_dir)
505: error = rename_same_dir(old_dir,old_msdos_name,new_dir,
506: new_msdos_name,old_bh,old_de,old_ino);
507: else error = rename_diff_dir(old_dir,old_msdos_name,new_dir,
508: new_msdos_name,old_bh,old_de,old_ino);
509: unlock_creation();
510: brelse(old_bh);
511: rename_done:
512: iput(old_dir);
513: iput(new_dir);
514: return error;
515: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.