Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/sys/src/cmd/dossrv/dosfs.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <auth.h>
4
#include <fcall.h>
5
#include "iotrack.h"
6
#include "dat.h"
7
#include "dosfs.h"
8
#include "fns.h"
9
 
10
void
11
rversion(void)
12
{
13
	if(req->msize > Maxiosize)
14
		rep->msize = Maxiosize;
15
	else
16
		rep->msize = req->msize;
17
	rep->version = "9P2000";
18
}
19
 
20
void
21
rauth(void)
22
{
23
	errno = Enoauth;
24
}
25
 
26
void
27
rflush(void)
28
{
29
}
30
 
31
void
32
rattach(void)
33
{
34
	Xfs *xf;
35
	Xfile *root;
36
	Dosptr *dp;
37
 
38
	root = xfile(req->fid, Clean);
39
	if(!root){
40
		errno = Enomem;
41
		goto error;
42
	}
43
	root->xf = xf = getxfs(req->uname, req->aname);
44
	if(!xf)
45
		goto error;
46
	if(xf->fmt == 0 && dosfs(xf) < 0){
47
		errno = Eformat;
48
		goto error;
49
	}
50
	root->qid.type = QTDIR;
51
	root->qid.path = 0;
52
	root->qid.vers = 0;
53
	root->xf->rootqid = root->qid;
54
	dp = malloc(sizeof(Dosptr));
55
	if(dp == nil){
56
		errno = Enomem;
57
		goto error;
58
	}
59
	root->ptr = dp;
60
	rootfile(root);
61
	rep->qid = root->qid;
62
	return;
63
error:
64
	if(root)
65
		xfile(req->fid, Clunk);
66
}
67
 
68
Xfile*
69
doclone(Xfile *of, int newfid)
70
{
71
	Xfile *nf, *next;
72
	Dosptr *dp;
73
 
74
	nf = xfile(newfid, Clean);
75
	if(!nf){
76
		errno = Enomem;
77
		return nil;
78
	}
79
	dp = malloc(sizeof(Dosptr));
80
	if(dp == nil){
81
		errno = Enomem;
82
		return nil;
83
	}
84
	next = nf->next;
85
	*nf = *of;
86
	nf->next = next;
87
	nf->fid = req->newfid;
88
	nf->ptr = dp;
89
	refxfs(nf->xf, 1);
90
	memmove(dp, of->ptr, sizeof(Dosptr));
91
	dp->p = nil;
92
	dp->d = nil;
93
	return nf;
94
}
95
 
