home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / comp / unix / bsd / 9004 < prev    next >
Encoding:
Internet Message Format  |  1992-11-21  |  43.5 KB

  1. Xref: sparky comp.unix.bsd:9004 alt.sources:2540
  2. Path: sparky!uunet!charon.amdahl.com!amdahl!paulp
  3. From: paulp@uts.amdahl.com (Paul Popelka)
  4. Newsgroups: comp.unix.bsd,alt.sources
  5. Subject: [386bsd] mountable DOS filesystem code, Part 2/5
  6. Message-ID: <bbqe03ZmbbYI00@amdahl.uts.amdahl.com>
  7. Date: 17 Nov 92 17:26:02 GMT
  8. Followup-To: comp.unix.bsd
  9. Organization: Amdahl Corporation, Sunnyvale CA
  10. Lines: 1677
  11.  
  12.  
  13. # This is a shell archive.  Save it in a file, remove anything before
  14. # this line, and then unpack it by entering "sh file".  Note, it may
  15. # create directories; files and directories will be owned by you and
  16. # have default permissions.
  17. #
  18. # This archive contains:
  19. #
  20. #    /sys/pcfs/pcfs_vnops.c
  21. #
  22. echo x - /sys/pcfs/pcfs_vnops.c
  23. sed 's/^X//' >/sys/pcfs/pcfs_vnops.c << 'END-of-/sys/pcfs/pcfs_vnops.c'
  24. X/*
  25. X *  Written by Paul Popelka (paulp@uts.amdahl.com)
  26. X *
  27. X *  You can do anything you want with this software,
  28. X *    just don't say you wrote it,
  29. X *    and don't remove this notice.
  30. X *
  31. X *  This software is provided "as is".
  32. X *
  33. X *  The author supplies this software to be publicly
  34. X *  redistributed on the understanding that the author
  35. X *  is not responsible for the correct functioning of
  36. X *  this software in any circumstances and is not liable
  37. X *  for any damages caused by this software.
  38. X *
  39. X *  October 1992
  40. X */
  41. X
  42. X#include "param.h"
  43. X#include "systm.h"
  44. X#include "namei.h"
  45. X#include "resourcevar.h"    /* defines plimit structure in proc struct */
  46. X#include "kernel.h"
  47. X#include "file.h"        /* define FWRITE ... */
  48. X#include "stat.h"
  49. X#include "buf.h"
  50. X#include "proc.h"
  51. X#include "mount.h"
  52. X#include "vnode.h"
  53. X#include "specdev.h"        /* defines plimit structure in the proc struct */
  54. X#include "malloc.h"
  55. X
  56. X#include "dir.h"        /* defines dirent structure        */
  57. X
  58. X#include "bpb.h"
  59. X#include "direntry.h"
  60. X#include "denode.h"
  61. X#include "pcfsmount.h"
  62. X#include "fat.h"
  63. X/*
  64. X *  Some general notes:
  65. X *
  66. X *  In the ufs filesystem the inodes, superblocks, and indirect
  67. X *  blocks are read/written using the vnode for the filesystem.
  68. X *  Blocks that represent the contents of a file are read/written
  69. X *  using the vnode for the file (including directories when
  70. X *  they are read/written as files).
  71. X *  This presents problems for the dos filesystem because data
  72. X *  that should be in an inode (if dos had them) resides in the
  73. X *  directory itself.  Since we must update directory entries
  74. X *  without the benefit of having the vnode for the directory
  75. X *  we must use the vnode for the filesystem.  This means that
  76. X *  when a directory is actually read/written (via read, write,
  77. X *  or readdir, or seek) we must use the vnode for the filesystem
  78. X *  instead of the vnode for the directory as would happen in ufs.
  79. X *  This is to insure we retreive the correct block from the
  80. X *  buffer cache since the hash value is based upon the vnode
  81. X *  address and the desired block number.
  82. X */
  83. X
  84. X/*
  85. X *  Create a regular file.
  86. X *  On entry the directory to contain the file being
  87. X *  created is locked.  We must release before we
  88. X *  return.
  89. X *  We must also free the pathname buffer pointed at
  90. X *  by ndp->ni_pnbuf, always on error, or only if the
  91. X *  SAVESTART bit in ni_nameiop is clear on success.
  92. X */
  93. Xint
  94. Xpcfs_create(ndp, vap, p)
  95. X    struct nameidata *ndp;
  96. X    struct vattr *vap;
  97. X    struct proc *p;
  98. X{
  99. X    struct denode ndirent;
  100. X    struct direntry *ndirp = &ndirent.de_de;
  101. X    struct denode *dep;
  102. X    struct denode *pdep = VTODE(ndp->ni_dvp);
  103. X    int error;
  104. X#if defined(PCFSDEBUG)
  105. Xprintf("pcfs_create(ndp %08x, vap %08x, p %08x\n", ndp, vap, p);
  106. X#endif /* defined(PCFSDEBUG) */
  107. X
  108. X/*
  109. X *  Create a directory entry for the file, then call
  110. X *  createde() to have it installed.
  111. X *  NOTE: DOS files are always executable.  We use the
  112. X *  absence of the owner write bit to make the file readonly.
  113. X */
  114. X    bzero(&ndirent, sizeof(ndirent));
  115. X    unix2dostime(&time, (union dosdate *)&ndirp->deDate,
  116. X        (union dostime *)&ndirp->deTime);
  117. X    unix2dosfn((unsigned char *)ndp->ni_ptr, ndirp->deName, ndp->ni_namelen);
  118. X    ndirp->deAttributes = (vap->va_mode & VWRITE) ? 0 : ATTR_READONLY;
  119. X    ndirp->deStartCluster = 0;
  120. X    ndirp->deFileSize = 0;
  121. X    ndirent.de_pmp = pdep->de_pmp;
  122. X    ndirent.de_dev = pdep->de_dev;
  123. X    ndirent.de_devvp = pdep->de_devvp;
  124. X    if ((error = createde(&ndirent, ndp, &dep)) == 0) {
  125. X        ndp->ni_vp = DETOV(dep);
  126. X        if ((ndp->ni_nameiop & SAVESTART) == 0)
  127. X            free(ndp->ni_pnbuf, M_NAMEI);
  128. X    } else {
  129. X        free(ndp->ni_pnbuf, M_NAMEI);
  130. X    }
  131. X    deput(pdep);        /* release parent dir    */
  132. X    return error;
  133. X}
  134. X
  135. Xint
  136. Xpcfs_mknod(ndp, vap, cred, p)
  137. X    struct nameidata *ndp;
  138. X    struct vattr *vap;
  139. X    struct ucred *cred;
  140. X    struct proc *p;
  141. X{
  142. X    int error;
  143. X
  144. X    switch (vap->va_type) {
  145. X    case VDIR:
  146. X        error = pcfs_mkdir(ndp, vap, p);
  147. X        break;
  148. X
  149. X/*
  150. X *  pcfs_create() sets ndp->ni_vp.
  151. X */
  152. X    case VREG:
  153. X        error = pcfs_create(ndp, vap, p);
  154. X        break;
  155. X
  156. X    default:
  157. X        error = EINVAL;
  158. X        break;
  159. X    }
  160. X    return error;
  161. X}
  162. X
  163. X/*
  164. X *  Since DOS directory entries that describe directories
  165. X *  have 0 in the filesize field, we take this opportunity (open)
  166. X *  to find out the length of the directory and plug it
  167. X *  into the denode structure.
  168. X */
  169. Xint
  170. Xpcfs_open(vp, mode, cred, p)
  171. X    struct vnode *vp;
  172. X    int mode;
  173. X    struct ucred *cred;
  174. X    struct proc *p;
  175. X{
  176. X    int error = 0;
  177. X    unsigned long sizeinclusters;
  178. X    struct denode *dep = VTODE(vp);
  179. X
  180. X    if (dep->de_Attributes & ATTR_DIRECTORY) {
  181. X        error = pcbmap(dep, 0xffff, 0, &sizeinclusters);
  182. X        if (error == E2BIG) {
  183. X            dep->de_FileSize =
  184. X                sizeinclusters * dep->de_pmp->pm_bpcluster;
  185. X            error = 0;
  186. X        } else
  187. X            printf("pcfs_open(): pcbmap returned %d\n", error);
  188. X    }
  189. X    return 0;
  190. X}
  191. X
  192. Xint
  193. Xpcfs_close(vp, fflag, cred, p)
  194. X    struct vnode *vp;
  195. X    int fflag;
  196. X    struct ucred *cred;
  197. X    struct proc *p;
  198. X{
  199. X    struct denode *dep = VTODE(vp);
  200. X
  201. X    if (vp->v_usecount > 1  &&  !(dep->de_flag & DELOCKED))
  202. X        DETIMES(dep, &time);
  203. X    return 0;
  204. X}
  205. X
  206. Xint
  207. Xpcfs_access(vp, mode, cred, p)
  208. X    struct vnode *vp;
  209. X    int mode;
  210. X    struct ucred *cred;
  211. X    struct proc *p;
  212. X{
  213. X    int dosmode;
  214. X    struct denode *dep = VTODE(vp);
  215. X
  216. X/*
  217. X *  Root gets to do anything.  Even execute a file
  218. X *  without the x-bit on?  But, for dos filesystems
  219. X *  every file is executable.  I may regret this.
  220. X */
  221. X    if (cred->cr_uid == 0)
  222. X        return 0;
  223. X
  224. X/*
  225. X *  mode is filled with a combination of VREAD, VWRITE,
  226. X *  and/or VEXEC bits turned on.  In an octal number these
  227. X *  are the Y in 0Y00.
  228. X *
  229. X *  Since the dos filesystem doesn't have the concept of
  230. X *  file ownership we just give everybody read and execute
  231. X *  access and write access if the readonly bit is off.
  232. X */
  233. X    dosmode = VEXEC | VREAD |
  234. X        ((dep->de_Attributes & ATTR_READONLY) ? 0 : VWRITE);
  235. X    return ((dosmode & mode) != 0) ? 0 : EACCES;
  236. X}
  237. X
  238. Xint
  239. Xpcfs_getattr(vp, vap, cred, p)
  240. X    struct vnode *vp;
  241. X    struct vattr *vap;
  242. X    struct ucred *cred;
  243. X    struct proc *p;
  244. X{
  245. X    unsigned int cn;
  246. X    struct denode *dep = VTODE(vp);
  247. X
  248. X    DETIMES(dep, &time);
  249. X    vap->va_fsid = dep->de_dev;
  250. X    /* The following computation of the fileid must be the
  251. X     * same as that used in pcfs_readdir() to compute d_fileno.
  252. X     * If not, pwd doesn't work. */
  253. X    if (dep->de_Attributes & ATTR_DIRECTORY) {
  254. X        if ((cn = dep->de_StartCluster) == PCFSROOT)
  255. X            cn = 1;
  256. X    } else {
  257. X        if ((cn = dep->de_dirclust) == PCFSROOT)
  258. X            cn = 1;
  259. X        cn = (cn << 16) | (dep->de_diroffset & 0xffff);
  260. X    }
  261. X    vap->va_fileid = cn;
  262. X    vap->va_mode = (dep->de_Attributes & ATTR_READONLY) ? 0555 : 0777;
  263. X    if (dep->de_Attributes & ATTR_DIRECTORY)
  264. X        vap->va_mode |= S_IFDIR;
  265. X    vap->va_nlink = 1;
  266. X    vap->va_gid = 0;
  267. X    vap->va_uid = 0;
  268. X    vap->va_rdev = 0;
  269. X    vap->va_size = dep->de_FileSize;
  270. X    vap->va_size_rsv = 0;
  271. X    dos2unixtime((union dosdate *)&dep->de_Date,
  272. X        (union dostime *)&dep->de_Time, &vap->va_atime);
  273. X    vap->va_atime.tv_usec = 0;
  274. X    vap->va_mtime.tv_sec = vap->va_atime.tv_sec;
  275. X    vap->va_mtime.tv_usec = 0;
  276. X    vap->va_ctime.tv_sec = vap->va_atime.tv_sec;
  277. X    vap->va_ctime.tv_usec = 0;
  278. X    vap->va_flags = dep->de_flag;
  279. X    vap->va_gen = 0;
  280. X    vap->va_blocksize = dep->de_pmp->pm_bpcluster;
  281. X    vap->va_bytes = (dep->de_FileSize + dep->de_pmp->pm_crbomask) &
  282. X        ~(dep->de_pmp->pm_crbomask);
  283. X    vap->va_bytes_rsv = 0;
  284. X    vap->va_type = vp->v_type;
  285. X    return 0;
  286. X}
  287. X
  288. Xint
  289. Xpcfs_setattr(vp, vap, cred, p)
  290. X    struct vnode *vp;
  291. X    struct vattr *vap;
  292. X    struct ucred *cred;
  293. X    struct proc *p;
  294. X{
  295. X    int error = 0;
  296. X    struct denode *dep = VTODE(vp);
  297. X
  298. X#if defined(PCFSDEBUG)
  299. Xprintf("pcfs_setattr(): vp %08x, vap %08x, cred %08x, p %08x\n",
  300. X    vp, vap, cred, p);
  301. X#endif /* defined(PCFSDEBUG) */
  302. X    if ((vap->va_type != VNON)  ||
  303. X        (vap->va_nlink != VNOVAL)  ||
  304. X        (vap->va_fsid != VNOVAL)  ||
  305. X        (vap->va_fileid != VNOVAL)  ||
  306. X        (vap->va_blocksize != VNOVAL)  ||
  307. X        (vap->va_rdev != VNOVAL)  ||
  308. X        (vap->va_bytes != VNOVAL)  ||
  309. X        (vap->va_gen != VNOVAL)  ||
  310. X        (vap->va_uid != (u_short)VNOVAL)  ||
  311. X        (vap->va_gid != (u_short)VNOVAL)  ||
  312. X        (vap->va_atime.tv_sec != VNOVAL)) {
  313. X#if defined(PCFSDEBUG)
  314. Xprintf("pcfs_setattr(): returning EINVAL\n");
  315. Xprintf("    va_type %d, va_nlink %x, va_fsid %x, va_fileid %x\n",
  316. X    vap->va_type, vap->va_nlink, vap->va_fsid, vap->va_fileid);
  317. Xprintf("    va_blocksize %x, va_rdev %x, va_bytes %x, va_gen %x\n",
  318. X    vap->va_blocksize, vap->va_rdev, vap->va_bytes, vap->va_gen);
  319. Xprintf("    va_uid %x, va_gid %x, va_atime.tv_sec %x\n",
  320. X    vap->va_uid, vap->va_gid, vap->va_atime.tv_sec);
  321. X#endif /* defined(PCFSDEBUG) */
  322. X        return EINVAL;
  323. X    }
  324. X
  325. X    if (vap->va_size != VNOVAL) {
  326. X        if (vp->v_type == VDIR)
  327. X            return EISDIR;
  328. X        if (error = detrunc(dep, vap->va_size, 0))
  329. X            return error;
  330. X    }
  331. X    if (vap->va_mtime.tv_sec != VNOVAL) {
  332. X        dep->de_flag |= DEUPD;
  333. X        if (error = deupdat(dep, &vap->va_mtime, 1))
  334. X            return error;
  335. X    }
  336. X
  337. X/*
  338. X *  DOS files only have the ability to have thier
  339. X *  writability attribute set, so we use the owner
  340. X *  write bit to set the readonly attribute.
  341. X */
  342. X    if (vap->va_mode != (u_short)VNOVAL) {
  343. X        /* We ignore the read and execute bits */
  344. X        if (vap->va_mode & VWRITE)
  345. X            dep->de_Attributes &= ~ATTR_READONLY;
  346. X        else
  347. X            dep->de_Attributes |= ATTR_READONLY;
  348. X        dep->de_flag |= DEUPD;
  349. X    }
  350. X
  351. X    if (vap->va_flags != VNOVAL) {
  352. X        if (error = suser(cred, &p->p_acflag))
  353. X            return error;
  354. X        if (cred->cr_uid == 0)
  355. X            dep->de_flag = vap->va_flags;
  356. X        else {
  357. X            dep->de_flag &= 0xffff0000;
  358. X            dep->de_flag |= (vap->va_flags & 0xffff);
  359. X        }
  360. X        dep->de_flag |= DEUPD;
  361. X    }
  362. X    return error;
  363. X}
  364. X
  365. X/*debug*/int brc[2];
  366. X
  367. Xint
  368. Xpcfs_read(vp, uio, ioflag, cred)
  369. X    struct vnode *vp;
  370. X    struct uio *uio;
  371. X    int ioflag;
  372. X    struct ucred *cred;
  373. X{
  374. X    int error = 0;
  375. X    int diff;
  376. X    int isadir;
  377. X    long n;
  378. X    long on;
  379. X    daddr_t bn;
  380. X    daddr_t lbn;
  381. X    daddr_t rablock;
  382. X    struct buf *bp;
  383. X    struct denode *dep = VTODE(vp);
  384. X    struct pcfsmount *pmp = dep->de_pmp;
  385. X
  386. X/*
  387. X *  If they didn't ask for any data, then we
  388. X *  are done.
  389. X */
  390. X    if (uio->uio_resid == 0)
  391. X        return 0;
  392. X    if (uio->uio_offset < 0)
  393. X        return EINVAL;
  394. X
  395. X    isadir = dep->de_Attributes & ATTR_DIRECTORY;
  396. X    do {
  397. X        lbn = uio->uio_offset >> pmp->pm_cnshift;
  398. X        on  = uio->uio_offset &  pmp->pm_crbomask;
  399. X        n = MIN((unsigned)(pmp->pm_bpcluster - on), uio->uio_resid);
  400. X        diff = dep->de_FileSize - uio->uio_offset;
  401. X        if (diff <= 0)
  402. X            return 0;
  403. X        /* convert cluster # to block # if a directory */
  404. X        if (isadir) {
  405. X            error = pcbmap(dep, lbn, &lbn, 0);
  406. X            if (error)
  407. X                return error;
  408. X        }
  409. X        if (diff < n)
  410. X            n = diff;
  411. X/*
  412. X *  If we are operating on a directory file then be
  413. X *  sure to do i/o with the vnode for the filesystem
  414. X *  instead of the vnode for the directory.
  415. X */
  416. X        if (isadir) {
  417. X            error = bread(pmp->pm_devvp, lbn, pmp->pm_bpcluster,
  418. X                NOCRED, &bp);
  419. X        } else {
  420. X            rablock = lbn + 1;
  421. X            if (vp->v_lastr + 1 == lbn  &&
  422. X                rablock * pmp->pm_bpcluster < dep->de_FileSize) {
  423. X                error = breada(vp, lbn, pmp->pm_bpcluster,
  424. X                    rablock, pmp->pm_bpcluster, NOCRED, &bp);
  425. Xbrc[0]++;
  426. X            } else {
  427. X                error = bread(vp, lbn, pmp->pm_bpcluster, NOCRED,
  428. X                    &bp);
  429. Xbrc[1]++;
  430. X            }
  431. X            vp->v_lastr = lbn;
  432. X        }
  433. X        n = MIN(n, pmp->pm_bpcluster - bp->b_resid);
  434. X        if (error) {
  435. X            brelse(bp);
  436. X            return error;
  437. X        }
  438. X        error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
  439. X/*
  440. X *  If we have read everything from this block or
  441. X *  have read to end of file then we are done with
  442. X *  this block.  Mark it to say the buffer can be reused if
  443. X *  need be.
  444. X */
  445. X        if (n + on == pmp->pm_bpcluster  ||
  446. X            uio->uio_offset == dep->de_FileSize)
  447. X            bp->b_flags |= B_AGE;
  448. X        brelse(bp);
  449. X    } while (error == 0  &&  uio->uio_resid > 0  && n != 0);
  450. X    return error;
  451. X}
  452. X
  453. X/*
  454. X *  Write data to a file or directory.
  455. X */
  456. Xint
  457. Xpcfs_write(vp, uio, ioflag, cred)
  458. X    struct vnode *vp;
  459. X    struct uio *uio;
  460. X    int ioflag;
  461. X    struct ucred *cred;
  462. X{
  463. X    int n;
  464. X    int isadir;
  465. X    int croffset;
  466. X    int resid;
  467. X    int osize;
  468. X    int error;
  469. X    unsigned long cluster;
  470. X    unsigned long nextcluster;
  471. X    unsigned long lastcluster;
  472. X    daddr_t bn;
  473. X    struct buf *bp;
  474. X    struct proc *p = uio->uio_procp;
  475. X    struct vnode *thisvp;
  476. X    struct denode *dep = VTODE(vp);
  477. X    struct pcfsmount *pmp = dep->de_pmp;
  478. X
  479. X#if defined(PCFSDEBUG)
  480. Xprintf("pcfs_write(vp %08x, uio %08x, ioflag %08x, cred %08x\n",
  481. X    vp, uio, ioflag, cred);
  482. Xprintf("pcfs_write(): diroff %d, dirclust %d, startcluster %d\n",
  483. X    dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
  484. X#endif /* defined(PCFSDEBUG) */
  485. X
  486. X    switch (vp->v_type) {
  487. X    case VREG:
  488. X        if (ioflag & IO_APPEND)
  489. X            uio->uio_offset = dep->de_FileSize;
  490. X        isadir = 0;
  491. X        thisvp = vp;
  492. X        break;
  493. X
  494. X    case VDIR:
  495. X        if ((ioflag & IO_SYNC) == 0)
  496. X            panic("pcfs_write(): non-sync directory update");
  497. X        isadir = 1;
  498. X        thisvp = pmp->pm_devvp;
  499. X        break;
  500. X
  501. X    default:
  502. X        panic("pcfs_write(): bad file type");
  503. X        break;
  504. X    }
  505. X
  506. X    if (uio->uio_offset < 0) {
  507. X        return EINVAL;
  508. X    }
  509. X    if (uio->uio_resid == 0)
  510. X        return 0;
  511. X
  512. X/*
  513. X *  If they've exceeded their filesize limit, tell them about it.
  514. X */
  515. X    if (vp->v_type == VREG  &&  p  &&
  516. X        ((uio->uio_offset + uio->uio_resid) >
  517. X         p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
  518. X        psignal(p, SIGXFSZ);
  519. X        return EFBIG;
  520. X    }
  521. X
  522. X/*
  523. X *  If attempting to write beyond the end of the root
  524. X *  directory we stop that here because the root directory
  525. X *  can not grow.
  526. X */
  527. X    if ((dep->de_Attributes & ATTR_DIRECTORY)  &&
  528. X        dep->de_StartCluster == PCFSROOT  &&
  529. X        (uio->uio_offset+uio->uio_resid) > dep->de_FileSize)
  530. X        return ENOSPC;
  531. X
  532. X/*
  533. X *  If the offset we are starting the write at is beyond the
  534. X *  end of the file, then they've done a seek.  Unix filesystems
  535. X *  allow files with holes in them, DOS doesn't so we must
  536. X *  fill the hole with zeroed blocks.  We do this by calling
  537. X *  our seek function.  This could probably be cleaned up
  538. X *  someday.
  539. X */
  540. X    if (uio->uio_offset > dep->de_FileSize) {
  541. X        error = pcfs_seek(vp, (off_t)0, uio->uio_offset, cred);
  542. X        if (error)
  543. X            return error;
  544. X    }
  545. X
  546. X/*
  547. X *  Remember some values in case the write fails.
  548. X */
  549. X    resid = uio->uio_resid;
  550. X    osize = dep->de_FileSize;
  551. X
  552. X    do {
  553. X        bn = uio->uio_offset >> pmp->pm_cnshift;
  554. X/*
  555. X *  If we are appending to the file and we are on a
  556. X *  cluster boundary, then allocate a new cluster
  557. X *  and chain it onto the file.
  558. X */
  559. X        if (uio->uio_offset == dep->de_FileSize  &&
  560. X            (uio->uio_offset & pmp->pm_crbomask) == 0) {
  561. X            if (error = extendfile(dep, &bp, 0))
  562. X                break;
  563. X        } else {
  564. X/*
  565. X *  The block we need to write into exists,
  566. X *  so just read it in.
  567. X */
  568. X            if (isadir) {
  569. X                error = pcbmap(dep, bn, &bn, 0);
  570. X                if (error)
  571. X                    return error;
  572. X            }
  573. X            error = bread(thisvp, bn, pmp->pm_bpcluster, cred, &bp);
  574. X            if (error) {
  575. X                brelse(bp);
  576. X                return error;
  577. X            }
  578. X        }
  579. X        croffset = uio->uio_offset & pmp->pm_crbomask;
  580. X        n = MIN(uio->uio_resid, pmp->pm_bpcluster-croffset);
  581. X        if (uio->uio_offset+n > dep->de_FileSize) {
  582. X            dep->de_FileSize = uio->uio_offset + n;
  583. X            vnode_pager_setsize(vp, dep->de_FileSize);    /* why? */
  584. X        }
  585. X        (void) vnode_pager_uncache(vp);        /* why not? */
  586. X        /* Should these vnode_pager_* functions be done on dir files? */
  587. X
  588. X/*
  589. X *  Copy the data from user space into the buf header.
  590. X */
  591. X        error = uiomove(bp->b_un.b_addr+croffset, n, uio);
  592. X
  593. X/*
  594. X *  If they want this synchronous then write it and wait
  595. X *  for it.  Otherwise, if on a cluster boundary write it
  596. X *  asynchronously so we can move on to the next block
  597. X *  without delay.  Otherwise do a delayed write because
  598. X *  we may want to write somemore into the block later.
  599. X */
  600. X        if (ioflag & IO_SYNC)
  601. X            (void) bwrite(bp);
  602. X        else
  603. X        if (n + croffset == pmp->pm_bpcluster) {
  604. X            bp->b_flags |= B_AGE;
  605. X            bawrite(bp);
  606. X        } else
  607. X            bdwrite(bp);
  608. X        dep->de_flag |= DEUPD;
  609. X    } while (error == 0  &&  uio->uio_resid > 0);
  610. X
  611. X/*
  612. X *  If the write failed and they want us to, truncate
  613. X *  the file back to the size it was before the write
  614. X *  was attempted.
  615. X */
  616. X    if (error && (ioflag & IO_UNIT)) {
  617. X        detrunc(dep, osize, ioflag & IO_SYNC);
  618. X        uio->uio_offset -= resid - uio->uio_resid;
  619. X        uio->uio_resid   = resid;
  620. X    }
  621. X    if (!error && (ioflag & IO_UNIT))
  622. X        error = deupdat(dep, &time, 1);
  623. X    return error;
  624. X}
  625. X
  626. Xint
  627. Xpcfs_ioctl(vp, com, data, fflag, cred, p)
  628. X    struct vnode *vp;
  629. X    int com;
  630. X    caddr_t data;
  631. X    struct ucred *cred;
  632. X    struct proc *p;
  633. X{
  634. X    return ENOTTY;
  635. X}
  636. X
  637. Xint
  638. Xpcfs_select(vp, which, fflags, cred, p)
  639. X    struct vnode *vp;
  640. X    int which;
  641. X    int fflags;
  642. X    struct ucred *cred;
  643. X    struct proc *p;
  644. X{
  645. X    return 1;        /* DOS filesystems never block? */
  646. X}
  647. X
  648. Xint
  649. Xpcfs_mmap(vp, fflags, cred, p)
  650. X    struct vnode *vp;
  651. X    int fflags;
  652. X    struct ucred *cred;
  653. X    struct proc *p;
  654. X{
  655. X    return EINVAL;
  656. X}
  657. X
  658. X/*
  659. X *  Flush the blocks of a file to disk.
  660. X *
  661. X *  This function is worthless for vnodes that represent
  662. X *  directories.
  663. X *  Maybe we could just do a sync if they try an fsync
  664. X *  on a directory file.
  665. X */
  666. Xint
  667. Xpcfs_fsync(vp, fflags, cred, waitfor, p)
  668. X    struct vnode *vp;
  669. X    int fflags;
  670. X    struct ucred *cred;
  671. X    int waitfor;
  672. X    struct proc *p;
  673. X{
  674. X    struct denode *dep = VTODE(vp);
  675. X
  676. X    if (fflags & FWRITE)
  677. X        dep->de_flag |= DEUPD;
  678. X/*
  679. X *  Does this call to vflushbuf() do anything?  I can
  680. X *  find no code anywhere that sets v_dirtyblkhd in the
  681. X *  vnode, which vflushbuf() seems to depend upon.
  682. X */
  683. X    vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0);
  684. X    return deupdat(dep, &time, waitfor == MNT_WAIT);
  685. X}
  686. X
  687. X/*
  688. X *  Since the dos filesystem does not allow files with
  689. X *  holes in them we must fill the file with zeroed
  690. X *  blocks when a seek past the end of file happens.
  691. X *
  692. X *  It seems that nothing in the kernel calls the filesystem
  693. X *  specific file seek functions.  And, someone on the
  694. X *  net told me that NFS never sends announcements of
  695. X *  seeks to the server.  So, if pcfs ever becomes
  696. X *  NFS mountable it will have to use other means to
  697. X *  fill in holes in what would be a sparse file.
  698. X */
  699. Xint
  700. Xpcfs_seek(vp, oldoff, newoff, cred)
  701. X    struct vnode *vp;
  702. X    off_t oldoff;
  703. X    off_t newoff;
  704. X    struct ucred *cred;
  705. X{
  706. X    int error = 0;
  707. X    off_t foff;
  708. X    daddr_t bn;
  709. X    unsigned long cluster;
  710. X    unsigned long lastcluster;
  711. X    struct buf *bp;
  712. X    struct denode *dep = VTODE(vp);
  713. X    struct pcfsmount *pmp = dep->de_pmp;
  714. X
  715. X#if defined(PCFSDEBUG)
  716. Xprintf("pcfs_seek(vp %08x, oldoff %d, newoff %d, cred %08x)\n",
  717. X    vp, oldoff, newoff, cred); 
  718. X#endif /* defined(PCFSDEBUG) */
  719. X
  720. X/*
  721. X *  Compute the offset of the first byte after the
  722. X *  last block in the file.
  723. X *  If seeking beyond the end of file then fill the
  724. X *  file with zeroed blocks up to the seek address.
  725. X */
  726. X    foff = (dep->de_FileSize + (pmp->pm_bpcluster-1)) & ~pmp->pm_crbomask;
  727. X#if defined(PCFSDEBUG)
  728. Xprintf("seek: newoff %d > foff %d\n", newoff, foff);
  729. X#endif /* defined(PCFSDEBUG) */
  730. X    if (newoff > foff) {
  731. X/*
  732. X *  If this is the root directory and we are
  733. X *  attempting to seek beyond the end disallow
  734. X *  it.  DOS filesystem root directories can
  735. X *  not grow.
  736. X */
  737. X        if (vp->v_flag & VROOT)
  738. X            return EINVAL;
  739. X/*
  740. X *  If this is a directory and the caller is not
  741. X *  root, then do not let them seek beyond the end
  742. X *  of file.  If we allowed this then users could
  743. X *  cause directories to grow.  Is this really that
  744. X *  important?
  745. X */
  746. X        if (dep->de_Attributes & ATTR_DIRECTORY) {
  747. X            if (error = suser(cred, NULL)) {
  748. X                return error;
  749. X            }
  750. X        }
  751. X/*
  752. X *  Allocate and chain together as many clusters as
  753. X *  are needed to get to newoff.
  754. X */
  755. X        while (foff < newoff) {
  756. X            if (error = extendfile(dep, &bp, 0))
  757. X                return error;
  758. X            dep->de_flag |= DEUPD;
  759. X            bdwrite(bp);
  760. X            foff += pmp->pm_bpcluster;
  761. X            dep->de_FileSize += pmp->pm_bpcluster;
  762. X        } /* end while() */
  763. X        dep->de_FileSize = newoff;
  764. X        return deupdat(dep, &time);
  765. X    }
  766. X    return 0;
  767. X}
  768. X
  769. Xint
  770. Xpcfs_remove(ndp, p)
  771. X    struct nameidata *ndp;
  772. X    struct proc *p;
  773. X{
  774. X    int error;
  775. X    struct denode *dep = VTODE(ndp->ni_vp);
  776. X    struct denode *ddep = VTODE(ndp->ni_dvp);
  777. X
  778. X    error = removede(ndp);
  779. X#if defined(PCFSDEBUG)
  780. Xprintf("pcfs_remove(), dep %08x, v_usecount %d\n", dep, ndp->ni_vp->v_usecount);
  781. X#endif /* defined(PCFSDEBUG) */
  782. X    if (ddep == dep)
  783. X        vrele(DETOV(dep));
  784. X    else
  785. X        deput(dep);    /* causes pcfs_inactive() to be called via vrele() */
  786. X    deput(ddep);
  787. X    return error;
  788. X}
  789. X
  790. X/*
  791. X *  DOS filesystems don't know what links are.
  792. X */
  793. Xint
  794. Xpcfs_link(vp, ndp, p)
  795. X    struct vnode *vp;
  796. X    struct nameidata *ndp;
  797. X    struct proc *p;
  798. X{
  799. X    return EINVAL;
  800. X}
  801. X
  802. X/*
  803. X *  Renames on files require moving the denode to
  804. X *  a new hash queue since the denode's location is
  805. X *  used to compute which hash queue to put the file in.
  806. X *  Unless it is a rename in place.  For example "mv a b".
  807. X *
  808. X *  What follows is the basic algorithm:
  809. X *
  810. X *    if (file move) {
  811. X *        if (dest file exists) {
  812. X *            remove dest file
  813. X *        }
  814. X *        if (dest and src in same directory) {
  815. X *            rewrite name in existing directory slot
  816. X *        } else {
  817. X *            write new entry in dest directory
  818. X *            update offset and dirclust in denode
  819. X *            move denode to new hash chain
  820. X *            clear old directory entry
  821. X *        }
  822. X *    } else {  directory move
  823. X *        if (dest directory exists) {
  824. X *            if (dest is not empty) {
  825. X *                return ENOTEMPTY
  826. X *            }
  827. X *            remove dest directory
  828. X *        }
  829. X *        if (dest and src in same directory) {
  830. X *            rewrite name in existing entry
  831. X *        } else {
  832. X *            be sure dest is not a child of src directory
  833. X *            write entry in dest directory
  834. X *            update "." and ".." in moved directory
  835. X *            update offset and dirclust in denode
  836. X *            move denode to new hash chain
  837. X *            clear old directory entry for moved directory
  838. X *        }
  839. X *    }
  840. X *
  841. X *  On entry:
  842. X *    source's parent directory is unlocked
  843. X *    source file or directory is unlocked
  844. X *    destination's parent directory is locked
  845. X *    destination file or directory is locked if it exists
  846. X *
  847. X *  On exit:
  848. X *    all denodes should be released
  849. X *  Notes:
  850. X *    I'm not sure how the memory containing the pathnames
  851. X *    pointed at by the nameidata structures is freed, there
  852. X *    may be some memory bleeding for each rename done.
  853. X */
  854. Xint
  855. Xpcfs_rename(fndp, tndp, p)
  856. X    struct nameidata *fndp;
  857. X    struct nameidata *tndp;
  858. X    struct proc *p;
  859. X{
  860. X    unsigned char toname[11];
  861. X    int error;
  862. X    int newparent = 0;
  863. X    int sourceisadirectory = 0;
  864. X    unsigned long to_dirclust;
  865. X    unsigned long to_diroffset;
  866. X    unsigned long cn;
  867. X    daddr_t bn;
  868. X    struct denode *fddep;    /* from file's parent directory    */
  869. X    struct denode *fdep;    /* from file or directory    */
  870. X    struct denode *tddep;    /* to file's parent directory    */
  871. X    struct denode *tdep;    /* to file or directory        */
  872. X    struct pcfsmount *pmp;
  873. X    struct direntry *dotdotp;
  874. X    struct direntry *ep;
  875. X    struct buf *bp;
  876. X
  877. X#if defined(PCFSDEBUG)
  878. Xprintf("pcfs_rename(fndp %08x, tndp %08x, p %08x\n", fndp, tndp, p);
  879. X#endif /* defined(PCFSDEBUG) */
  880. X    fddep = VTODE(fndp->ni_dvp);
  881. X    fdep  = VTODE(fndp->ni_vp);
  882. X    tddep = VTODE(tndp->ni_dvp);
  883. X    tdep  = tndp->ni_vp ? VTODE(tndp->ni_vp) : NULL;
  884. X    pmp = fddep->de_pmp;
  885. X
  886. X/*
  887. X *  Convert the filename in tdnp into a dos filename.
  888. X *  We copy this into the denode and directory entry
  889. X *  for the destination file/directory.
  890. X */
  891. X    unix2dosfn((unsigned char *)tndp->ni_ptr, toname, tndp->ni_namelen);
  892. X
  893. X/*
  894. X *  At this point this is the lock state of the denodes:
  895. X *   fddep referenced
  896. X *   fdep  referenced
  897. X *   tddep locked
  898. X *   tdep  locked if it exists
  899. X */
  900. X
  901. X/*
  902. X *  Be sure we are not renaming ".", "..", or an alias of ".".
  903. X *  This leads to a crippled directory tree.  It's pretty tough
  904. X *  to do a "ls" or "pwd" with the "." directory entry missing,
  905. X *  and "cd .." doesn't work if the ".." entry is missing.
  906. X */
  907. X    if (fdep->de_Attributes & ATTR_DIRECTORY) {
  908. X        if ((fndp->ni_namelen == 1  &&  fndp->ni_ptr[0] == '.')  ||
  909. X            fddep == fdep  || /* won't happen ? */
  910. X            fndp->ni_isdotdot) {
  911. X            VOP_ABORTOP(tndp);
  912. X            vput(tndp->ni_dvp);
  913. X            if (tndp->ni_vp)
  914. X                vput(tndp->ni_vp);
  915. X            VOP_ABORTOP(fndp);
  916. X            vrele(fndp->ni_dvp);
  917. X            vrele(fndp->ni_vp);
  918. X            return EINVAL;
  919. X        }
  920. X        sourceisadirectory = 1;
  921. X    }
  922. X
  923. X/*
  924. X *  If we are renaming a directory, and the directory
  925. X *  is being moved to another directory, then we must
  926. X *  be sure the destination directory is not in the
  927. X *  subtree of the source directory.  This could orphan
  928. X *  everything under the source directory.
  929. X *  doscheckpath() unlocks the destination's parent
  930. X *  directory so we must look it up again to relock it.
  931. X */
  932. X    if (fddep->de_StartCluster != tddep->de_StartCluster)
  933. X        newparent = 1;
  934. X    if (sourceisadirectory && newparent) {
  935. X        if (tdep) {
  936. X            deput(tdep);
  937. X            tdep = NULL;
  938. X        }
  939. X        /* doscheckpath() deput()'s tddep */
  940. X        error = doscheckpath(fdep, tddep, tndp->ni_cred);
  941. X        tddep = NULL;
  942. X        if (error) {
  943. X            goto bad;
  944. X        }
  945. X        if ((tndp->ni_nameiop & SAVESTART) == 0)
  946. X            panic("pcfs_rename(): lost to startdir");
  947. X        if (error = lookup(tndp, p)) {
  948. X            goto bad;
  949. X        }
  950. X        tddep = VTODE(tndp->ni_dvp);
  951. X        tdep  = tndp->ni_vp ? VTODE(tndp->ni_vp) : NULL;
  952. X    }
  953. X
  954. X/*
  955. X *  If the destination exists, then be sure its type (file or dir)
  956. X *  matches that of the source.  And, if it is a directory make
  957. X *  sure it is empty.  Then delete the destination.
  958. X */
  959. X    if (tdep) {
  960. X        if (tdep->de_Attributes & ATTR_DIRECTORY) {
  961. X            if (!sourceisadirectory) {
  962. X                error = ENOTDIR;
  963. X                goto bad;
  964. X            }
  965. X            if (!dosdirempty(tdep)) {
  966. X                error = ENOTEMPTY;
  967. X                goto bad;
  968. X            }
  969. X        } else {    /* destination is file */
  970. X            if (sourceisadirectory) {
  971. X                error = EISDIR;
  972. X                goto bad;
  973. X            }
  974. X        }
  975. X        to_dirclust = tdep->de_dirclust;
  976. X        to_diroffset = tdep->de_diroffset;
  977. X        if (error = removede(tndp)) {
  978. X            goto bad;
  979. X        }
  980. X        deput(tdep);
  981. X        tdep = NULL;
  982. X
  983. X/*
  984. X *  Remember where the slot was for createde().
  985. X */
  986. X        tndp->ni_pcfs.pcfs_count = 1;
  987. X        tndp->ni_pcfs.pcfs_cluster = to_dirclust;
  988. X        tndp->ni_pcfs.pcfs_offset  = to_diroffset;
  989. X    }
  990. X
  991. X/*
  992. X *  If the source and destination are in the same
  993. X *  directory then just read in the directory entry,
  994. X *  change the name in the directory entry and
  995. X *  write it back to disk.
  996. X */
  997. X    if (newparent == 0) {
  998. X        /* tddep and fddep point to the same denode here */
  999. X        DELOCK(fdep);        /* tddep is already locked */
  1000. X        if (error = readde(fdep, &bp, &ep)) {
  1001. X            /* readde() does brelse() on error */
  1002. X            DEUNLOCK(fdep);
  1003. X            goto bad;
  1004. X        }
  1005. X        bcopy(toname, ep->deName, 11);
  1006. X        if (error = bwrite(bp)) {
  1007. X            DEUNLOCK(fdep);
  1008. X            goto bad;
  1009. X        }
  1010. X        bcopy(toname, fdep->de_Name, 11);    /* update denode */
  1011. X/*
  1012. X *  fdep locked
  1013. X *  fddep and tddep point to the same denode which is locked
  1014. X *  tdep is unlocked and unreferenced
  1015. X */
  1016. X    } else {
  1017. X/*
  1018. X *  If the source and destination are in different
  1019. X *  directories, then mark the entry in the source
  1020. X *  directory as deleted and write a new entry in the
  1021. X *  destination directory.  Then move the denode to
  1022. X *  the correct hash chain for its new location in
  1023. X *  the filesystem.  And, if we moved a directory,
  1024. X *  then update its .. entry to point to the new
  1025. X *  parent directory.
  1026. X */
  1027. X        DELOCK(fdep);
  1028. X        bcopy(toname, fdep->de_Name, 11);    /* update denode */
  1029. X        if (error = createde(fdep, tndp, (struct denode **)0)) {
  1030. X            /* should put back filename */
  1031. X            DEUNLOCK(fdep);
  1032. X            goto bad;
  1033. X        }
  1034. X        DELOCK(fddep);
  1035. X        if (error = readde(fdep, &bp, &ep)) { /* read source de */
  1036. X            DEUNLOCK(fdep);
  1037. X            DEUNLOCK(fddep);
  1038. X            goto bad;
  1039. X        }
  1040. X        ep->deName[0] = SLOT_DELETED;
  1041. X        if (error = bwrite(bp)) {
  1042. X            DEUNLOCK(fdep);
  1043. X            DEUNLOCK(fddep);
  1044. X            goto bad;
  1045. X        }
  1046. X        fdep->de_dirclust = tndp->ni_pcfs.pcfs_cluster;
  1047. X        fdep->de_diroffset = tndp->ni_pcfs.pcfs_offset;
  1048. X        reinsert(fdep);
  1049. X        DEUNLOCK(fddep);
  1050. X    }
  1051. X    /* fdep is still locked here */
  1052. X
  1053. X/*
  1054. X *  If we moved a directory to a new parent directory,
  1055. X *  then we must fixup the ".." entry in the moved
  1056. X *  directory.
  1057. X */
  1058. X    if (sourceisadirectory  &&  newparent) {
  1059. X        cn = fdep->de_StartCluster;
  1060. X        if (cn == PCFSROOT) {
  1061. X            /* this should never happen */
  1062. X            panic("pcfs_rename(): updating .. in root directory?\n");
  1063. X        } else {
  1064. X            bn = cntobn(pmp, cn);
  1065. X        }
  1066. X        error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
  1067. X            NOCRED, &bp);
  1068. X        if (error) {
  1069. X            brelse(bp);
  1070. X            /* should really panic here, fs is corrupt */
  1071. X            DEUNLOCK(fdep);
  1072. X            goto bad;
  1073. X        }
  1074. X        dotdotp = (struct direntry *)bp->b_un.b_addr + 1;
  1075. X        dotdotp->deStartCluster = tddep->de_StartCluster;
  1076. X        error = bwrite(bp);
  1077. X        DEUNLOCK(fdep);
  1078. X        if (error) {
  1079. X            /* should really panic here, fs is corrupt */
  1080. X            goto bad;
  1081. X        }
  1082. X    } else {
  1083. X        DEUNLOCK(fdep);
  1084. X    }
  1085. Xbad:;
  1086. X    vrele(DETOV(fdep));
  1087. X    vrele(DETOV(fddep));
  1088. X    if (tdep)
  1089. X        vput(DETOV(tdep));
  1090. X    if (tddep)
  1091. X        vput(DETOV(tddep));
  1092. X    return error;
  1093. X}
  1094. X
  1095. Xstruct {
  1096. X    struct direntry dot;
  1097. X    struct direntry dotdot;
  1098. X} dosdirtemplate = {
  1099. X    ".       ", "   ",        /* the . entry */
  1100. X    ATTR_DIRECTORY,            /* file attribute */
  1101. X    0,0,0,0,0,0,0,0,0,0,        /* resevered */
  1102. X    1234, 1234,            /* time and date */
  1103. X    0,                /* startcluster */
  1104. X    0,                /* filesize */
  1105. X    "..      ", "   ",        /* the .. entry */
  1106. X    ATTR_DIRECTORY,            /* file attribute */
  1107. X    0,0,0,0,0,0,0,0,0,0,        /* resevered */
  1108. X    1234, 1234,            /* time and date */
  1109. X    0,                /* startcluster */
  1110. X    0,                /* filesize */
  1111. X};
  1112. X
  1113. Xint
  1114. Xpcfs_mkdir(ndp, vap, p)
  1115. X    struct nameidata *ndp;
  1116. X    struct vattr *vap;
  1117. X    struct proc *p;
  1118. X{
  1119. X    int bn;
  1120. X    int error;
  1121. X    unsigned long newcluster;
  1122. X    struct denode *pdep;
  1123. X    struct denode *ndep;
  1124. X    struct vnode *pvp;
  1125. X    struct direntry *denp;
  1126. X    struct denode ndirent;
  1127. X    struct pcfsmount *pmp;
  1128. X    struct buf *bp;
  1129. X
  1130. X    pvp = ndp->ni_dvp;
  1131. X    pdep = VTODE(pvp);
  1132. X
  1133. X/*
  1134. X *  If this is the root directory and there is no space left
  1135. X *  we can't do anything.  This is because the root directory
  1136. X *  can not change size.
  1137. X */
  1138. X    if (pdep->de_StartCluster == PCFSROOT  &&  ndp->ni_pcfs.pcfs_count == 0) {
  1139. X        free(ndp->ni_pnbuf, M_NAMEI);
  1140. X        deput(pdep);
  1141. X        return ENOSPC;
  1142. X    }
  1143. X
  1144. X    pmp = pdep->de_pmp;
  1145. X
  1146. X/*
  1147. X *  Allocate a cluster to hold the about to be created directory.
  1148. X */
  1149. X    if (error = clusteralloc(pmp, &newcluster, CLUST_EOFE)) {
  1150. X        free(ndp->ni_pnbuf, M_NAMEI);
  1151. X        deput(pdep);
  1152. X        return error;
  1153. X    }
  1154. X
  1155. X/*
  1156. X *  Now fill the cluster with the "." and ".." entries.
  1157. X *  And write the cluster to disk.  This way it is there
  1158. X *  for the parent directory to be pointing at if there
  1159. X *  were a crash.
  1160. X */
  1161. X    bn = cntobn(pmp, newcluster);
  1162. X    bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster); /* always succeeds */
  1163. X    bzero(bp->b_un.b_addr, pmp->pm_bpcluster);
  1164. X    bcopy(&dosdirtemplate, bp->b_un.b_addr, sizeof dosdirtemplate);
  1165. X    denp = (struct direntry *)bp->b_un.b_addr;
  1166. X    denp->deStartCluster = newcluster;
  1167. X    unix2dostime(&time, (union dosdate *)&denp->deDate,
  1168. X        (union dostime *)&denp->deTime);
  1169. X    denp++;
  1170. X    denp->deStartCluster = pdep->de_StartCluster;
  1171. X    unix2dostime(&time, (union dosdate *)&denp->deDate,
  1172. X        (union dostime *)&denp->deTime);
  1173. X    if (error = bwrite(bp)) {
  1174. X        clusterfree(pmp, newcluster);
  1175. X        free(ndp->ni_pnbuf, M_NAMEI);
  1176. X        deput(pdep);
  1177. X        return error;
  1178. X    }
  1179. X
  1180. X/*
  1181. X *  Now build up a directory entry pointing to the newly
  1182. X *  allocated cluster.  This will be written to an empty
  1183. X *  slot in the parent directory.
  1184. X */
  1185. X    ndep = &ndirent;
  1186. X    bzero(ndep, sizeof(*ndep));
  1187. X    unix2dosfn((unsigned char *)ndp->ni_ptr, ndep->de_Name, ndp->ni_namelen);
  1188. X    unix2dostime(&time, (union dosdate *)&ndep->de_Date,
  1189. X        (union dostime *)&ndep->de_Time);
  1190. X    ndep->de_StartCluster = newcluster;
  1191. X    ndep->de_Attributes = ATTR_DIRECTORY;
  1192. X    ndep->de_pmp = pmp;    /* createde() needs this    */
  1193. X
  1194. X    error = createde(ndep, ndp, &ndep);
  1195. X    if (error) {
  1196. X        clusterfree(pmp, newcluster);
  1197. X    } else {
  1198. X        ndp->ni_vp = DETOV(ndep);
  1199. X    }
  1200. X    free(ndp->ni_pnbuf, M_NAMEI);
  1201. X#if defined(PCFSDEBUG)
  1202. Xprintf("pcfs_mkdir(): deput(%08x), vnode %08x\n", pdep, DETOV(pdep));
  1203. X#endif /* defined(PCFSDEBUG) */
  1204. X    deput(pdep);
  1205. X    return error;
  1206. X}
  1207. X
  1208. Xint
  1209. Xpcfs_rmdir(ndp, p)
  1210. X    struct nameidata *ndp;
  1211. X    struct proc *p;
  1212. X{
  1213. X    struct denode *ddep;
  1214. X    struct denode *dep;
  1215. X    int error = 0;
  1216. X
  1217. X    ddep = VTODE(ndp->ni_dvp);    /* parent dir of dir to delete    */
  1218. X    dep  = VTODE(ndp->ni_vp);    /* directory to delete    */
  1219. X
  1220. X/*
  1221. X *  Don't let "rmdir ." go thru.
  1222. X */
  1223. X    if (ddep == dep) {
  1224. X        vrele(DETOV(dep));
  1225. X        deput(dep);
  1226. X        return EINVAL;
  1227. X    }
  1228. X
  1229. X/*
  1230. X *  Be sure the directory being deleted is empty.
  1231. X */
  1232. X    if (dosdirempty(dep) == 0) {
  1233. X        error = ENOTEMPTY;
  1234. X        goto out;
  1235. X    }
  1236. X
  1237. X/*
  1238. X *  Delete the entry from the directory.  For dos filesystems
  1239. X *  this gets rid of the directory entry on disk, the in memory
  1240. X *  copy still exists but the de_refcnt is <= 0.  This prevents
  1241. X *  it from being found by deget().  When the deput() on dep is
  1242. X *  done we give up access and eventually pcfs_reclaim() will
  1243. X *  be called which will remove it from the denode cache.
  1244. X */
  1245. X    if (error = removede(ndp))
  1246. X        goto out;
  1247. X
  1248. X/*
  1249. X *  This is where we decrement the link count in the parent
  1250. X *  directory.  Since dos filesystems don't do this we just
  1251. X *  purge the name cache and let go of the parent directory
  1252. X *  denode.
  1253. X */
  1254. X    cache_purge(DETOV(ddep));
  1255. X    deput(ddep);
  1256. X    ndp->ni_dvp = NULL;    /* getting rid of parent dir pointer? */
  1257. X
  1258. X/*
  1259. X *  Truncate the directory that is being deleted.
  1260. X */
  1261. X    error = detrunc(dep, (u_long)0, IO_SYNC);
  1262. X    cache_purge(DETOV(dep));
  1263. X
  1264. Xout:;
  1265. X    if (ndp->ni_dvp)
  1266. X        deput(ddep);
  1267. X    deput(dep);
  1268. X    return error;
  1269. X}
  1270. X
  1271. X/*
  1272. X *  DOS filesystems don't know what symlinks are.
  1273. X */
  1274. Xint
  1275. Xpcfs_symlink(ndp, vap, target, p)
  1276. X    struct nameidata *ndp;
  1277. X    struct vattr *vap;
  1278. X    char *target;
  1279. X    struct proc *p;
  1280. X{
  1281. X    return EINVAL;
  1282. X}
  1283. X
  1284. X/*
  1285. X *  Dummy dirents to simulate the "." and ".." entries
  1286. X *  of the root directory in a dos filesystem.  Dos doesn't
  1287. X *  provide these.
  1288. X *  Note that each entry must be the same size as a dos
  1289. X *  directory entry (32 bytes).
  1290. X */
  1291. Xstruct dos_dirent {
  1292. X    u_long d_fileno;
  1293. X    u_short d_reclen;
  1294. X    u_short d_namlen;
  1295. X    u_char d_name[24];
  1296. X} rootdots[2] = {
  1297. X    {
  1298. X    1,                /* d_fileno            */
  1299. X    sizeof(struct direntry),    /* d_reclen            */
  1300. X    1,                /* d_namlen            */
  1301. X    "."                /* d_name            */
  1302. X    },
  1303. X    {
  1304. X    1,                /* d_fileno            */
  1305. X    sizeof(struct direntry),    /* d_reclen            */
  1306. X    2,                /* d_namlen            */
  1307. X    ".."                /* d_name            */
  1308. X    }
  1309. X};
  1310. X
  1311. Xint
  1312. Xpcfs_readdir(vp, uio, cred, eofflagp)
  1313. X    struct vnode *vp;
  1314. X    struct uio *uio;
  1315. X    struct ucred *cred;
  1316. X    int *eofflagp;
  1317. X{
  1318. X    int error = 0;
  1319. X    int diff;
  1320. X    long n;
  1321. X    long on;
  1322. X    long lost;
  1323. X    long count;
  1324. X    unsigned long cn;
  1325. X    unsigned long fileno;
  1326. X    long bias = 0;
  1327. X    daddr_t bn;
  1328. X    daddr_t lbn;
  1329. X    struct buf *bp;
  1330. X    struct denode *dep = VTODE(vp);
  1331. X    struct pcfsmount *pmp = dep->de_pmp;
  1332. X    struct direntry *dentp;
  1333. X    struct dirent *prev;
  1334. X    struct dirent *crnt;
  1335. X    unsigned char dirbuf[512];    /* holds converted dos directories */
  1336. Xint i=0;
  1337. X
  1338. X#if defined(PCFSDEBUG)
  1339. Xprintf("pcfs_readdir(): vp %08x, uio %08x, cred %08x, eofflagp %08x\n",
  1340. X    vp, uio, cred, eofflagp);
  1341. X#endif /* defined(PCFSDEBUG) */
  1342. X
  1343. X/*
  1344. X *  pcfs_readdir() won't operate properly on regular files
  1345. X *  since it does i/o only with the the filesystem vnode,
  1346. X *  and hence can retrieve the wrong block from the buffer
  1347. X *  cache for a plain file.  So, fail attempts to readdir()
  1348. X *  on a plain file.
  1349. X */
  1350. X    if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
  1351. X        return ENOTDIR;
  1352. X
  1353. X/*
  1354. X *  If the user buffer is smaller than the size of one dos
  1355. X *  directory entry or the file offset is not a multiple of
  1356. X *  the size of a directory entry, then we fail the read.
  1357. X */
  1358. X    count = uio->uio_resid & ~(sizeof(struct direntry)-1);
  1359. X    lost  = uio->uio_resid - count;
  1360. X    if (count < sizeof(struct direntry)  ||
  1361. X        (uio->uio_offset & (sizeof(struct direntry)-1)))
  1362. X        return EINVAL;
  1363. X    uio->uio_resid = count;
  1364. X    uio->uio_iov->iov_len = count; /* does this assume the vector is big enough? */
  1365. X
  1366. X/*
  1367. X *  If they are reading from the root directory then,
  1368. X *  we simulate the . and .. entries since these don't
  1369. X *  exist in the root directory.  We also set the offset
  1370. X *  bias to make up for having to simulate these entries.
  1371. X *  By this I mean that at file offset 64 we read the first entry
  1372. X *  in the root directory that lives on disk.
  1373. X */
  1374. X    if (dep->de_StartCluster == PCFSROOT) {
  1375. X/*printf("pcfs_readdir(): going after . or .. in root dir, offset %d\n",
  1376. X    uio->uio_offset);*/
  1377. X        bias = 2*sizeof(struct direntry);
  1378. X        if (uio->uio_offset < 2*sizeof(struct direntry)) {
  1379. X            error = uiomove((char *)rootdots + uio->uio_offset,
  1380. X                sizeof rootdots - uio->uio_offset, uio);
  1381. X            goto out;
  1382. X        }
  1383. X    }
  1384. X    do {
  1385. X        lbn = (uio->uio_offset-bias) >> pmp->pm_cnshift;
  1386. X        on  = (uio->uio_offset-bias) &  pmp->pm_crbomask;
  1387. X        n = MIN((unsigned)(pmp->pm_bpcluster - on), uio->uio_resid);
  1388. X        diff = dep->de_FileSize - (uio->uio_offset - bias);
  1389. X        if (diff <= 0)
  1390. X            return 0;
  1391. X        if (diff < n)
  1392. X            n = diff;
  1393. X        error = pcbmap(dep, lbn, &bn, &cn);
  1394. X        if (error)
  1395. X            break;
  1396. X        error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, &bp);
  1397. X        n = MIN(n, pmp->pm_bpcluster - bp->b_resid);
  1398. X        if (error) {
  1399. X            brelse(bp);
  1400. X            return error;
  1401. X        }
  1402. X
  1403. X/*
  1404. X *  code to convert from dos directory entries to ufs directory entries
  1405. X */
  1406. X        dentp = (struct direntry *)bp->b_un.b_addr + on;
  1407. X        prev = 0;
  1408. X        crnt = (struct dirent *)dirbuf;
  1409. X        while ((char *)dentp < bp->b_un.b_addr + n) {
  1410. X/*printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
  1411. X    dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);*/
  1412. X/*
  1413. X *  If we have an empty entry or a slot from a deleted
  1414. X *  file, or a volume label entry just concatenate its
  1415. X *  space onto the end of the previous entry or,
  1416. X *  manufacture an empty entry if there is no previous
  1417. X *  entry.
  1418. X *  If the entry is empty then set a flag saying finish
  1419. X *  out the block but signal an end of file since empty
  1420. X *  slots mean there are no further entries of interest
  1421. X *  in the directory.
  1422. X */
  1423. X            if (dentp->deName[0] == SLOT_EMPTY  ||
  1424. X                dentp->deName[0] == SLOT_DELETED  ||
  1425. X                (dentp->deAttributes & ATTR_VOLUME)) {
  1426. X                if (prev) {
  1427. X                    prev->d_reclen += sizeof(struct direntry);
  1428. X                } else {
  1429. X                    prev = crnt;
  1430. X                    prev->d_fileno = 0;
  1431. X                    prev->d_reclen = sizeof(struct direntry);
  1432. X                    prev->d_namlen = 0;
  1433. X                    prev->d_name[0] = 0;
  1434. X                }
  1435. X            } else {
  1436. X                /* this computation of d_fileno must match
  1437. X                 * the computation of va_fileid in pcfs_getattr */
  1438. X                if (dentp->deAttributes & ATTR_DIRECTORY) {
  1439. X                    /* if this is the root directory */
  1440. X                    if ((fileno = dentp->deStartCluster) == PCFSROOT)
  1441. X                        fileno = 1;
  1442. X                } else {
  1443. X                    /* if the file's dirent lives in root dir */
  1444. X                    if ((fileno = cn) == PCFSROOT)
  1445. X                        fileno = 1;
  1446. X                    fileno = (fileno << 16) |
  1447. X                        ((dentp - (struct direntry *)bp->b_un.b_addr) & 0xffff);
  1448. X                }
  1449. X                crnt->d_fileno = fileno;
  1450. X                crnt->d_reclen = sizeof(struct direntry);
  1451. X                crnt->d_namlen = dos2unixfn(dentp->deName,
  1452. X                    (unsigned char *)crnt->d_name);
  1453. X/*printf("readdir: file %s, fileno %08x, attr %02x, start %08x\n",
  1454. X    crnt->d_name, crnt->d_fileno, dentp->deAttributes, dentp->deStartCluster);*/
  1455. X                prev = crnt;
  1456. X            }
  1457. X            crnt = (struct dirent *)((char *)crnt + sizeof(struct direntry));
  1458. X
  1459. X/*
  1460. X *  If our intermediate buffer is full then copy
  1461. X *  its contents to user space.  I would just
  1462. X *  use the buffer the buf header points to but,
  1463. X *  I'm afraid that when we brelse() it someone else
  1464. X *  might find it in the cache and think its contents
  1465. X *  are valid.  Maybe there is a way to invalidate
  1466. X *  the buffer before brelse()'ing it.
  1467. X */
  1468. X            if ((unsigned char *)crnt >= &dirbuf[sizeof dirbuf]) {
  1469. X                error = uiomove(dirbuf, n, uio);
  1470. X                if (error)
  1471. X                    break;
  1472. X                prev = 0;
  1473. X                crnt = (struct dirent *)dirbuf;
  1474. X            }
  1475. X            dentp++;
  1476. X        }
  1477. X
  1478. X/*
  1479. X *  If we have read everything from this block or
  1480. X *  have read to end of file then we are done with
  1481. X *  this block.  Mark it to say the buffer can be reused if
  1482. X *  need be.
  1483. X */
  1484. X        if (n + on == pmp->pm_bpcluster  ||
  1485. X            (uio->uio_offset-bias) == dep->de_FileSize)
  1486. X            bp->b_flags |= B_AGE;
  1487. X        brelse(bp);
  1488. X    } while (error == 0  &&  uio->uio_resid > 0  && n != 0);
  1489. Xout:;
  1490. X    uio->uio_resid += lost;
  1491. X
  1492. X/*
  1493. X *  I don't know why we bother setting this eofflag, getdirentries()
  1494. X *  in vfs_syscalls.c doesn't bother to look at it when we return.
  1495. X */
  1496. X    if (dep->de_FileSize - uio->uio_offset - bias <= 0)
  1497. X        *eofflagp = 1;
  1498. X    else
  1499. X        *eofflagp = 0;
  1500. X    return error;
  1501. X}
  1502. X
  1503. X/*
  1504. X *  DOS filesystems don't know what symlinks are.
  1505. X */
  1506. Xint
  1507. Xpcfs_readlink(vp, uio, cred)
  1508. X    struct vnode *vp;
  1509. X    struct uio *uio;
  1510. X    struct ucred *cred;
  1511. X{
  1512. X    return EINVAL;
  1513. X}
  1514. X
  1515. Xint
  1516. Xpcfs_abortop(ndp)
  1517. X    struct nameidata *ndp;
  1518. X{
  1519. X    if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
  1520. X        FREE(ndp->ni_pnbuf, M_NAMEI);
  1521. X    return 0;
  1522. X}
  1523. X
  1524. Xint
  1525. Xpcfs_lock(vp)
  1526. X    struct vnode *vp;
  1527. X{
  1528. X    struct denode *dep = VTODE(vp);
  1529. X
  1530. X    DELOCK(dep);
  1531. X    return 0;
  1532. X}
  1533. X
  1534. Xint
  1535. Xpcfs_unlock(vp)
  1536. X    struct vnode *vp;
  1537. X{
  1538. X    struct denode *dep = VTODE(vp);
  1539. X
  1540. X    if (!(dep->de_flag & DELOCKED))
  1541. X        panic("pcfs_unlock: denode not locked");
  1542. X    DEUNLOCK(dep);
  1543. X    return 0;
  1544. X}
  1545. X
  1546. Xint
  1547. Xpcfs_islocked(vp)
  1548. X    struct vnode *vp;
  1549. X{
  1550. X    return VTODE(vp)->de_flag & DELOCKED ? 1 : 0;
  1551. X}
  1552. X
  1553. X/*
  1554. X *  vp - address of vnode file the file
  1555. X *  bn - which cluster we are interested in mapping to
  1556. X *    a filesystem block number.
  1557. X *  vpp - returns the vnode for the block special file
  1558. X *    holding the filesystem containing the file of interest
  1559. X *  bnp - address of where to return the filesystem
  1560. X *    relative block number
  1561. X */
  1562. Xint
  1563. Xpcfs_bmap(vp, bn, vpp, bnp)
  1564. X    struct vnode *vp;
  1565. X    daddr_t bn;
  1566. X    struct vnode **vpp;
  1567. X    daddr_t *bnp;
  1568. X{
  1569. X    struct denode *dep = VTODE(vp);
  1570. X    struct pcfsmount *pmp = dep->de_pmp;
  1571. X
  1572. X    if (vpp != NULL)
  1573. X        *vpp = dep->de_devvp;
  1574. X    if (bnp == NULL)
  1575. X        return 0;
  1576. X    return pcbmap(dep, bn << (pmp->pm_cnshift - pmp->pm_bnshift), bnp, 0);
  1577. X}
  1578. X
  1579. Xint
  1580. Xpcfs_strategy(bp)
  1581. X    struct buf *bp;
  1582. X{
  1583. X    struct denode *dep = VTODE(bp->b_vp);
  1584. X    struct pcfsmount *pmp = dep->de_pmp;
  1585. X    struct vnode *vp;
  1586. X    int error;
  1587. X
  1588. X    if (bp->b_vp->v_type == VBLK  ||  bp->b_vp->v_type == VCHR)
  1589. X        panic("pcfs_strategy: spec");
  1590. X/*
  1591. X *  If we don't already know the filesystem relative
  1592. X *  block number then get it using pcbmap().  If pcbmap()
  1593. X *  returns the block number as -1 then we've got a hole
  1594. X *  in the file.  DOS filesystems don't allow files with
  1595. X *  holes, so we shouldn't ever see this.
  1596. X */
  1597. X    if (bp->b_blkno == bp->b_lblkno) {
  1598. X        if (error = pcbmap(dep,
  1599. X            bp->b_lblkno << (pmp->pm_cnshift - pmp->pm_bnshift),
  1600. X            &bp->b_blkno, 0))
  1601. X            return error;
  1602. X        if ((long)bp->b_blkno == -1)
  1603. X            clrbuf(bp);
  1604. X    }
  1605. X    if ((long)bp->b_blkno == -1) {
  1606. X        biodone(bp);
  1607. X        return 0;
  1608. X    }
  1609. X#ifdef DIAGNOSTIC
  1610. X#endif /* defined(DIAGNOSTIC) */
  1611. X/*
  1612. X *  Read/write the block from/to the disk that contains the desired
  1613. X *  file block.
  1614. X */
  1615. X    vp = dep->de_devvp;
  1616. X    bp->b_dev = vp->v_rdev;
  1617. X    (*(vp->v_op->vop_strategy))(bp);
  1618. X    return 0;
  1619. X}
  1620. X
  1621. Xint
  1622. Xpcfs_print(vp)
  1623. X    struct vnode *vp;
  1624. X{
  1625. X    struct denode *dep = VTODE(vp);
  1626. X
  1627. X    printf("tag VT_PCFS, startcluster %d, dircluster %d, diroffset %d ",
  1628. X        dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset);
  1629. X    printf(" dev %d, %d, %s\n",
  1630. X        major(dep->de_dev), minor(dep->de_dev),
  1631. X        dep->de_flag & DELOCKED ? "(LOCKED)" : "");
  1632. X    if (dep->de_spare0) {
  1633. X        printf("    owner pid %d", dep->de_spare0);
  1634. X        if (dep->de_spare1)
  1635. X            printf(" waiting pid %d", dep->de_spare1);
  1636. X        printf("\n");
  1637. X    }
  1638. X}
  1639. X
  1640. Xint
  1641. Xpcfs_advlock(vp, id, op, fl, flags)
  1642. X    struct vnode *vp;
  1643. X    caddr_t id;
  1644. X    int op;
  1645. X    struct flock *fl;
  1646. X    int flags;
  1647. X{
  1648. X    return EINVAL;        /* we don't do locking yet        */
  1649. X}
  1650. X
  1651. Xstruct vnodeops pcfs_vnodeops = {
  1652. X    pcfs_lookup,
  1653. X    pcfs_create,
  1654. X    pcfs_mknod,
  1655. X    pcfs_open,
  1656. X    pcfs_close,
  1657. X    pcfs_access,
  1658. X    pcfs_getattr,
  1659. X    pcfs_setattr,
  1660. X    pcfs_read,
  1661. X    pcfs_write,
  1662. X    pcfs_ioctl,
  1663. X    pcfs_select,
  1664. X    pcfs_mmap,
  1665. X    pcfs_fsync,
  1666. X    pcfs_seek,
  1667. X    pcfs_remove,
  1668. X    pcfs_link,
  1669. X    pcfs_rename,
  1670. X    pcfs_mkdir,
  1671. X    pcfs_rmdir,
  1672. X    pcfs_symlink,
  1673. X    pcfs_readdir,
  1674. X    pcfs_readlink,
  1675. X    pcfs_abortop,
  1676. X    pcfs_inactive,
  1677. X    pcfs_reclaim,
  1678. X    pcfs_lock,
  1679. X    pcfs_unlock,
  1680. X    pcfs_bmap,
  1681. X    pcfs_strategy,
  1682. X    pcfs_print,
  1683. X    pcfs_islocked,
  1684. X    pcfs_advlock,
  1685. X};
  1686. END-of-/sys/pcfs/pcfs_vnops.c
  1687. exit
  1688.  
  1689.