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

  1. Xref: sparky comp.unix.bsd:9006 alt.sources:2542
  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 4/5
  6. Message-ID: <bdRJ03eIbb0c00@amdahl.uts.amdahl.com>
  7. Date: 17 Nov 92 17:28:05 GMT
  8. Organization: Amdahl Corporation, Sunnyvale CA
  9. Lines: 1648
  10.  
  11.  
  12. # This is a shell archive.  Save it in a file, remove anything before
  13. # this line, and then unpack it by entering "sh file".  Note, it may
  14. # create directories; files and directories will be owned by you and
  15. # have default permissions.
  16. #
  17. # This archive contains:
  18. #
  19. #    /sys/pcfs/pcfs_vfsops.c
  20. #    /sys/pcfs/pcfs_denode.c
  21. #    /sys/pcfs/pcfs_conv.c
  22. #
  23. echo x - /sys/pcfs/pcfs_vfsops.c
  24. sed 's/^X//' >/sys/pcfs/pcfs_vfsops.c << 'END-of-/sys/pcfs/pcfs_vfsops.c'
  25. X/*
  26. X *  Written by Paul Popelka (paulp@uts.amdahl.com)
  27. X *
  28. X *  You can do anything you want with this software,
  29. X *    just don't say you wrote it,
  30. X *    and don't remove this notice.
  31. X *
  32. X *  This software is provided "as is".
  33. X *
  34. X *  The author supplies this software to be publicly
  35. X *  redistributed on the understanding that the author
  36. X *  is not responsible for the correct functioning of
  37. X *  this software in any circumstances and is not liable
  38. X *  for any damages caused by this software.
  39. X *
  40. X *  October 1992
  41. X */
  42. X
  43. X#include "param.h"
  44. X#include "systm.h"
  45. X#include "namei.h"
  46. X#include "proc.h"
  47. X#include "kernel.h"
  48. X#include "vnode.h"
  49. X#include "specdev.h"    /* defines v_rdev    */
  50. X#include "mount.h"
  51. X#include "buf.h"
  52. X#include "file.h"
  53. X#include "malloc.h"
  54. X
  55. X#include "bpb.h"
  56. X#include "bootsect.h"
  57. X#include "direntry.h"
  58. X#include "denode.h"
  59. X#include "pcfsmount.h"
  60. X#include "fat.h"
  61. X
  62. Xint pcfsdoforce = 0;    /* 1 = force unmount */
  63. X
  64. X/*
  65. X *  mp -
  66. X *  path - addr in user space of mount point (ie /usr or whatever)
  67. X *  data - addr in user space of mount params including the
  68. X *         name of the block special file to treat as a filesystem.
  69. X *  ndp  - 
  70. X *  p    -
  71. X */
  72. Xint
  73. Xpcfs_mount(mp, path, data, ndp, p)
  74. X    struct mount *mp;
  75. X    char *path;
  76. X    caddr_t data;
  77. X    struct nameidata *ndp;
  78. X    struct proc *p;
  79. X{
  80. X    struct vnode *devvp;    /* vnode for blk device to mount    */
  81. X    struct pcfs_args args;    /* will hold data from mount request    */
  82. X    struct pcfsmount *pmp;    /* pcfs specific mount control block    */
  83. X    int error;
  84. X    u_int size;
  85. X
  86. X/*
  87. X *  Copy in the args for the mount request.
  88. X */
  89. X    if (error = copyin(data, (caddr_t)&args, sizeof(struct pcfs_args)))
  90. X        return error;
  91. X
  92. X/*
  93. X *  Check to see if they want it to be an exportable
  94. X *  filesystem via nfs.  And, if they do, should it
  95. X *  be read only, and what uid is root to be mapped
  96. X *  to.
  97. X */
  98. X    if ((args.exflags & MNT_EXPORTED)  ||  (mp->mnt_flag & MNT_EXPORTED)) {
  99. X        if (args.exflags & MNT_EXPORTED)
  100. X            mp->mnt_flag |= MNT_EXPORTED;
  101. X        else
  102. X            mp->mnt_flag &= ~MNT_EXPORTED;
  103. X        if (args.exflags & MNT_EXRDONLY)
  104. X            mp->mnt_flag |= MNT_EXRDONLY;
  105. X        else
  106. X            mp->mnt_flag &= ~MNT_EXRDONLY;
  107. X        mp->mnt_exroot = args.exroot;
  108. X    }
  109. X
  110. X/*
  111. X *  If they just want to update then be sure we can
  112. X *  do what is asked.  Can't change a filesystem from
  113. X *  read/write to read only.  Why?
  114. X *  And if they've supplied a new filesystem then we
  115. X *  continue, otherwise return.
  116. X */
  117. X    if (mp->mnt_flag & MNT_UPDATE) {
  118. X        pmp = (struct pcfsmount *)mp->mnt_data;
  119. X        if (pmp->pm_ronly  &&  (mp->mnt_flag & MNT_RDONLY) == 0)
  120. X            pmp->pm_ronly = 0;
  121. X        if (args.fspec == 0)
  122. X            return 0;
  123. X    }
  124. X
  125. X/*
  126. X *  Now, lookup the name of the block device this
  127. X *  mount or name update request is to apply to.
  128. X */
  129. X    ndp->ni_nameiop = LOOKUP | FOLLOW;
  130. X    ndp->ni_segflg  = UIO_USERSPACE;
  131. X    ndp->ni_dirp    = args.fspec;
  132. X    if (error = namei(ndp, p))
  133. X        return error;
  134. X
  135. X/*
  136. X *  Be sure they've given us a block device to treat
  137. X *  as a filesystem.  And, that its major number is
  138. X *  within the bdevsw table.
  139. X */
  140. X    devvp = ndp->ni_vp;
  141. X    if (devvp->v_type != VBLK) {
  142. X        vrele(devvp);        /* namei() acquires this?    */
  143. X        return ENOTBLK;
  144. X    }
  145. X    if (major(devvp->v_rdev) >= nblkdev) {
  146. X        vrele(devvp);
  147. X        return ENXIO;
  148. X    }
  149. X
  150. X/*
  151. X *  If this is an update, then make sure the vnode
  152. X *  for the block special device is the same as the
  153. X *  one our filesystem is in.
  154. X */
  155. X    if (mp->mnt_flag & MNT_UPDATE) {
  156. X        if (devvp != pmp->pm_devvp)
  157. X            error = EINVAL;
  158. X        else
  159. X            vrele(devvp);
  160. X    } else {
  161. X
  162. X/*
  163. X *  Well, it's not an update, it's a real mount request.
  164. X *  Time to get dirty.
  165. X */
  166. X        error = mountpcfs(devvp, mp, p);
  167. X    }
  168. X    if (error) {
  169. X        vrele(devvp);
  170. X        return error;
  171. X    }
  172. X
  173. X/*
  174. X *  Copy in the name of the directory the filesystem
  175. X *  is to be mounted on.
  176. X *  Then copy in the name of the block special file
  177. X *  representing the filesystem being mounted.
  178. X *  And we clear the remainder of the character strings
  179. X *  to be tidy.
  180. X *  Then, we try to fill in the filesystem stats structure
  181. X *  as best we can with whatever applies from a dos file
  182. X *  system.
  183. X */
  184. X    pmp = (struct pcfsmount *)mp->mnt_data;
  185. X    copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname,
  186. X        sizeof(mp->mnt_stat.f_mntonname)-1, &size);
  187. X    bzero(mp->mnt_stat.f_mntonname + size,
  188. X        sizeof(mp->mnt_stat.f_mntonname) - size);
  189. X    copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN-1, &size);
  190. X    bzero(mp->mnt_stat.f_mntfromname + size,
  191. X        MNAMELEN - size);
  192. X    (void)pcfs_statfs(mp, &mp->mnt_stat, p);
  193. X#if defined(PCFSDEBUG)
  194. Xprintf("pcfs_mount(): mp %x, pmp %x, inusemap %x\n", mp, pmp, pmp->pm_inusemap);
  195. X#endif /* defined(PCFSDEBUG) */
  196. X    return 0;
  197. X}
  198. X
  199. Xint
  200. Xmountpcfs(devvp, mp, p)
  201. X    struct vnode *devvp;
  202. X    struct mount *mp;
  203. X    struct proc *p;
  204. X{
  205. X    int i;
  206. X    int bpc;
  207. X    int bit;
  208. X    int error = 0;
  209. X    int needclose;
  210. X    int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
  211. X    dev_t dev = devvp->v_rdev;
  212. X    union bootsector *bsp;
  213. X    struct pcfsmount *pmp;
  214. X    struct buf *bp0 = 0;
  215. X    struct byte_bpb33 *b33;
  216. X    struct byte_bpb50 *b50;
  217. X
  218. X/*
  219. X *  Multiple mounts of the same block special file
  220. X *  aren't allowed.  Make sure no one else has the
  221. X *  special file open.  And flush any old buffers
  222. X *  from this filesystem.  Presumably this prevents
  223. X *  us from running into buffers that are the wrong
  224. X *  blocksize.
  225. X *  NOTE: mountedon() is a part of the ufs filesystem.
  226. X *  If the ufs filesystem is not gen'ed into the system
  227. X *  we will get an unresolved reference.
  228. X */
  229. X    if (error = mountedon(devvp)) {
  230. X        return error;
  231. X    }
  232. X    if (vcount(devvp) > 1)
  233. X        return EBUSY;
  234. X    vinvalbuf(devvp, 1);
  235. X
  236. X/*
  237. X *  Now open the block special file.
  238. X *  I wonder if you need this for the VOP_IOCTL() or
  239. X *  for the bread() later.  Or, maybe both.
  240. X */
  241. X    if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p)) {
  242. X        return error;
  243. X    }
  244. X    needclose = 1;
  245. X#if defined(HDSUPPORT)
  246. X/*
  247. X *  Put this in when we support reading dos filesystems
  248. X *  from partitioned harddisks.
  249. X */
  250. X    if (VOP_IOCTL(devvp, DIOCGPART, &pcfspart, FREAD, NOCRED, p) == 0) {
  251. X    }
  252. X#endif /* defined(HDSUPPORT) */
  253. X
  254. X/*
  255. X *  Read the boot sector of the filesystem, and then
  256. X *  check the boot signature.  If not a dos boot sector
  257. X *  then error out.  We could also add some checking on
  258. X *  the bsOemName field.  So far I've seen the following
  259. X *  values:
  260. X *    "IBM  3.3"
  261. X *    "MSDOS3.3"
  262. X *    "MSDOS5.0"
  263. X */
  264. X    if (error = bread(devvp, 0, 512, NOCRED, &bp0)) {
  265. X        goto error_exit;
  266. X    }
  267. X    bsp = (union bootsector *)bp0->b_un.b_addr;
  268. X    b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
  269. X    b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
  270. X    if (bsp->bs50.bsBootSectSig != BOOTSIG) {
  271. X        error = EINVAL;
  272. X        goto error_exit;
  273. X    }
  274. X
  275. X    pmp = (struct pcfsmount *)malloc(sizeof *pmp, M_PCFSMNT, M_WAITOK);
  276. X    if (pmp == NULL) {
  277. X        error = ENOMEM;
  278. X        goto error_exit;
  279. X    }
  280. X    pmp->pm_inusemap = NULL;
  281. X    pmp->pm_mountp = mp;
  282. X
  283. X/*
  284. X *  Compute several useful quantities from the bpb in
  285. X *  the bootsector.  Copy in the dos 5 variant of the
  286. X *  bpb then fix up the fields that are different between
  287. X *  dos 5 and dos 3.3.
  288. X */
  289. X    pmp->pm_BytesPerSec  = getushort(b50->bpbBytesPerSec);
  290. X    pmp->pm_SectPerClust = b50->bpbSecPerClust;
  291. X    pmp->pm_ResSectors   = getushort(b50->bpbResSectors);
  292. X    pmp->pm_FATs         = b50->bpbFATs;
  293. X    pmp->pm_RootDirEnts  = getushort(b50->bpbRootDirEnts);
  294. X    pmp->pm_Sectors      = getushort(b50->bpbSectors);
  295. X    pmp->pm_Media        = b50->bpbMedia;
  296. X    pmp->pm_FATsecs      = getushort(b50->bpbFATsecs);
  297. X    pmp->pm_SecPerTrack  = getushort(b50->bpbSecPerTrack);
  298. X    pmp->pm_Heads        = getushort(b50->bpbHeads);
  299. X    if (bsp->bs50.bsOemName[5] == '5') {
  300. X        pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
  301. X        pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
  302. X    } else {
  303. X        pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
  304. X        pmp->pm_HugeSectors = 0;
  305. X    }
  306. X    if (pmp->pm_Sectors != 0)
  307. X        pmp->pm_HugeSectors = pmp->pm_Sectors;
  308. X    pmp->pm_fatblk = pmp->pm_ResSectors;
  309. X    pmp->pm_rootdirblk = pmp->pm_fatblk +
  310. X        (pmp->pm_FATs * pmp->pm_FATsecs);
  311. X    pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry))
  312. X                    /
  313. X                pmp->pm_BytesPerSec; /* in sectors */
  314. X    pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
  315. X    pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
  316. X        pmp->pm_SectPerClust;
  317. X    pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
  318. X    if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0)
  319. X        printf("mountpcfs(): root directory is not a multiple of the clustersize in length\n");
  320. X
  321. X/*
  322. X *  Compute mask and shift value for isolating cluster relative
  323. X *  byte offsets and cluster numbers from a file offset.
  324. X */
  325. X    bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
  326. X    pmp->pm_bpcluster = bpc;
  327. X    pmp->pm_depclust  = bpc/sizeof(struct direntry);
  328. X    pmp->pm_crbomask = bpc - 1;
  329. X    if (bpc == 0) {
  330. X        error = EINVAL;
  331. X        goto error_exit;
  332. X    }
  333. X    bit = 1;
  334. X    for (i = 0; i < 32; i++) {
  335. X        if (bit & bpc) {
  336. X            if (bit ^ bpc) {
  337. X                error = EINVAL;
  338. X                goto error_exit;
  339. X            }
  340. X            pmp->pm_cnshift = i;
  341. X            break;
  342. X        }
  343. X        bit <<= 1;
  344. X    }
  345. X
  346. X    pmp->pm_brbomask = 0x01ff;    /* 512 byte blocks only (so far) */
  347. X    pmp->pm_bnshift = 9;        /* shift right 9 bits to get bn */
  348. X
  349. X/*
  350. X *  Release the bootsector buffer.
  351. X */
  352. X    brelse(bp0);
  353. X    bp0 = NULL;
  354. X
  355. X/*
  356. X *  Allocate memory for the bitmap of allocated clusters,
  357. X *  and then fill it in.
  358. X */
  359. X    pmp->pm_inusemap = malloc((pmp->pm_maxcluster >> 3) + 1,
  360. X        M_PCFSFAT, M_WAITOK);
  361. X    if (!pmp->pm_inusemap) {
  362. X        error = ENOMEM;
  363. X        goto error_exit;
  364. X    }
  365. X
  366. X/*
  367. X *  fillinusemap() needs pm_devvp.
  368. X */
  369. X    pmp->pm_dev = dev;
  370. X    pmp->pm_devvp = devvp;
  371. X
  372. X/*
  373. X *  Have the inuse map filled in.
  374. X */
  375. X    error = fillinusemap(pmp);
  376. X    if (error) {
  377. X        goto error_exit;
  378. X    }
  379. X
  380. X/*
  381. X *  If they want fat updates to be synchronous then let
  382. X *  them suffer the performance degradation in exchange
  383. X *  for the on disk copy of the fat being correct just
  384. X *  about all the time.  I suppose this would be a good
  385. X *  thing to turn on if the kernel is still flakey.
  386. X */
  387. X    pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS;
  388. X
  389. X/*
  390. X *  Finish up.
  391. X */
  392. X    pmp->pm_ronly = ronly;
  393. X    if (ronly == 0)
  394. X        pmp->pm_fmod = 1;
  395. X    mp->mnt_data = (qaddr_t)pmp;
  396. X    mp->mnt_stat.f_fsid.val[0] = (long)dev;
  397. X    mp->mnt_stat.f_fsid.val[1] = MOUNT_PCFS;
  398. X    mp->mnt_flag |= MNT_LOCAL;
  399. X#if defined(QUOTA)
  400. X/*
  401. X *  If we ever do quotas for DOS filesystems this would
  402. X *  be a place to fill in the info in the pcfsmount
  403. X *  structure.
  404. X *  You dolt, quotas on dos filesystems make no sense
  405. X *  because files have no owners on dos filesystems.
  406. X *  of course there is some empty space in the directory
  407. X *  entry where we could put uid's and gid's.
  408. X */
  409. X#endif /* defined(QUOTA) */
  410. X    devvp->v_specflags |= SI_MOUNTEDON;
  411. X
  412. X    return 0;
  413. X
  414. Xerror_exit:;
  415. X    if (bp0)
  416. X        brelse(bp0);
  417. X    if (needclose)
  418. X        (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE,
  419. X            NOCRED, p);
  420. X    if (pmp) {
  421. X        if (pmp->pm_inusemap)
  422. X            free((caddr_t)pmp->pm_inusemap, M_PCFSFAT);
  423. X        free((caddr_t)pmp, M_PCFSMNT);
  424. X        mp->mnt_data = (qaddr_t)0;
  425. X    }
  426. X    return error;
  427. X}
  428. X
  429. Xint
  430. Xpcfs_start(mp, flags, p)
  431. X    struct mount *mp;
  432. X    int flags;
  433. X    struct proc *p;
  434. X{
  435. X    return 0;
  436. X}
  437. X
  438. X/*
  439. X *  Unmount the filesystem described by mp.
  440. X */
  441. Xint
  442. Xpcfs_unmount(mp, mntflags, p)
  443. X    struct mount *mp;
  444. X    int mntflags;
  445. X    struct proc *p;
  446. X{
  447. X    int flags = 0;
  448. X    int error;
  449. X    struct pcfsmount *pmp = (struct pcfsmount *)mp->mnt_data;
  450. X    struct vnode *vp = pmp->pm_devvp;
  451. X
  452. X    if (mntflags & MNT_FORCE) {
  453. X        if (!pcfsdoforce)
  454. X            return EINVAL;
  455. X        flags |= FORCECLOSE;
  456. X    }
  457. X    mntflushbuf(mp, 0);
  458. X    if (mntinvalbuf(mp))
  459. X        return EBUSY;
  460. X#if defined(QUOTA)
  461. X#endif /* defined(QUOTA) */
  462. X    if (error = vflush(mp, NULLVP, flags))
  463. X        return error;
  464. X    pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON;
  465. X#if defined(PCFSDEBUG)
  466. Xprintf("pcfs_umount(): just before calling VOP_CLOSE()\n");
  467. Xprintf("flag %08x, usecount %d, writecount %d, holdcnt %d\n",
  468. X    vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt);
  469. Xprintf("lastr %d, id %d, mount %08x, op %08x\n",
  470. X    vp->v_lastr, vp->v_id, vp->v_mount, vp->v_op);
  471. Xprintf("freef %08x, freeb %08x, mountf %08x, mountb %08x\n",
  472. X    vp->v_freef, vp->v_freeb, vp->v_mountf, vp->v_mountb);
  473. Xprintf("cleanblkhd %08x, dirtyblkhd %08x, numoutput %d, type %d\n",
  474. X    vp->v_cleanblkhd, vp->v_dirtyblkhd, vp->v_numoutput, vp->v_type);
  475. Xprintf("union %08x, tag %d, data[0] %08x, data[1] %08x\n",
  476. X    vp->v_socket, vp->v_tag, vp->v_data[0], vp->v_data[1]);
  477. X#endif /* defined(PCFSDEBUG) */
  478. X    error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD|FWRITE,
  479. X        NOCRED, p);
  480. X    vrele(pmp->pm_devvp);
  481. X    free((caddr_t)pmp->pm_inusemap, M_PCFSFAT);
  482. X    free((caddr_t)pmp, M_PCFSMNT);
  483. X    mp->mnt_data = (qaddr_t)0;
  484. X    mp->mnt_flag &= ~MNT_LOCAL;
  485. X    return error;
  486. X}
  487. X
  488. Xint
  489. Xpcfs_root(mp, vpp)
  490. X    struct mount *mp;
  491. X    struct vnode **vpp;
  492. X{
  493. X    struct denode *ndep;
  494. X    struct pcfsmount *pmp = (struct pcfsmount *)(mp->mnt_data);
  495. X    int error;
  496. X
  497. X    error = deget(pmp, ATTR_DIRECTORY, 0, 0, PCFSROOT, 0, &ndep);
  498. X#if defined(PCFSDEBUG)
  499. Xprintf("pcfs_root(); mp %08x, pmp %08x, ndep %08x, vp %08x\n",
  500. X mp, pmp, ndep, DETOV(ndep));
  501. X#endif /* defined(PCFSDEBUG) */
  502. X    if (error == 0)
  503. X        *vpp = DETOV(ndep);
  504. X    return error;
  505. X}
  506. X
  507. Xint
  508. Xpcfs_quotactl(mp, cmds, uid, arg, p)
  509. X    struct mount *mp;
  510. X    int cmds;
  511. X    uid_t uid;
  512. X    caddr_t arg;
  513. X    struct proc *p;
  514. X{
  515. X#if defined(QUOTA)
  516. X#else
  517. X    return EOPNOTSUPP;
  518. X#endif /* defined(QUOTA) */
  519. X}
  520. X
  521. Xint
  522. Xpcfs_statfs(mp, sbp, p)
  523. X    struct mount *mp;
  524. X    struct statfs *sbp;
  525. X    struct proc *p;
  526. X{
  527. X    struct pcfsmount *pmp = (struct pcfsmount *)mp->mnt_data;
  528. X
  529. X/*
  530. X *  Fill in the stat block.
  531. X */
  532. X    sbp->f_type   = MOUNT_PCFS;
  533. X    sbp->f_fsize  = pmp->pm_bpcluster;
  534. X    sbp->f_bsize  = pmp->pm_bpcluster;
  535. X    sbp->f_blocks = pmp->pm_nmbrofclusters;
  536. X    sbp->f_bfree  = pmp->pm_freeclustercount;
  537. X    sbp->f_bavail = pmp->pm_freeclustercount;
  538. X    sbp->f_files  = pmp->pm_RootDirEnts;
  539. X    sbp->f_ffree  = 0;        /* what to put in here? */
  540. X
  541. X/*
  542. X *  Copy the mounted on and mounted from names into
  543. X *  the passed in stat block, if it is not the one
  544. X *  in the mount structure.
  545. X */
  546. X    if (sbp != &mp->mnt_stat) {
  547. X        bcopy((caddr_t)mp->mnt_stat.f_mntonname,
  548. X            (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
  549. X        bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
  550. X            (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
  551. X    }
  552. X    return 0;
  553. X}
  554. X
  555. Xint
  556. Xpcfs_sync(mp, waitfor)
  557. X    struct mount *mp;
  558. X    int waitfor;
  559. X{
  560. X    struct vnode *vp;
  561. X    struct denode *dep;
  562. X    struct pcfsmount *pmp;
  563. X    int error;
  564. X    int allerror = 0;
  565. X
  566. X    pmp = (struct pcfsmount *)mp->mnt_data;
  567. X
  568. X/*
  569. X *  If we ever switch to not updating all of the fats
  570. X *  all the time, this would be the place to update them
  571. X *  from the first one.
  572. X */
  573. X    if (pmp->pm_fmod) {
  574. X        if (pmp->pm_ronly) {
  575. X            printf("pcfs_sync(): writing to readonly filesystem\n");
  576. X            return EINVAL;
  577. X        } else {
  578. X            /* update fats here */
  579. X        }
  580. X    }
  581. X
  582. X/*
  583. X *  Go thru in memory denodes and write them out along
  584. X *  with unwritten file blocks.
  585. X */
  586. Xloop:
  587. X    for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
  588. X        if (vp->v_mount != mp)    /* not ours anymore    */
  589. X            goto loop;
  590. X        if (VOP_ISLOCKED(vp))    /* file is busy        */
  591. X            continue;
  592. X        dep = VTODE(vp);
  593. X        if ((dep->de_flag & DEUPD) == 0  &&  vp->v_dirtyblkhd == NULL)
  594. X            continue;
  595. X        if (vget(vp))        /* not there anymore?    */
  596. X            goto loop;
  597. X        if (vp->v_dirtyblkhd)    /* flush dirty file blocks */
  598. X            vflushbuf(vp, 0);
  599. X        if ((dep->de_flag & DEUPD)  &&
  600. X            (error = deupdat(dep, &time, 0)))
  601. X            allerror = error;
  602. X        vput(vp);        /* done with this one    */
  603. X    }
  604. X
  605. X/*
  606. X *  Flush filesystem control info.
  607. X */
  608. X    vflushbuf(pmp->pm_devvp, waitfor == MNT_WAIT ? B_SYNC : 0);
  609. X    return allerror;
  610. X}
  611. X
  612. Xint
  613. Xpcfs_fhtovp(mp, fhp, vpp)
  614. X    struct mount *mp;
  615. X    struct fid *fhp;
  616. X    struct vnode **vpp;
  617. X{
  618. X    printf("pcfs_fhtovp(): someone is finally calling this!\n");
  619. X    return EINVAL;
  620. X}
  621. X
  622. Xint
  623. Xpcfs_vptofh(vp, fhp)
  624. X    struct vnode *vp;
  625. X    struct fid *fhp;
  626. X{
  627. X    printf("pcfs_vptofh(): someone is finally calling this!\n");
  628. X    return EINVAL;
  629. X}
  630. X
  631. Xstruct vfsops pcfs_vfsops = {
  632. X    pcfs_mount,
  633. X    pcfs_start,
  634. X    pcfs_unmount,
  635. X    pcfs_root,
  636. X    pcfs_quotactl,
  637. X    pcfs_statfs,
  638. X    pcfs_sync,
  639. X    pcfs_fhtovp,
  640. X    pcfs_vptofh,
  641. X    pcfs_init
  642. X};
  643. END-of-/sys/pcfs/pcfs_vfsops.c
  644. echo x - /sys/pcfs/pcfs_denode.c
  645. sed 's/^X//' >/sys/pcfs/pcfs_denode.c << 'END-of-/sys/pcfs/pcfs_denode.c'
  646. X/*
  647. X *  Written by Paul Popelka (paulp@uts.amdahl.com)
  648. X *
  649. X *  You can do anything you want with this software,
  650. X *    just don't say you wrote it,
  651. X *    and don't remove this notice.
  652. X *
  653. X *  This software is provided "as is".
  654. X *
  655. X *  The author supplies this software to be publicly
  656. X *  redistributed on the understanding that the author
  657. X *  is not responsible for the correct functioning of
  658. X *  this software in any circumstances and is not liable
  659. X *  for any damages caused by this software.
  660. X *
  661. X *  October 1992
  662. X */
  663. X
  664. X#include "param.h"
  665. X#include "systm.h"
  666. X#include "mount.h"
  667. X#include "proc.h"
  668. X#include "buf.h"
  669. X#include "vnode.h"
  670. X#include "kernel.h"    /* defines "time"            */
  671. X
  672. X#include "bpb.h"
  673. X#include "pcfsmount.h"
  674. X#include "direntry.h"
  675. X#include "denode.h"
  676. X#include "fat.h"
  677. X
  678. X#define    DEHSZ    512
  679. X#if ((DEHSZ & (DEHSZ-1)) == 0)
  680. X#define    DEHASH(dev, deno)    (((dev)+(deno)+((deno)>>16))&(DEHSZ-1))
  681. X#else
  682. X#define    DEHASH(dev, deno)    (((dev)+(deno)+((deno)>>16))%DEHSZ)
  683. X#endif /* ((DEHSZ & (DEHSZ-1)) == 0) */
  684. X
  685. Xunion dehead {
  686. X    union dehead *deh_head[2];
  687. X    struct denode *deh_chain[2];
  688. X} dehead[DEHSZ];
  689. X
  690. Xpcfs_init()
  691. X{
  692. X    int i;
  693. X    union dehead *deh;
  694. X
  695. X    if (VN_MAXPRIVATE < sizeof(struct denode))
  696. X        panic("pcfs_init: vnode too small");
  697. X
  698. X    for (i = DEHSZ, deh = dehead; --i >= 0; deh++) {
  699. X        deh->deh_head[0] = deh;
  700. X        deh->deh_head[1] = deh;
  701. X    }
  702. X}
  703. X
  704. X/*
  705. X *  If deget() succeeds it returns with the gotten denode
  706. X *  locked().
  707. X *  pmp - address of pcfsmount structure of the filesystem
  708. X *    containing the denode of interest.  The pm_dev field
  709. X *    and the address of the pcfsmount structure are used. 
  710. X *  isadir - a flag used to indicate whether the denode of
  711. X *    interest represents a file or a directory.
  712. X *  dirclust - which cluster bp contains, if dirclust is 0
  713. X *    (root directory) diroffset is relative to the beginning
  714. X *    of the root directory, otherwise it is cluster relative.
  715. X *  diroffset - offset past begin of cluster of denode we
  716. X *    want
  717. X *  startclust - number of 1st cluster in the file the
  718. X *    denode represents.  Similar to an inode number.
  719. X *  bp - address of the buf header for the buffer containing
  720. X *    the direntry structure of interest.
  721. X *  depp - returns the address of the gotten denode.
  722. X */
  723. Xint
  724. Xdeget(pmp, isadir, dirclust, diroffset, startclust, bp, depp)
  725. X    struct pcfsmount *pmp;    /* so we know the maj/min number    */
  726. X    int isadir;        /* ~0 means the denode is a directory    */
  727. X    u_long dirclust;    /* cluster this dir entry came from    */
  728. X    u_long diroffset;    /* index of entry within the cluster    */
  729. X    u_long startclust;    /* # of the 1st cluster in file this de
  730. X                 *  points to                */
  731. X    struct buf *bp;        /* buffer containing the dir entry    */
  732. X    struct denode **depp;    /* returns the addr of the gotten denode*/
  733. X{
  734. X    int error;
  735. X    int deoff;
  736. X    dev_t dev = pmp->pm_dev;
  737. X    union dehead *deh;
  738. X    struct mount *mntp = pmp->pm_mountp;
  739. X    extern struct vnodeops pcfs_vnodeops;
  740. X    struct denode *ldep;
  741. X    struct vnode *nvp;
  742. X    struct direntry *direntptr;
  743. X#if defined(PCFSDEBUG)
  744. Xprintf("deget(pmp %08x, isadir %d, dirclust %d, diroffset %d, startclust %d\n",
  745. X    pmp, isadir, dirclust, diroffset, startclust);
  746. Xprintf("      bp %08x, depp %08x)\n",
  747. X    bp, depp);
  748. X#endif /* defined(PCFSDEBUG) */
  749. X
  750. X/*
  751. X *  See if the denode is in the denode cache.
  752. X *  If the denode is for a directory then use the
  753. X *  startcluster in computing the hash value.  If
  754. X *  a regular file then use the location of the directory
  755. X *  entry to compute the hash value.  We use startcluster
  756. X *  for directories because several directory entries
  757. X *  may point to the same directory.  For files
  758. X *  we use the directory entry location because
  759. X *  empty files have a startcluster of 0, which
  760. X *  is non-unique and because it matches the root
  761. X *  directory too.  I don't think the dos filesystem
  762. X *  was designed.
  763. X *  NOTE: The check for de_refcnt > 0 below insures the denode
  764. X *  being examined does not represent an unlinked but
  765. X *  still open file.  These files are not to be accessible
  766. X *  even when the directory entry that represented the
  767. X *  file happens to be reused while the deleted file is still
  768. X *  open.
  769. X */
  770. X    if (isadir)
  771. X        deh = &dehead[DEHASH(dev, startclust)];
  772. X    else
  773. X        deh = &dehead[DEHASH(dev, dirclust+diroffset)];
  774. Xloop:
  775. X    for (ldep = deh->deh_chain[0]; ldep != (struct denode *)deh;
  776. X        ldep = ldep->de_forw) {
  777. X        if (dev == ldep->de_dev  &&  ldep->de_refcnt > 0) {
  778. X            if (ldep->de_Attributes & ATTR_DIRECTORY) {
  779. X                if (ldep->de_StartCluster != startclust  ||
  780. X                    !isadir)
  781. X                    continue;
  782. X            } else {    /* it's a file */
  783. X                if (isadir  ||
  784. X                    dirclust  != ldep->de_dirclust  ||
  785. X                    diroffset != ldep->de_diroffset)
  786. X                    continue;
  787. X            }
  788. X            if (ldep->de_flag & DELOCKED) {
  789. X                /* should we brelse() the passed buf hdr to
  790. X                 *  avoid some potential deadlock? */
  791. X                ldep->de_flag |= DEWANT;
  792. X                sleep((caddr_t)ldep, PINOD);
  793. X                goto loop;
  794. X            }
  795. X            if (vget(DETOV(ldep)))
  796. X                goto loop;
  797. X#if defined(PCFSDEBUG)
  798. Xprintf("deget(): entry found in cache %08x\n", ldep);
  799. X#endif /* defined(PCFSDEBUG) */
  800. X            *depp = ldep;
  801. X            return 0;
  802. X        }
  803. X    }
  804. X
  805. X
  806. X/*
  807. X *  Directory entry was not in cache, have to create
  808. X *  a vnode and copy it from the passed disk buffer.
  809. X */
  810. X    /* getnewvnode() does a VREF() on the vnode */
  811. X    if (error = getnewvnode(VT_PCFS, mntp, &pcfs_vnodeops, &nvp)) {
  812. X        *depp = 0;
  813. X        return error;
  814. X    }
  815. X    ldep = VTODE(nvp);
  816. X    ldep->de_vnode = nvp;
  817. X    ldep->de_flag = 0;
  818. X    ldep->de_devvp = 0;
  819. X    ldep->de_lockf = 0;
  820. X    ldep->de_dev   = dev;
  821. X    fc_purge(ldep, 0);    /* init the fat cache for this denode */
  822. X
  823. X/*
  824. X *  Insert the denode into the hash queue and lock the
  825. X *  denode so it can't be accessed until we've read it
  826. X *  in and have done what we need to it.
  827. X */
  828. X    insque(ldep, deh);
  829. X    DELOCK(ldep);
  830. X
  831. X/*
  832. X *  Note that the root directory is treated
  833. X *  differently.  There isn't really a directory entry that
  834. X *  describes the root directory (actually the bpb describes it).
  835. X *  So, when we see a reference to cluster 0 we know they
  836. X *  want a directory entry from the root directory.
  837. X *  The value of diroffset for a directory entry  in the
  838. X *  root directory is relative to the beginning of the root
  839. X *  directory.
  840. X */
  841. X    if (dirclust == PCFSROOT) { /* root directory is special */
  842. X        deoff = diroffset % pmp->pm_depclust;
  843. X    } else {
  844. X        deoff = diroffset;
  845. X    }
  846. X
  847. X/*
  848. X *  Copy the directory entry into the denode area of the
  849. X *  vnode.  If they are going after the directory entry
  850. X *  for the root directory, there isn't one so we manufacture
  851. X *  one.
  852. X *  We should probably rummage through the root directory and
  853. X *  find a label entry (if it exists), and then use the time
  854. X *  and date from that entry as the time and date for the
  855. X *  root denode.
  856. X */
  857. X    if (startclust == PCFSROOT  &&  isadir) {
  858. X        ldep->de_Attributes = ATTR_DIRECTORY;
  859. X        ldep->de_StartCluster = PCFSROOT;
  860. X        ldep->de_FileSize = 0;
  861. X        /* fill in time and date so that dos2unixtime() doesn't
  862. X         * spit up when called from pcfs_getattr() with root denode */
  863. X        ldep->de_Time = 0x0000;        /* 00:00:00    */
  864. X        ldep->de_Date = (0 << 9) | (1 << 5) | (1 << 0);
  865. X                        /* Jan 1, 1980    */
  866. X        /* leave the other fields as garbage */
  867. X    } else {
  868. X        direntptr = (struct direntry *)bp->b_un.b_addr;
  869. X        direntptr += deoff;
  870. X        ldep->de_de = *direntptr;
  871. X    }
  872. X
  873. X/*
  874. X *  Fill in a few fields of the vnode and finish filling
  875. X *  in the denode.  Then return the address of the found
  876. X *  denode.
  877. X */
  878. X    if (ldep->de_Attributes & ATTR_DIRECTORY) {
  879. X        nvp->v_type = VDIR;
  880. X        if (startclust == PCFSROOT)
  881. X            nvp->v_flag |= VROOT;
  882. X    } else
  883. X        nvp->v_type = VREG;
  884. X    ldep->de_pmp = pmp;
  885. X    ldep->de_devvp = pmp->pm_devvp;
  886. X    ldep->de_refcnt = 1;
  887. X    ldep->de_dirclust = dirclust;
  888. X    ldep->de_diroffset = diroffset;
  889. X    VREF(ldep->de_devvp); /* mark filesystem as inuse? */
  890. X    *depp = ldep;
  891. X    return 0;
  892. X}
  893. X
  894. Xvoid
  895. Xdeput(dep)
  896. X    struct denode *dep;
  897. X{
  898. X    if ((dep->de_flag & DELOCKED) == 0)
  899. X        panic("deput: denode not locked");
  900. X    DEUNLOCK(dep);
  901. X    vrele(DETOV(dep));
  902. X}
  903. X
  904. Xint
  905. Xdeupdat(dep, tp, waitfor)
  906. X    struct denode *dep;
  907. X    struct timeval *tp;
  908. X    int waitfor;
  909. X{
  910. X    int error;
  911. X    daddr_t bn;
  912. X    int diro;
  913. X    struct buf *bp;
  914. X    struct direntry *dirp;
  915. X    struct pcfsmount *pmp = dep->de_pmp;
  916. X    struct vnode *vp = DETOV(dep);
  917. X#if defined(PCFSDEBUG)
  918. Xprintf("deupdat(): dep %08x\n", dep);
  919. X#endif /* defined(PCFSDEBUG) */
  920. X
  921. X/*
  922. X *  If the update bit is off, or this denode is from
  923. X *  a readonly filesystem, or this denode is for a
  924. X *  directory, or the denode represents an open but
  925. X *  unlinked file then don't do anything.  DOS directory
  926. X *  entries that describe a directory do not ever
  927. X *  get updated.  This is the way dos treats them.
  928. X */
  929. X    if ((dep->de_flag & DEUPD) == 0  ||
  930. X        vp->v_mount->mnt_flag & MNT_RDONLY  ||
  931. X        dep->de_Attributes & ATTR_DIRECTORY  ||
  932. X        dep->de_refcnt <= 0)
  933. X        return 0;
  934. X
  935. X/*
  936. X *  Read in the cluster containing the directory entry
  937. X *  we want to update.
  938. X */
  939. X    if (error = readde(dep, &bp, &dirp)) {
  940. X        return error;
  941. X    }
  942. X
  943. X/*
  944. X *  Put the passed in time into the directory entry.
  945. X */
  946. X    unix2dostime(&time, (union dosdate *)&dep->de_Date,
  947. X        (union dostime *)&dep->de_Time);
  948. X    dep->de_flag &= ~DEUPD;
  949. X
  950. X/*
  951. X *  Copy the directory entry out of the denode into
  952. X *  the cluster it came from.
  953. X */
  954. X    *dirp = dep->de_de;    /* structure copy */
  955. X
  956. X/*
  957. X *  Write the cluster back to disk.  If they asked
  958. X *  for us to wait for the write to complete, then
  959. X *  use bwrite() otherwise use bdwrite().
  960. X */
  961. X    error = 0;    /* note that error is 0 from above, but ... */
  962. X    if (waitfor)
  963. X        error = bwrite(bp);
  964. X    else
  965. X        bdwrite(bp);
  966. X    return error;
  967. X}
  968. X
  969. X/*
  970. X *  Truncate the file described by dep to the length
  971. X *  specified by length.
  972. X */
  973. Xint
  974. Xdetrunc(dep, length, flags)
  975. X    struct denode *dep;
  976. X    u_long length;
  977. X    int flags;
  978. X{
  979. X    int error;
  980. X    int allerror;
  981. X    unsigned long eofentry;
  982. X    unsigned long chaintofree;
  983. X    daddr_t bn;
  984. X    int boff;
  985. X    int isadir = dep->de_Attributes & ATTR_DIRECTORY;
  986. X    struct buf *bp;
  987. X    struct pcfsmount *pmp = dep->de_pmp;
  988. X#if defined(PCFSDEBUG)
  989. Xprintf("detrunc(): file %s, length %d, flags %d\n", dep->de_Name, length, flags);
  990. X#endif /* defined(PCFSDEBUG) */
  991. X
  992. X/*
  993. X *  Disallow attempts to truncate the root directory
  994. X *  since it is of fixed size.  That's just the way
  995. X *  dos filesystems are.  We use the VROOT bit in the
  996. X *  vnode because checking for the directory bit and
  997. X *  a startcluster of 0 in the denode is not adequate
  998. X *  to recognize the root directory at this point in
  999. X *  a file or directory's life.
  1000. X */
  1001. X    if (DETOV(dep)->v_flag & VROOT) {
  1002. X        printf("detrunc(): can't truncate root directory, clust %d, offset %d\n",
  1003. X            dep->de_dirclust, dep->de_diroffset);
  1004. X        return EINVAL;
  1005. X    }
  1006. X
  1007. X    vnode_pager_setsize(DETOV(dep), length);
  1008. X
  1009. X/*
  1010. X *  If we are going to truncate a directory then we better
  1011. X *  find out how long it is.  DOS doesn't keep the length of
  1012. X *  a directory file in its directory entry.
  1013. X */
  1014. X    if (isadir) {
  1015. X        /* pcbmap() returns the # of clusters in the file */
  1016. X        error = pcbmap(dep, 0xffff, 0, &eofentry);
  1017. X        if (error != 0  &&  error != E2BIG)
  1018. X            return error;
  1019. X        dep->de_FileSize = eofentry << pmp->pm_cnshift;
  1020. X    }
  1021. X
  1022. X    if (dep->de_FileSize <= length) {
  1023. X        dep->de_flag |= DEUPD;
  1024. X        error = deupdat(dep, &time, 1);
  1025. X#if defined(PCFSDEBUG)
  1026. Xprintf("detrunc(): file is shorter return point, errno %d\n", error);
  1027. X#endif /* defined(PCFSDEBUG) */
  1028. X        return error;
  1029. X    }
  1030. X
  1031. X/*
  1032. X *  If the desired length is 0 then remember the starting
  1033. X *  cluster of the file and set the StartCluster field in
  1034. X *  the directory entry to 0.  If the desired length is
  1035. X *  not zero, then get the number of the last cluster in
  1036. X *  the shortened file.  Then get the number of the first
  1037. X *  cluster in the part of the file that is to be freed.
  1038. X *  Then set the next cluster pointer in the last cluster
  1039. X *  of the file to CLUST_EOFE.
  1040. X */
  1041. X    if (length == 0) {
  1042. X        chaintofree = dep->de_StartCluster;
  1043. X        dep->de_StartCluster = 0;
  1044. X        eofentry = ~0;
  1045. X    } else {
  1046. X        error = pcbmap(dep, (length-1) >> pmp->pm_cnshift,
  1047. X                0, &eofentry);
  1048. X        if (error) {
  1049. X#if defined(PCFSDEBUG)
  1050. Xprintf("detrunc(): pcbmap fails %d\n", error);
  1051. X#endif /* defined(PCFSDEBUG) */
  1052. X            return error;
  1053. X        }
  1054. X    }
  1055. X
  1056. X    fc_purge(dep, (length + pmp->pm_crbomask) >> pmp->pm_cnshift);
  1057. X
  1058. X/*
  1059. X *  If the new length is not a multiple of the cluster size
  1060. X *  then we must zero the tail end of the new last cluster in case
  1061. X *  it becomes part of the file again because of a seek.
  1062. X */
  1063. X    if ((boff = length & pmp->pm_crbomask) != 0) {
  1064. X        /* should read from file vnode or
  1065. X         * filesystem vnode depending on if file or dir */
  1066. X        if (isadir) {
  1067. X            bn = cntobn(pmp, eofentry);
  1068. X            error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
  1069. X                NOCRED, &bp);
  1070. X        } else {
  1071. X            bn = (length-1) >> pmp->pm_cnshift;
  1072. X            error = bread(DETOV(dep), bn, pmp->pm_bpcluster,
  1073. X                NOCRED, &bp);
  1074. X        }
  1075. X        if (error) {
  1076. X#if defined(PCFSDEBUG)
  1077. Xprintf("detrunc(): bread fails %d\n", error);
  1078. X#endif /* defined(PCFSDEBUG) */
  1079. X            brelse(bp);
  1080. X            return error;
  1081. X        }
  1082. X        vnode_pager_uncache(DETOV(dep));    /* what's this for? */
  1083. X                            /* is this the right
  1084. X                             *  place for it? */
  1085. X        bzero(bp->b_un.b_addr + boff, pmp->pm_bpcluster - boff);
  1086. X        if (flags & IO_SYNC)
  1087. X            bwrite(bp);
  1088. X        else
  1089. X            bdwrite(bp);
  1090. X    }
  1091. X
  1092. X/*
  1093. X *  Write out the updated directory entry.  Even
  1094. X *  if the update fails we free the trailing clusters.
  1095. X */
  1096. X    dep->de_FileSize = length;
  1097. X    dep->de_flag |= DEUPD;
  1098. X    vinvalbuf(DETOV(dep), length > 0);
  1099. X    allerror = deupdat(dep, &time, MNT_WAIT);
  1100. X#if defined(PCFSDEBUG)
  1101. Xprintf("detrunc(): allerror %d, eofentry %d\n",
  1102. X    allerror, eofentry);
  1103. X#endif /* defined(PCFSDEBUG) */
  1104. X
  1105. X/*
  1106. X *  If we need to break the cluster chain for the file
  1107. X *  then do it now.
  1108. X */
  1109. X    if (eofentry != ~0) {
  1110. X        error = fatentry(FAT_GET_AND_SET, pmp, eofentry,
  1111. X            &chaintofree, CLUST_EOFE);
  1112. X        if (error) {
  1113. X#if defined(PCFSDEBUG)
  1114. Xprintf("detrunc(): fatentry errors %d\n", error);
  1115. X#endif /* defined(PCFSDEBUG) */
  1116. X            return error;
  1117. X        }
  1118. X        fc_setcache(dep, FC_LASTFC, (length - 1) >> pmp->pm_cnshift,
  1119. X            eofentry);
  1120. X    }
  1121. X
  1122. X/*
  1123. X *  Now free the clusters removed from the file because
  1124. X *  of the truncation.
  1125. X */
  1126. X    if (chaintofree != 0  &&  !PCFSEOF(chaintofree))
  1127. X        freeclusterchain(pmp, chaintofree);
  1128. X
  1129. X    return allerror;
  1130. X}
  1131. X
  1132. X/*
  1133. X *  Move a denode to its correct hash queue after
  1134. X *  the file it represents has been moved to a new
  1135. X *  directory.
  1136. X */
  1137. Xreinsert(dep)
  1138. X    struct denode *dep;
  1139. X{
  1140. X    struct pcfsmount *pmp = dep->de_pmp;
  1141. X    union dehead *deh;
  1142. X
  1143. X/*
  1144. X *  Fix up the denode cache.  If the denode is
  1145. X *  for a directory, there is nothing to do since the
  1146. X *  hash is based on the starting cluster of the directory
  1147. X *  file and that hasn't changed.  If for a file the hash
  1148. X *  is based on the location
  1149. X *  of the directory entry, so we must remove it from the
  1150. X *  cache and re-enter it with the hash based on the new
  1151. X *  location of the directory entry.
  1152. X */
  1153. X    if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
  1154. X        remque(dep);
  1155. X        deh = &dehead[DEHASH(pmp->pm_dev,
  1156. X            dep->de_dirclust + dep->de_diroffset)];
  1157. X        insque(dep, deh);
  1158. X    }
  1159. X}
  1160. X
  1161. Xint pcfs_prtactive;    /* print reclaims of active vnodes */
  1162. X
  1163. Xint
  1164. Xpcfs_reclaim(vp)
  1165. X    struct vnode *vp;
  1166. X{
  1167. X    struct denode *dep = VTODE(vp);
  1168. X    int i;
  1169. X#if defined(PCFSDEBUG)
  1170. Xprintf("pcfs_reclaim(): dep %08x, file %s, refcnt %d\n",
  1171. X    dep, dep->de_Name, dep->de_refcnt);
  1172. X#endif /* defined(PCFSDEBUG) */
  1173. X
  1174. X    if (pcfs_prtactive && vp->v_usecount != 0)
  1175. X        vprint("pcfs_reclaim(): pushing active", vp);
  1176. X
  1177. X/*
  1178. X *  Remove the denode from the denode hash chain we
  1179. X *  are in.
  1180. X */
  1181. X    remque(dep);
  1182. X    dep->de_forw = dep;
  1183. X    dep->de_back = dep;
  1184. X
  1185. X    cache_purge(vp);
  1186. X/*
  1187. X *  Indicate that one less file on the filesystem is open.
  1188. X */
  1189. X    if (dep->de_devvp) {
  1190. X        vrele(dep->de_devvp);
  1191. X        dep->de_devvp = 0;
  1192. X    }
  1193. X
  1194. X    dep->de_flag = 0;
  1195. X    return 0;
  1196. X}
  1197. X
  1198. Xint
  1199. Xpcfs_inactive(vp, p)
  1200. X    struct vnode *vp;
  1201. X    struct proc *p;
  1202. X{
  1203. X    struct denode *dep = VTODE(vp);
  1204. X    int error = 0;
  1205. X#if defined(PCFSDEBUG)
  1206. Xprintf("pcfs_inactive(): dep %08x, de_Name[0] %x\n", dep, dep->de_Name[0]);
  1207. X#endif /* defined(PCFSDEBUG) */
  1208. X
  1209. X    if (pcfs_prtactive && vp->v_usecount != 0)
  1210. X        vprint("pcfs_inactive(): pushing active", vp);
  1211. X
  1212. X/*
  1213. X *  Get rid of denodes related to stale file handles.
  1214. X *  Hmmm, what does this really do?
  1215. X */
  1216. X    if (dep->de_Name[0] == SLOT_DELETED) {
  1217. X        if ((vp->v_flag & VXLOCK) == 0)
  1218. X            vgone(vp);
  1219. X        return 0;
  1220. X    }
  1221. X
  1222. X/*
  1223. X *  If the file has been deleted and it is on a read/write
  1224. X *  filesystem, then truncate the file, and mark the directory
  1225. X *  slot as empty.  (This may not be necessary for the dos
  1226. X *  filesystem.
  1227. X */
  1228. X#if defined(PCFSDEBUG)
  1229. Xprintf("pcfs_inactive(): dep %08x, refcnt %d, mntflag %x, MNT_RDONLY %x\n",
  1230. X    dep, dep->de_refcnt, vp->v_mount->mnt_flag, MNT_RDONLY);
  1231. X#endif /* defined(PCFSDEBUG) */
  1232. X    DELOCK(dep);
  1233. X    if (dep->de_refcnt <= 0  &&  (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
  1234. X        error = detrunc(dep, (u_long)0, 0);
  1235. X        dep->de_flag |= DEUPD;
  1236. X        dep->de_Name[0] = SLOT_DELETED;
  1237. X    }
  1238. X    DEUPDAT(dep, &time, 0);
  1239. X    DEUNLOCK(dep);
  1240. X    dep->de_flag = 0;
  1241. X
  1242. X/*
  1243. X *  If we are done with the denode, then reclaim
  1244. X *  it so that it can be reused now.
  1245. X */
  1246. X#if defined(PCFSDEBUG)
  1247. Xprintf("pcfs_inactive(): v_usecount %d, de_Name[0] %x\n", vp->v_usecount,
  1248. X    dep->de_Name[0]);
  1249. X#endif /* defined(PCFSDEBUG) */
  1250. X    if (vp->v_usecount == 0  &&  dep->de_Name[0] == SLOT_DELETED)
  1251. X        vgone(vp);
  1252. X    return error;
  1253. X}
  1254. X
  1255. Xint
  1256. Xdelock(dep)
  1257. X    struct denode *dep;
  1258. X{
  1259. X    while (dep->de_flag & DELOCKED) {
  1260. X        dep->de_flag |= DEWANT;
  1261. X        if (dep->de_spare0 == curproc->p_pid)
  1262. X            panic("delock: locking against myself");
  1263. X        dep->de_spare1 = curproc->p_pid;
  1264. X        (void) sleep((caddr_t)dep, PINOD);
  1265. X    }
  1266. X    dep->de_spare1 = 0;
  1267. X    dep->de_spare0 = curproc->p_pid;
  1268. X    dep->de_flag |= DELOCKED;
  1269. X
  1270. X    return 0;
  1271. X}
  1272. X
  1273. Xint
  1274. Xdeunlock(dep)
  1275. X    struct denode *dep;
  1276. X{
  1277. X    if ((dep->de_flag & DELOCKED) == 0)
  1278. X        vprint("deunlock: found unlocked denode", DETOV(dep));
  1279. X    dep->de_spare0 = 0;
  1280. X    dep->de_flag &= ~DELOCKED;
  1281. X    if (dep->de_flag & DEWANT) {
  1282. X        dep->de_flag &= ~DEWANT;
  1283. X        wakeup((caddr_t)dep);
  1284. X    }
  1285. X
  1286. X    return 0;
  1287. X}
  1288. END-of-/sys/pcfs/pcfs_denode.c
  1289. echo x - /sys/pcfs/pcfs_conv.c
  1290. sed 's/^X//' >/sys/pcfs/pcfs_conv.c << 'END-of-/sys/pcfs/pcfs_conv.c'
  1291. X/*
  1292. X *  Written by Paul Popelka (paulp@uts.amdahl.com)
  1293. X *
  1294. X *  You can do anything you want with this software,
  1295. X *    just don't say you wrote it,
  1296. X *    and don't remove this notice.
  1297. X *
  1298. X *  This software is provided "as is".
  1299. X *
  1300. X *  The author supplies this software to be publicly
  1301. X *  redistributed on the understanding that the author
  1302. X *  is not responsible for the correct functioning of
  1303. X *  this software in any circumstances and is not liable
  1304. X *  for any damages caused by this software.
  1305. X *
  1306. X *  October 1992
  1307. X */
  1308. X
  1309. X/*
  1310. X *  System include files.
  1311. X */
  1312. X#include "param.h"
  1313. X#include "time.h"
  1314. X#include "kernel.h"    /* defines tz */
  1315. X
  1316. X/*
  1317. X *  PCFS include files.
  1318. X */
  1319. X#include "direntry.h"
  1320. X
  1321. X/*
  1322. X *  Days in each month in a regular year.
  1323. X */
  1324. Xunsigned short regyear[] = {
  1325. X    31,    28,    31,    30,    31,    30,
  1326. X    31,    31,    30,    31,    30,    31
  1327. X};
  1328. X
  1329. X/*
  1330. X *  Days in each month in a leap year.
  1331. X */
  1332. Xunsigned short leapyear[] = {
  1333. X    31,    29,    31,    30,    31,    30,
  1334. X    31,    31,    30,    31,    30,    31
  1335. X};
  1336. X
  1337. X/*
  1338. X *  Variables used to remember parts of the last time
  1339. X *  conversion.  Maybe we can avoid a full conversion.
  1340. X */
  1341. Xunsigned long lasttime = 0;
  1342. Xunsigned long lastday;
  1343. Xunion dosdate lastddate;
  1344. Xunion dostime lastdtime;
  1345. X
  1346. X/*
  1347. X *  Convert the unix version of time to dos's idea of time
  1348. X *  to be used in file timestamps.
  1349. X *  The passed in unix time is assumed to be in GMT.
  1350. X */
  1351. Xvoid
  1352. Xunix2dostime(tvp, ddp, dtp)
  1353. X    struct timeval *tvp;
  1354. X    union dosdate *ddp;
  1355. X    union dostime *dtp;
  1356. X{
  1357. X    unsigned long days;
  1358. X    unsigned long inc;
  1359. X    unsigned long year;
  1360. X    unsigned long month;
  1361. X    unsigned short *months;
  1362. X
  1363. X/*
  1364. X *  If the time from the last conversion is the same
  1365. X *  as now, then skip the computations and use the
  1366. X *  saved result.
  1367. X */
  1368. X    if (lasttime != tvp->tv_sec) {
  1369. X        lasttime = tvp->tv_sec - (tz.tz_minuteswest * 60)
  1370. X            /* +- daylight savings time correction */;
  1371. X        lastdtime.dts.dt_2seconds = (lasttime % 60) >> 1;
  1372. X        lastdtime.dts.dt_minutes  = (lasttime / 60) % 60;
  1373. X        lastdtime.dts.dt_hours    = (lasttime / (60 * 60)) % 24;
  1374. X
  1375. X/*
  1376. X *  If the number of days since 1970 is the same as the
  1377. X *  last time we did the computation then skip all this
  1378. X *  leap year and month stuff.
  1379. X */
  1380. X        days = lasttime / (24 * 60 * 60);
  1381. X        if (days != lastday) {
  1382. X            lastday = days;
  1383. X            for (year = 1970; ; year++) {
  1384. X                inc = year & 0x03 ? 365 : 366;
  1385. X                if (days < inc) break;
  1386. X                days -= inc;
  1387. X            }
  1388. X            months = year & 0x03 ? regyear : leapyear;
  1389. X            for (month = 0; month < 12; month++) {
  1390. X                if (days < months[month]) break;
  1391. X                days -= months[month];
  1392. X            }
  1393. X            lastddate.dds.dd_day = days + 1;
  1394. X            lastddate.dds.dd_month = month+1;
  1395. X/*
  1396. X *  Remember dos's idea of time is relative to 1980.
  1397. X *  unix's is relative to 1970.  If somehow we get a
  1398. X *  time before 1980 then don't give totally crazy
  1399. X *  results.
  1400. X */
  1401. X            lastddate.dds.dd_year = year < 1980 ? 0 : year - 1980;
  1402. X        }
  1403. X    }
  1404. X    dtp->dti = lastdtime.dti;
  1405. X    ddp->ddi = lastddate.ddi;
  1406. X}
  1407. X
  1408. X/*
  1409. X *  The number of seconds between Jan 1, 1970 and
  1410. X *  Jan 1, 1980.
  1411. X *  In that interval there were 8 regular years and
  1412. X *  2 leap years.
  1413. X */
  1414. X#define    SECONDSTO1980    (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
  1415. X
  1416. Xunion dosdate lastdosdate;
  1417. Xunsigned long lastseconds;
  1418. X
  1419. X/*
  1420. X *  Convert from dos' idea of time to unix'.
  1421. X *  This will probably only be called from the
  1422. X *  stat(), and fstat() system calls
  1423. X *  and so probably need not be too efficient.
  1424. X */
  1425. Xvoid
  1426. Xdos2unixtime(ddp, dtp, tvp)
  1427. X    union dosdate *ddp;
  1428. X    union dostime *dtp;
  1429. X    struct timeval *tvp;
  1430. X{
  1431. X    unsigned long seconds;
  1432. X    unsigned long month;
  1433. X    unsigned long yr;
  1434. X    unsigned long days;
  1435. X    unsigned short *months;
  1436. X
  1437. X    seconds = (dtp->dts.dt_2seconds << 1) +
  1438. X          (dtp->dts.dt_minutes * 60) +
  1439. X          (dtp->dts.dt_hours * 60 * 60);
  1440. X/*
  1441. X *  If the year, month, and day from the last conversion
  1442. X *  are the same then use the saved value.
  1443. X */
  1444. X    if (lastdosdate.ddi != ddp->ddi) {
  1445. X        lastdosdate.ddi = ddp->ddi;
  1446. X        days = 0;
  1447. X        for (yr = 0; yr < ddp->dds.dd_year; yr++) {
  1448. X            days += yr & 0x03 ? 365 : 366;
  1449. X        }
  1450. X        months = yr & 0x03 ? regyear : leapyear;
  1451. X/*
  1452. X *  Prevent going from 0 to 0xffffffff in the following
  1453. X *  loop.
  1454. X */
  1455. X        if (ddp->dds.dd_month == 0) {
  1456. X            printf("dos2unixtime(): month value out of range (%d)\n",
  1457. X                ddp->dds.dd_month);
  1458. X            ddp->dds.dd_month = 1;
  1459. X        }
  1460. X        for (month = 0; month < ddp->dds.dd_month-1; month++) {
  1461. X            days += months[month];
  1462. X        }
  1463. X        days += ddp->dds.dd_day - 1;
  1464. X        lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
  1465. X    }
  1466. X    tvp->tv_sec = seconds + lastseconds + (tz.tz_minuteswest * 60)
  1467. X        /* -+ daylight savings time correction */;
  1468. X    tvp->tv_usec = 0;
  1469. X}
  1470. X
  1471. X/*
  1472. X *  Cheezy macros to do case detection and conversion
  1473. X *  for the ascii character set.  DOESN'T work for ebcdic.
  1474. X */
  1475. X#define    isupper(c)    (c >= 'A'  &&  c <= 'Z')
  1476. X#define    islower(c)    (c >= 'a'  &&  c <= 'z')
  1477. X#define    toupper(c)    (c & ~' ')
  1478. X#define    tolower(c)    (c | ' ')
  1479. X
  1480. X/*
  1481. X *  DOS filenames are made of 2 parts, the name part and
  1482. X *  the extension part.  The name part is 8 characters
  1483. X *  long and the extension part is 3 characters long.  They
  1484. X *  may contain trailing blanks if the name or extension
  1485. X *  are not long enough to fill their respective fields.
  1486. X */
  1487. X
  1488. X/*
  1489. X *  Convert a DOS filename to a unix filename.
  1490. X *  And, return the number of characters in the
  1491. X *  resulting unix filename excluding the terminating
  1492. X *  null.
  1493. X */
  1494. Xint
  1495. Xdos2unixfn(dn, un)
  1496. X    unsigned char dn[11];
  1497. X    unsigned char *un;
  1498. X{
  1499. X    int i;
  1500. X    int ni;
  1501. X    int ei;
  1502. X    int thislong = 0;
  1503. X    unsigned char c;
  1504. X    unsigned char *origun = un;
  1505. X
  1506. X/*
  1507. X *  Find the last character in the name portion
  1508. X *  of the dos filename.
  1509. X */
  1510. X    for (ni = 7; ni >= 0; ni--)
  1511. X        if (dn[ni] != ' ') break;
  1512. X
  1513. X/*
  1514. X *  Find the last character in the extension
  1515. X *  portion of the filename.
  1516. X */
  1517. X    for (ei = 10; ei >= 8; ei--)
  1518. X        if (dn[ei] != ' ') break;
  1519. X
  1520. X/*
  1521. X *  Copy the name portion into the unix filename
  1522. X *  string.
  1523. X *  NOTE: DOS filenames are usually kept in upper
  1524. X *  case.  To make it more unixy we convert all
  1525. X *  DOS filenames to lower case.  Some may like
  1526. X *  this, some may not.
  1527. X */
  1528. X    for (i = 0; i <= ni; i++) {
  1529. X        c = dn[i];
  1530. X        *un++ = isupper(c) ? tolower(c) : c;
  1531. X        thislong++;
  1532. X    }
  1533. X
  1534. X/*
  1535. X *  Now, if there is an extension then put in a period
  1536. X *  and copy in the extension.
  1537. X */
  1538. X    if (ei >= 8) {
  1539. X        *un++ = '.';
  1540. X        thislong++;
  1541. X        for (i = 8; i <= ei; i++) {
  1542. X            c = dn[i];
  1543. X            *un++ = isupper(c) ? tolower(c) : c;
  1544. X            thislong++;
  1545. X        }
  1546. X    }
  1547. X    *un++ = 0;
  1548. X
  1549. X/*
  1550. X *  If first char of the filename is SLOT_E5 (0x05), then
  1551. X *  the real first char of the filename should be 0xe5.
  1552. X *  But, they couldn't just have a 0xe5 mean 0xe5 because
  1553. X *  that is used to mean a freed directory slot.
  1554. X *  Another dos quirk.
  1555. X */
  1556. X    if (*origun == SLOT_E5)
  1557. X        *origun = 0xe5;
  1558. X
  1559. X    return thislong;
  1560. X}
  1561. X
  1562. X/*
  1563. X *  Convert a unix filename to a DOS filename.
  1564. X *  This function does not ensure that valid
  1565. X *  characters for a dos filename are supplied.
  1566. X */
  1567. Xvoid
  1568. Xunix2dosfn(un, dn, unlen)
  1569. X    unsigned char *un;
  1570. X    unsigned char dn[11];
  1571. X    int unlen;
  1572. X{
  1573. X    int i;
  1574. X    unsigned char c;
  1575. X
  1576. X/*
  1577. X *  Fill the dos filename string with blanks.
  1578. X *  These are DOS's pad characters.
  1579. X */
  1580. X    for (i = 0; i <= 10; i++)
  1581. X        dn[i] = ' ';
  1582. X
  1583. X/*
  1584. X *  The filenames "." and ".." are handled specially,
  1585. X *  since they don't follow dos filename rules.
  1586. X */
  1587. X    if (un[0] == '.'  &&  un[1] == '\0') {
  1588. X        dn[0] = '.';
  1589. X        return;
  1590. X    }
  1591. X    if (un[0] == '.'  &&  un[1] == '.'  &&  un[2] == '\0') {
  1592. X        dn[0] = '.';
  1593. X        dn[1] = '.';
  1594. X        return;
  1595. X    }
  1596. X
  1597. X/*
  1598. X *  Copy the unix filename into the dos filename string
  1599. X *  upto the end of string, a '.', or 8 characters.
  1600. X *  Whichever happens first stops us.
  1601. X *  This forms the name portion of the dos filename.
  1602. X *  Fold to upper case.
  1603. X */
  1604. X    for (i = 0; i <= 7  &&  unlen  &&  (c = *un)  &&  c != '.'; i++) {
  1605. X        dn[i] = islower(c) ? toupper(c) : c;
  1606. X        un++;
  1607. X        unlen--;
  1608. X    }
  1609. X
  1610. X/*
  1611. X *  If the first char of the filename is 0xe5, then translate
  1612. X *  it to 0x05.  This is because 0xe5 is the marker for a
  1613. X *  deleted directory slot.  I guess this means you can't
  1614. X *  have filenames that start with 0x05.  I suppose we should
  1615. X *  check for this and doing something about it.
  1616. X */
  1617. X    if (dn[0] == SLOT_DELETED)
  1618. X        dn[0] = SLOT_E5;
  1619. X
  1620. X/*
  1621. X *  Strip any further characters up to a '.' or the
  1622. X *  end of the string.
  1623. X */
  1624. X    while (unlen  &&  (c = *un)  &&  c != '.') {
  1625. X        un++;
  1626. X        unlen--;
  1627. X    }
  1628. X
  1629. X/*
  1630. X *  If we stopped on a '.', then get past it.
  1631. X */
  1632. X    if (c == '.') un++;
  1633. X
  1634. X/*
  1635. X *  Copy in the extension part of the name, if any.
  1636. X *  Force to upper case.
  1637. X *  Note that the extension is allowed to contain '.'s.
  1638. X *  Filenames in this form are probably inaccessable
  1639. X *  under dos.
  1640. X */
  1641. X    for (i = 8; i <= 10  &&  unlen  &&  (c = *un); i++) {
  1642. X        dn[i] = islower(c) ? toupper(c) : c;
  1643. X        un++;
  1644. X        unlen--;
  1645. X    }
  1646. X}
  1647. X
  1648. X/*
  1649. X *  Get rid of these macros before someone discovers
  1650. X *  we are using such hideous things.
  1651. X */
  1652. X#undef    isupper
  1653. X#undef    islower
  1654. X#undef    toupper
  1655. X#undef    tolower
  1656. END-of-/sys/pcfs/pcfs_conv.c
  1657. exit
  1658.  
  1659.