96
void
97
rwalk(void)
98
{
99
	Xfile *f, *nf;
100
	Dosptr dp[1], savedp[1];
101
	int r, longtype;
102
	Qid saveqid;
103
 
104
	rep->nwqid = 0;
105
	nf = nil;
106
	f = xfile(req->fid, Asis);
107
	if(f == nil){
108
		chat("\tno xfile\n");
109
		goto error2;
110
	}
111
	if(req->fid != req->newfid){
112
		nf = doclone(f, req->newfid);
113
		if(nf == nil){
114
			chat("\tclone failed\n");
115
			goto error2;
116
		}
117
		f = nf;
118
	}
119
 
120
	saveqid = f->qid;
121
	memmove(savedp, f->ptr, sizeof(Dosptr));
122
	for(; rep->nwqid < req->nwname && rep->nwqid < MAXWELEM; rep->nwqid++){
123
		chat("\twalking %s\n", req->wname[rep->nwqid]);
124
		if(!(f->qid.type & QTDIR)){
125
			chat("\tnot dir: type=%#x\n", f->qid.type);
126
			goto error;
127
		}
128
		if(strcmp(req->wname[rep->nwqid], ".") == 0){
129
			;
130
		}else if(strcmp(req->wname[rep->nwqid], "..") == 0){
131
			if(f->qid.path != f->xf->rootqid.path){
132
				r = walkup(f, dp);
133
				if(r < 0)
134
					goto error;
135
				memmove(f->ptr, dp, sizeof(Dosptr));
136
				if(isroot(dp->addr))
137
					f->qid.path = f->xf->rootqid.path;
138
				else
139
					f->qid.path = QIDPATH(dp);
140
			}
141
		}else{
142
			fixname(req->wname[rep->nwqid]);
143
			longtype = classifyname(req->wname[rep->nwqid]);
144
			if(longtype==Invalid || getfile(f) < 0)
145
				goto error;
146
 
147
			/*
148
			 * always do a search for the long name,
149
			 * because it could be filed as such
150
			 */
151
			r = searchdir(f, req->wname[rep->nwqid], dp, 0, longtype);
152
			putfile(f);
153
			if(r < 0)
154
				goto error;
155
			memmove(f->ptr, dp, sizeof(Dosptr));
156
			f->qid.path = QIDPATH(dp);
157
			f->qid.type = QTFILE;
158
			if(isroot(dp->addr))
159
				f->qid.path = f->xf->rootqid.path;
160
			else if(dp->d->attr & DDIR)
161
				f->qid.type = QTDIR;
162
			else if(dp->d->attr & DSYSTEM){
163
				f->qid.type |= QTEXCL;
164
				if(iscontig(f->xf, dp->d))
165
					f->qid.type |= QTAPPEND;
166
			}
167
//ZZZ maybe use other bits than qtexcl & qtapppend
168
			putfile(f);
169
		}
170
		rep->wqid[rep->nwqid] = f->qid;
171
	}
172
	return;
173
error:
174
	f->qid = saveqid;
175
	memmove(f->ptr, savedp, sizeof(Dosptr));
176
	if(nf != nil)
177
		xfile(req->newfid, Clunk);
178
error2:
179
	if(!errno && !rep->nwqid)
180
		errno = Enonexist;
181
}
182
 
183
void
184
ropen(void)
185
{
186
	Xfile *f;
187
	Iosect *p;
188
	Dosptr *dp;
189
	int attr, omode;
190
 
191
	f = xfile(req->fid, Asis);
192
	if(!f || (f->flags&Omodes)){
193
		errno = Eio;
194
		return;
195
	}
196
	dp = f->ptr;
197
	omode = 0;
198
	if(!isroot(dp->paddr) && (req->mode & ORCLOSE)){
199
		/*
200
		 * check on parent directory of file to be deleted
201
		 */
202
		p = getsect(f->xf, dp->paddr);
203
		if(p == nil){
204
			errno = Eio;
205
			return;
206
		}
207
		attr = ((Dosdir *)&p->iobuf[dp->poffset])->attr;
208
		putsect(p);
209
		if(attr & DRONLY){
210
			errno = Eperm;
211
			return;
212
		}
213
		omode |= Orclose;
214
	}else if(req->mode & ORCLOSE)
215
		omode |= Orclose;
216
	if(getfile(f) < 0){
217
		errno = Enonexist;
218
		return;
219
	}
220
	if(!isroot(dp->addr))
221
		attr = dp->d->attr;
222
	else
223
		attr = DDIR;
224
	switch(req->mode & 7){
225
	case OREAD:
226
	case OEXEC:
227
		omode |= Oread;
228
		break;
229
	case ORDWR:
230
		omode |= Oread;
231
		/* fall through */
232
	case OWRITE:
233
		omode |= Owrite;
234
		if(attr & DRONLY){
235
			errno = Eperm;
236
			goto out;
237
		}
238
		break;
239
	default:
240
		errno = Eio;
241
		goto out;
242
	}
243
	if(req->mode & OTRUNC){
244
		if(attr & DDIR || attr & DRONLY){
245
			errno = Eperm;
246
			goto out;
247
		}
248
		if(truncfile(f, 0) < 0){
249
			errno = Eio;
250
			goto out;
251
		}
252
	}
253
	f->flags |= omode;
254
	rep->qid = f->qid;
255
	rep->iounit = 0;
256
out:
257
	putfile(f);
258
}
259
 
260
static int
261
mk8dot3name(Xfile *f, Dosptr *ndp, char *name, char *sname)
262
{
263
	Dosptr tmpdp;
264
	int i, longtype;
265
 
266
	if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
267
		return Invalid;
268
 
269
	/*
270
	 * always do a search for the long name,
271
	 * because it could be filed as such
272
	 */
273
	fixname(name);
274
	longtype = classifyname(name);
275
	if(longtype==Invalid || searchdir(f, name, ndp, 1, longtype) < 0)
276
		return Invalid;
277
 
278
	if(longtype==Short)
279
		return Short;
280
 
281
	if(longtype==ShortLower){
282
		/*
283
		 * alias is the upper-case version, which we
284
		 * already know does not exist.
285
		 */
286
		strcpy(sname, name);
287
		for(i=0; sname[i]; i++)
288
			if('a' <= sname[i] && sname[i] <= 'z')
289
				sname[i] += 'A'-'a';
290
		return ShortLower;
291
	}
292
 
293
	/*
294
	 * find alias for the long name
295
	 */
296
	for(i=1;; i++){
297
		mkalias(name, sname, i);
298
		if(searchdir(f, sname, &tmpdp, 0, 0) < 0)
299
			return Long;
300
		putsect(tmpdp.p);
301
	}
302
}
303
 
304
/*
305
 * fill in a directory entry for a new file
306
 */
307
static int
308
mkdentry(Xfs *xf, Dosptr *ndp, char *name, char *sname, int longtype, int nattr, long start, long length)
309
{
310
	Dosdir *nd;
311
 
312
	/*
313
	 * fill in the entry
314
	 */
315
	ndp->p = getsect(xf, ndp->addr);
316
	if(ndp->p == nil
317
	|| longtype!=Short && putlongname(xf, ndp, name, sname) < 0){
318
		errno = Eio;
319
		return -1;
320
	}
321
 
322
	ndp->d = (Dosdir *)&ndp->p->iobuf[ndp->offset];
323
	nd = ndp->d;
324
	memset(nd, 0, DOSDIRSIZE);
325
 
326
	if(longtype!=Short)
327
		name = sname;
328
	putname(name, nd);
329
 
330
	nd->attr = nattr;
331
	puttime(nd, 0);
332
	putstart(xf, nd, start);
333
	nd->length[0] = length;
334
	nd->length[1] = length>>8;
335
	nd->length[2] = length>>16;
336
	nd->length[3] = length>>24;
337
 
338
	ndp->p->flags |= BMOD;
339
 
340
	return 0;
341
}
342
 
343
void
344
rcreate(void)
345
{
346
	Dosbpb *bp;
347
	Xfile *f;
348
	Dosptr *pdp, *ndp;
349
	Iosect *xp;
350
	Dosdir *pd, *xd;
351
	char sname[13];
352
	long start;
353
	int longtype, attr, omode, nattr;
354
 
355
	f = xfile(req->fid, Asis);
356
	if(!f || (f->flags&Omodes) || getfile(f)<0){
357
		errno = Eio;
358
		return;
359
	}
360
	pdp = f->ptr;
361
	pd = pdp->d;
362
	/*
363
	 * perm check
364
	 */
365
	if(isroot(pdp->addr) && pd != nil)
366
		panic("root pd != nil");
367
	attr = pd ? pd->attr : DDIR;
368
	if(!(attr & DDIR) || (attr & DRONLY)){
369
badperm:
370
		putfile(f);
371
		errno = Eperm;
372
		return;
373
	}
374
	omode = 0;
375
	if(req->mode & ORCLOSE)
376
		omode |= Orclose;
377
	switch(req->mode & 7){
378
	case OREAD:
379
	case OEXEC:
380
		omode |= Oread;
381
		break;
382
	case ORDWR:
383
		omode |= Oread;
384
		/* fall through */
385
	case OWRITE:
386
		omode |= Owrite;
387
		if(req->perm & DMDIR)
388
			goto badperm;
389
		break;
390
	default:
391
		goto badperm;
392
	}
393
 
394
	/*
395
	 * check the name, find the slot for the dentry,
396
	 * and find a good alias for a long name
397
	 */
398
	ndp = malloc(sizeof(Dosptr));
399
	if(ndp == nil){
400
		putfile(f);
401
		errno = Enomem;
402
		return;
403
	}
404
	longtype = mk8dot3name(f, ndp, req->name, sname);
405
	chat("rcreate %s longtype %d...\n", req->name, longtype);
406
	if(longtype == Invalid){
407
		free(ndp);
408
		goto badperm;
409
	}
410
 
411
	/*
412
	 * allocate first cluster, if making directory
413
	 */
414
	start = 0;
415
	bp = nil;
416
	if(req->perm & DMDIR){
417
		bp = f->xf->ptr;
418
		mlock(bp);
419
		start = falloc(f->xf);
420
		unmlock(bp);
421
		if(start <= 0){
422
			free(ndp);
423
			putfile(f);
424
			errno = Eio;
425
			return;
426
		}
427
	}
428
 
429
	/*
430
	 * make the entry
431
	 */
432
	nattr = 0;
433
	if((req->perm & 0222) == 0)
434
		nattr |= DRONLY;
435
	if(req->perm & DMDIR)
436
		nattr |= DDIR;
437
 
438
	if(mkdentry(f->xf, ndp, req->name, sname, longtype, nattr, start, 0) < 0){
439
		if(ndp->p != nil)
440
			putsect(ndp->p);
441
		free(ndp);
442
		if(start > 0)
443
			ffree(f->xf, start);
444
		putfile(f);
445
		return;
446
	}
447
 
448
	if(pd != nil){
449
		puttime(pd, 0);
450
		pdp->p->flags |= BMOD;
451
	}
452
 
453
	/*
454
	 * fix up the fid
455
	 */
456
	f->ptr = ndp;
457
	f->qid.type = QTFILE;
458
	f->qid.path = QIDPATH(ndp);
459
 
460
//ZZZ set type for excl, append?
461
	if(req->perm & DMDIR){
462
		f->qid.type = QTDIR;
463
		xp = getsect(f->xf, clust2sect(bp, start));
464
		if(xp == nil){
465
			errno = Eio;
466
			goto badio;
467
		}
468
		xd = (Dosdir *)&xp->iobuf[0];
469
		memmove(xd, ndp->d, DOSDIRSIZE);
470
		memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
471
		xd->name[0] = '.';
472
		xd = (Dosdir *)&xp->iobuf[DOSDIRSIZE];
473
		if(pd)
474
			memmove(xd, pd, DOSDIRSIZE);
475
		else{
476
			memset(xd, 0, DOSDIRSIZE);
477
			puttime(xd, 0);
478
			xd->attr = DDIR;
479
		}
480
		memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
481
		xd->name[0] = '.';
482
		xd->name[1] = '.';
483
		xp->flags |= BMOD;
484
		putsect(xp);
485
	}
486
 
487
	f->flags |= omode;
488
	rep->qid = f->qid;
489
	rep->iounit = 0;
490
 
491
badio:
492
	putfile(f);
493
	putsect(pdp->p);
494
	free(pdp);
495
}
496
 
497
void
498
rread(void)
499
{
500
	Xfile *f;
501
	int r;
502
 
503
	if (!(f=xfile(req->fid, Asis)) || !(f->flags&Oread))
504
		goto error;
505
	if(req->count > sizeof repdata)
506
		req->count = sizeof repdata;
507
	if(f->qid.type & QTDIR){
508
		if(getfile(f) < 0)
509
			goto error;
510
		r = readdir(f, repdata, req->offset, req->count);
511
	}else{
512
		if(getfile(f) < 0)
513
			goto error;
514
		r = readfile(f, repdata, req->offset, req->count);
515
	}
516
	putfile(f);
517
	if(r < 0){
518
error:
519
		errno = Eio;
520
	}else{
521
		rep->count = r;
522
		rep->data = (char*)repdata;
523
	}
524
}
525
 
526
void
527
rwrite(void)
528
{
529
	Xfile *f;
530
	int r;
531
 
532
	if (!(f=xfile(req->fid, Asis)) || !(f->flags&Owrite))
533
		goto error;
534
	if(getfile(f) < 0)
535
		goto error;
536
	r = writefile(f, req->data, req->offset, req->count);
537
	putfile(f);
538
	if(r < 0){
539
error:
540
		errno = Eio;
541
	}else{
542
		rep->count = r;
543
	}
544
}
545
 
546
void
547
rclunk(void)
548
{
549
	xfile(req->fid, Clunk);
550
	sync();
551
}
552
 
553
/*
554
 * wipe out a dos directory entry
555
 */
556
static void
557
doremove(Xfs *xf, Dosptr *dp)
558
{
559
	Iosect *p;
560
	int prevdo;
561
 
562
	dp->p->iobuf[dp->offset] = DOSEMPTY;
563
	dp->p->flags |= BMOD;
564
	for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
565
		if(dp->p->iobuf[prevdo+11] != 0xf)
566
			break;
567
		dp->p->iobuf[prevdo] = DOSEMPTY;
568
	}
569
	if(prevdo < 0 && dp->prevaddr != -1){
570
		p = getsect(xf, dp->prevaddr);
571
		for(prevdo = ((Dosbpb*)xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
572
			if(p->iobuf[prevdo+11] != 0xf)
573
				break;
574
			p->iobuf[prevdo] = DOSEMPTY;
575
			p->flags |= BMOD;
576
		}
577
		putsect(p);
578
	}		
579
}
580
 
581
void
582
rremove(void)
583
{
584
	Xfile *f;
585
	Dosptr *dp;
586
	Iosect *parp;
587
	Dosdir *pard;
588
 
589
	f = xfile(req->fid, Asis);
590
	parp = nil;
591
	if(f == nil){
592
		errno = Eio;
593
		goto out;
594
	}
595
	dp = f->ptr;
596
	if(isroot(dp->addr)){
597
		errno = Eperm;
598
		goto out;
599
	}
600
 
601
	/*
602
	 * can't remove if parent is read only,
603
	 * it's a non-empty directory,
604
	 * or it's a read only file in the root directory
605
	 */
606
	parp = getsect(f->xf, dp->paddr);
607
	if(parp == nil
608
	|| getfile(f) < 0){
609
		errno = Eio;
610
		goto out;
611
	}
612
	pard = (Dosdir *)&parp->iobuf[dp->poffset];
613
	if(!isroot(dp->paddr) && (pard->attr & DRONLY)
614
	|| (dp->d->attr & DDIR) && emptydir(f) < 0
615
	|| isroot(dp->paddr) && (dp->d->attr&DRONLY)){
616
		errno = Eperm;
617
		goto out;
618
	}
619
	if(truncfile(f, 0) < 0){
620
		errno = Eio;
621
		goto out;
622
	}
623
	doremove(f->xf, f->ptr);
624
	if(!isroot(dp->paddr)){
625
		puttime(pard, 0);
626
		parp->flags |= BMOD;
627
	}
628
out:
629
	if(parp != nil)
630
		putsect(parp);
631
	if(f != nil)
632
		putfile(f);
633
	xfile(req->fid, Clunk);
634
	sync();
635
}
636
 
637
static void
638
dostat(Xfile *f, Dir *d)
639
{
640
	Dosptr *dp;
641
	Iosect *p;
642
	char *name, namebuf[DOSNAMELEN];
643
	int islong, sum, prevdo;
644
 
645
	dp = f->ptr;
646
	if(isroot(dp->addr)){
647
		memset(d, 0, sizeof(Dir));
648
		d->name = "/";
649
		d->qid.type = QTDIR;
650
		d->qid.path = f->xf->rootqid.path;
651
		d->mode = DMDIR|0777;
652
		d->uid = "bill";
653
		d->muid = "bill";
654
		d->gid = "trog";
655
	}else{
656
		/*
657
		 * assemble any long file name
658
		 */
659
		sum = aliassum(dp->d);
660
		islong = 0;
661
		name = namebuf;
662
		for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
663
			if(dp->p->iobuf[prevdo+11] != 0xf)
664
				break;
665
			name = getnamesect(namebuf, name, &dp->p->iobuf[prevdo], &islong, &sum, -1);
666
		}
667
		if(prevdo < 0 && dp->prevaddr != -1){
668
			p = getsect(f->xf, dp->prevaddr);
669
			for(prevdo = ((Dosbpb*)f->xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
670
				if(p->iobuf[prevdo+11] != 0xf)
671
					break;
672
				name = getnamesect(namebuf, name, &p->iobuf[prevdo], &islong, &sum, -1);
673
			}
674
			putsect(p);
675
		}
676
		getdir(f->xf, d, dp->d, dp->addr, dp->offset);
677
		if(islong && sum == -1 && nameok(namebuf))
678
			strcpy(d->name, namebuf);
679
	}
680
}
681
 
682
void
683
rstat(void)
684
{
685
	Dir dir;
686
	Xfile *f;
687
 
688
	f = xfile(req->fid, Asis);
689
	if(!f || getfile(f) < 0){
690
		errno = Eio;
691
		return;
692
	}
693
 
694
	dir.name = repdata;
695
	dostat(f, &dir);
696
 
697
	rep->nstat = convD2M(&dir, statbuf, sizeof statbuf);
698
	rep->stat = statbuf;
699
	putfile(f);
700
}
701
 
702
void
703
rwstat(void)
704
{
705
	Dir dir, wdir;
706
	Xfile *f, pf;
707
	Dosptr *dp, ndp, pdp;
708
	Iosect *parp;
709
	Dosdir *pard, *d, od;
710
	char sname[13];
711
	ulong oaddr, ooffset;
712
	long start, length;
713
	int i, longtype, changes, attr;
714
 
715
	f = xfile(req->fid, Asis);
716
	if(!f || getfile(f) < 0){
717
		errno = Eio;
718
		return;
719
	}
720
	dp = f->ptr;
721
 
722
	if(isroot(dp->addr)){
723
		errno = Eperm;
724
		goto out;
725
	}
726
 
727
	changes = 0;
728
	dir.name = repdata;
729
	dostat(f, &dir);
730
	if(convM2D(req->stat, req->nstat, &wdir, (char*)statbuf) != req->nstat){
731
		errno = Ebadstat;
732
		goto out;
733
	}
734
 
735
	/*
736
	 * To change length, must have write permission on file.
737
	 * we only allow truncates for now.
738
	 */
739
	if(wdir.length!=~0 && wdir.length!=dir.length){
740
		if(wdir.length > dir.length || !dir.mode & 0222){
741
			errno = Eperm;
742
			goto out;
743
		}
744
	}
745
 
746
	/*
747
	 * no chown or chgrp
748
	 */
749
	if(wdir.uid[0] != '\0' && strcmp(dir.uid, wdir.uid) != 0
750
	|| wdir.gid[0] != '\0' && strcmp(dir.gid, wdir.gid) != 0){
751
		errno = Eperm;
752
		goto out;
753
	}
754
 
755
	/*
756
	 * mode/mtime allowed
757
	 */
758
	if(wdir.mtime != ~0 && dir.mtime != wdir.mtime)
759
		changes = 1;
760
 
761
	/*
762
	 * Setting DMAPPEND (make system file contiguous)
763
	 * requires setting DMEXCL (system file).
764
	 */
765
	if(wdir.mode != ~0){
766
		if((wdir.mode & 7) != ((wdir.mode >> 3) & 7)
767
		|| (wdir.mode & 7) != ((wdir.mode >> 6) & 7)){
768
			errno = Eperm;
769
			goto out;
770
		}
771
		if((dir.mode^wdir.mode) & (DMEXCL|DMAPPEND|0777))
772
			changes = 1;
773
		if((dir.mode^wdir.mode) & DMAPPEND) {
774
			if((wdir.mode & (DMEXCL|DMAPPEND)) == DMAPPEND) {
775
				errno = Eperm;
776
				goto out;
777
			}
778
			if((wdir.mode & DMAPPEND) && makecontig(f, 0) < 0) {
779
				errno = Econtig;
780
				goto out;
781
			}
782
		}
783
	}
784
 
785
 
786
	/*
787
	 * to rename:
788
	 *	1) make up a fake clone
789
	 *	2) walk to parent
790
	 *	3) remove the old entry
791
	 *	4) create entry with new name
792
	 *	5) write correct mode/mtime info
793
	 * we need to remove the old entry before creating the new one
794
	 * to avoid a lock loop.
795
	 */
796
	if(wdir.name[0] != '\0' && strcmp(dir.name, wdir.name) != 0){
797
		if(utflen(wdir.name) >= DOSNAMELEN){
798
			errno = Etoolong;
799
			goto out;
800
		}
801
 
802
		/*
803
		 * grab parent directory of file to be changed and check for write perm
804
		 * rename also disallowed for read-only files in root directory
805
		 */
806
		parp = getsect(f->xf, dp->paddr);
807
		if(parp == nil){
808
			errno = Eio;
809
			goto out;
810
		}
811
		pard = (Dosdir *)&parp->iobuf[dp->poffset];
812
		if(!isroot(dp->paddr) && (pard->attr & DRONLY)
813
		|| isroot(dp->paddr) && (dp->d->attr&DRONLY)){
814
			putsect(parp);
815
			errno = Eperm;
816
			goto out;
817
		}
818
 
819
		/*
820
		 * retrieve info from old entry
821
		 */
822
		oaddr = dp->addr;
823
		ooffset = dp->offset;
824
		d = dp->d;
825
		od = *d;
826
		start = getstart(f->xf, d);
827
		length = GLONG(d->length);
828
		attr = d->attr;
829
 
830
		/*
831
		 * temporarily release file to allow other directory ops:
832
		 * walk to parent, validate new name
833
		 * then remove old entry
834
		 */
835
		putfile(f);
836
		pf = *f;
837
		memset(&pdp, 0, sizeof(Dosptr));
838
		pdp.prevaddr = -1;
839
		pdp.naddr = -1;
840
		pdp.addr = dp->paddr;
841
		pdp.offset = dp->poffset;
842
		pdp.p = parp;
843
		if(!isroot(pdp.addr))
844
			pdp.d = (Dosdir *)&parp->iobuf[pdp.offset];
845
		pf.ptr = &pdp;
846
		longtype = mk8dot3name(&pf, &ndp, wdir.name, sname);
847
		if(longtype==Invalid){
848
			putsect(parp);
849
			errno = Eperm;
850
			return;
851
		}
852
		if(getfile(f) < 0){
853
			putsect(parp);
854
			errno = Eio;
855
			return;
856
		}
857
		doremove(f->xf, dp);
858
		putfile(f);
859
 
860
		/*
861
		 * search for dir entry again, since we may be able to use the old slot,
862
		 * and we need to set up the naddr field if a long name spans the block.
863
		 * create new entry.
864
		 */
865
		if(searchdir(&pf, wdir.name, dp, 1, longtype) < 0
866
		|| mkdentry(pf.xf, dp, wdir.name, sname, longtype, attr, start, length) < 0){
867
			putsect(parp);
868
			errno = Eio;
869
			goto out;
870
		}
871
 
872
		/*
873
		 * copy invisible fields
874
		 */
875
		d = dp->d;
876
		for(i = 0; i < 2; i++)
877
			d->ctime[i] = od.ctime[i];
878
		for(i = 0; i < nelem(od.cdate); i++)
879
			d->cdate[i] = od.cdate[i];
880
		for(i = 0; i < nelem(od.adate); i++)
881
			d->adate[i] = od.adate[i];
882
 
883
		putsect(parp);
884
 
885
		/*
886
		 * relocate up other fids to the same file, if it moved
887
		 */
888
		f->qid.path = QIDPATH(dp);
889
		if(oaddr != dp->addr || ooffset != dp->offset)
890
			dosptrreloc(f, dp, oaddr, ooffset);
891
 
892
		/*
893
		 * copy fields that are not supposed to change
894
		 */
895
		if(wdir.mtime == ~0)
896
			wdir.mtime = dir.mtime;
897
		if(wdir.mode == ~0)
898
			wdir.mode = dir.mode;
899
		changes = 1;
900
	}
901
 
902
	/*
903
	 * do the actual truncate
904
	 */
905
	if(wdir.length != ~0 && wdir.length != dir.length && truncfile(f, wdir.length) < 0)
906
		errno = Eio;
907
 
908
	if(changes){
909
		putdir(dp->d, &wdir);
910
		dp->p->flags |= BMOD;
911
	}
912
 
913
out:
914
	putfile(f);
915
	sync();
916
}