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

  1. Xref: sparky comp.unix.bsd:9005 alt.sources:2541
  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 3/5
  6. Message-ID: <bc0H03vfbbM800@amdahl.uts.amdahl.com>
  7. Date: 17 Nov 92 17:26:49 GMT
  8. Followup-To: comp.unix.bsd
  9. Organization: Amdahl Corporation, Sunnyvale CA
  10. Lines: 1660
  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_lookup.c
  21. #    /sys/pcfs/pcfs_fat.c
  22. #
  23. echo x - /sys/pcfs/pcfs_lookup.c
  24. sed 's/^X//' >/sys/pcfs/pcfs_lookup.c << 'END-of-/sys/pcfs/pcfs_lookup.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 "namei.h"
  45. X#include "buf.h"
  46. X#include "vnode.h"
  47. X#include "mount.h"
  48. X
  49. X#include "bpb.h"
  50. X#include "direntry.h"
  51. X#include "denode.h"
  52. X#include "pcfsmount.h"
  53. X#include "fat.h"
  54. X
  55. X/*
  56. X *  When we search a directory the blocks containing directory
  57. X *  entries are read and examined.  The directory entries
  58. X *  contain information that would normally be in the inode
  59. X *  of a unix filesystem.  This means that some of a directory's
  60. X *  contents may also be in memory resident denodes (sort of
  61. X *  an inode).  This can cause problems if we are searching
  62. X *  while some other process is modifying a directory.  To
  63. X *  prevent one process from accessing incompletely modified
  64. X *  directory information we depend upon being the soul owner
  65. X *  of a directory block.  bread/brelse provide this service.
  66. X *  This being the case, when a process modifies a directory
  67. X *  it must first acquire the disk block that contains the
  68. X *  directory entry to be modified.  Then update the disk
  69. X *  block and the denode, and then write the disk block out
  70. X *  to disk.  This way disk blocks containing directory
  71. X *  entries and in memory denode's will be in synch.
  72. X */
  73. Xint
  74. Xpcfs_lookup(vdp, ndp, p)
  75. X    struct vnode *vdp;    /* vnode of directory to search        */
  76. X    struct nameidata *ndp;
  77. X    struct proc *p;
  78. X{
  79. X    daddr_t bn;
  80. X    int flag;
  81. X    int error;
  82. X    int lockparent;
  83. X    int wantparent;
  84. X    int slotstatus;
  85. X#define    NONE    0
  86. X#define    FOUND    1
  87. X    int slotoffset;
  88. X    int slotcluster;
  89. X    int frcn;
  90. X    unsigned long cluster;
  91. X    int rootreloff;
  92. X    int diroff;
  93. X    int isadir;        /* ~0 if found direntry is a directory    */
  94. X    unsigned long scn;    /* starting cluster number        */
  95. X    struct denode *dp;
  96. X    struct denode *pdp;
  97. X    struct denode *tdp;
  98. X    struct pcfsmount *pmp;
  99. X    struct buf *bp = 0;
  100. X    struct direntry *dep;
  101. X    unsigned char dosfilename[12];
  102. X
  103. X#if defined(PCFSDEBUG)
  104. Xprintf("pcfs_lookup(): looking for %s\n", ndp->ni_ptr);
  105. X#endif /* defined(PCFSDEBUG) */
  106. X    ndp->ni_dvp = vdp;
  107. X    ndp->ni_vp  = NULL;
  108. X    dp = VTODE(vdp);
  109. X    pmp = dp->de_pmp;
  110. X    lockparent = ndp->ni_nameiop & LOCKPARENT;
  111. X    flag = ndp->ni_nameiop & OPMASK;
  112. X    wantparent = ndp->ni_nameiop & (LOCKPARENT | WANTPARENT);
  113. X#if defined(PCFSDEBUG)
  114. Xprintf("pcfs_lookup(): vdp %08x, dp %08x, Attr %02x\n",
  115. X    vdp, dp, dp->de_Attributes);
  116. X#endif /* defined(PCFSDEBUG) */
  117. X
  118. X/*
  119. X *  Be sure vdp is a directory.  Since dos filesystems
  120. X *  don't have the concept of execute permission anybody
  121. X *  can search a directory.
  122. X */
  123. X    if ((dp->de_Attributes & ATTR_DIRECTORY) == 0)
  124. X        return ENOTDIR;
  125. X
  126. X/*
  127. X *  See if the component of the pathname we are looking for
  128. X *  is in the directory cache.  If so then do a few things
  129. X *  and return.
  130. X */
  131. X    if (error = cache_lookup(ndp)) {
  132. X        int vpid;
  133. X
  134. X        if (error == ENOENT)
  135. X            return error;
  136. X#ifdef PARANOID
  137. X        if (vdp == ndp->ni_rdir  &&  ndp->ni_isdotdot)
  138. X            panic("pcfs_lookup: .. thru root");
  139. X#endif /* PARANOID */
  140. X        pdp = dp;
  141. X        vdp = ndp->ni_vp;
  142. X        dp  = VTODE(vdp);
  143. X        vpid = vdp->v_id;
  144. X        if (pdp == dp) {
  145. X            VREF(vdp);
  146. X            error = 0;
  147. X        } else if (ndp->ni_isdotdot) {
  148. X            DEUNLOCK(pdp);
  149. X            error = vget(vdp);
  150. X            if (!error && lockparent && *ndp->ni_next == '\0')
  151. X                DELOCK(pdp);
  152. X        } else {
  153. X            error = vget(vdp);
  154. X            if (!lockparent || error || *ndp->ni_next != '\0')
  155. X                DEUNLOCK(pdp);
  156. X        }
  157. X
  158. X        if (!error) {
  159. X            if (vpid == vdp->v_id) {
  160. X#if defined(PCFSDEBUG)
  161. Xprintf("pcfs_lookup(): cache hit, vnode %08x, file %s\n", vdp, dp->de_Name);
  162. X#endif /* defined(PCFSDEBUG) */
  163. X                return 0;
  164. X            }
  165. X            deput(dp);
  166. X            if (lockparent && pdp != dp && *ndp->ni_next == '\0')
  167. X                DEUNLOCK(pdp);
  168. X        }
  169. X        DELOCK(pdp);
  170. X        dp = pdp;
  171. X        vdp = DETOV(dp);
  172. X        ndp->ni_vp = NULL;
  173. X    }
  174. X
  175. X/*
  176. X *  If they are going after the . or .. entry in the
  177. X *  root directory, they won't find it.  DOS filesystems
  178. X *  don't have them in the root directory.  So, we fake it.
  179. X *  deget() is in on this scam too.
  180. X */
  181. X    if ((vdp->v_flag & VROOT)  &&  ndp->ni_ptr[0] == '.'  &&
  182. X        (ndp->ni_namelen == 1  ||
  183. X         (ndp->ni_namelen == 2  &&  ndp->ni_ptr[1] == '.'))) {
  184. X        isadir = ATTR_DIRECTORY;
  185. X        scn = PCFSROOT;
  186. X        diroff = -1;
  187. X        cluster = ~0;
  188. X#if defined(PCFSDEBUG)
  189. Xprintf("pcfs_lookup(): looking for . or .. in root directory\n");
  190. X#endif /* defined(PCFSDEBUG) */
  191. X        goto foundroot;
  192. X    }
  193. X
  194. X/*
  195. X *  Don't search for free slots unless we are creating
  196. X *  a filename and we are at the end of the pathname.
  197. X */
  198. X    slotstatus = FOUND;
  199. X    if ((flag == CREATE || flag == RENAME) && *ndp->ni_next == '\0') {
  200. X        slotstatus = NONE;
  201. X        slotoffset = -1;
  202. X    }
  203. X
  204. X    unix2dosfn((unsigned char *)ndp->ni_ptr, dosfilename, ndp->ni_namelen);
  205. X    dosfilename[11] = 0;
  206. X#if defined(PCFSDEBUG)
  207. Xprintf("pcfs_lookup(): dos version of filename %s, length %d\n",
  208. X    dosfilename, ndp->ni_namelen);
  209. X#endif /* defined(PCFSDEBUG) */
  210. X/*
  211. X *  Search the directory pointed at by vdp for the
  212. X *  name pointed at by ndp->ni_ptr.
  213. X */
  214. X    tdp = NULL;
  215. X/*
  216. X *  The outer loop ranges over the clusters that make
  217. X *  up the directory.  Note that the root directory is
  218. X *  different from all other directories.  It has a
  219. X *  fixed number of blocks that are not part of the
  220. X *  pool of allocatable clusters.  So, we treat it a
  221. X *  little differently.
  222. X *  The root directory starts at "cluster" 0.
  223. X */
  224. X    rootreloff = 0;
  225. X    for (frcn = 0; ; frcn++) {
  226. X        if (error = pcbmap(dp, frcn, &bn, &cluster)) {
  227. X            if (error == E2BIG)
  228. X                break;
  229. X            return error;
  230. X        }
  231. X        if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, &bp)) {
  232. X            brelse(bp);
  233. X            return error;
  234. X        }
  235. X        for (diroff = 0; diroff < pmp->pm_depclust; diroff++) {
  236. X            dep = (struct direntry *)bp->b_un.b_addr + diroff;
  237. X
  238. X/*
  239. X *  If the slot is empty and we are still looking for
  240. X *  an empty then remember this one.  If the slot is
  241. X *  not empty then check to see if it matches what we
  242. X *  are looking for.  If the slot has never been filled
  243. X *  with anything, then the remainder of the directory
  244. X *  has never been used, so there is no point in searching
  245. X *  it.
  246. X */
  247. X            if (dep->deName[0] == SLOT_EMPTY   ||
  248. X                dep->deName[0] == SLOT_DELETED) {
  249. X                if (slotstatus != FOUND) {
  250. X                    slotstatus  = FOUND;
  251. X                    if (cluster == PCFSROOT)
  252. X                        slotoffset = rootreloff;
  253. X                    else
  254. X                        slotoffset = diroff;
  255. X                    slotcluster = cluster;
  256. X                }
  257. X                if (dep->deName[0] == SLOT_EMPTY) {
  258. X                    brelse(bp);
  259. X                    goto notfound;
  260. X                }
  261. X            } else {
  262. X                /* Ignore volume labels (anywhere, not just
  263. X                 * the root directory). */
  264. X                if ((dep->deAttributes & ATTR_VOLUME) == 0  &&
  265. X                    bcmp(dosfilename, dep->deName, 11) == 0) {
  266. X#if defined(PCFSDEBUG)
  267. Xprintf("pcfs_lookup(): match diroff %d, rootreloff %d\n", diroff, rootreloff);
  268. X#endif /* defined(PCFSDEBUG) */
  269. X/*
  270. X *  Remember where this directory entry came from
  271. X *  for whoever did this lookup.
  272. X *  If this is the root directory we are interested
  273. X *  in the offset relative to the beginning of the
  274. X *  directory (not the beginning of the cluster).
  275. X */
  276. X                    if (cluster == PCFSROOT)
  277. X                        diroff = rootreloff;
  278. X                    ndp->ni_pcfs.pcfs_offset = diroff;
  279. X                    ndp->ni_pcfs.pcfs_cluster = cluster;
  280. X                    goto found;
  281. X                }
  282. X            }
  283. X            rootreloff++;
  284. X        }            /* for (diroff = 0; .... */
  285. X/*
  286. X *  Release the buffer holding the directory cluster
  287. X *  just searched.
  288. X */
  289. X        brelse(bp);
  290. X    }            /* for (frcn = 0; ; frcn++) */
  291. Xnotfound:;
  292. X/*
  293. X *  We hold no disk buffers at this point.
  294. X */
  295. X
  296. X/*
  297. X *  If we get here we didn't find the entry we were looking
  298. X *  for.  But that's ok if we are creating or renaming and
  299. X *  are at the end of the pathname and the directory hasn't
  300. X *  been removed.
  301. X */
  302. X#if defined(PCFSDEBUG)
  303. Xprintf("pcfs_lookup(): flag %d, refcnt %d, slotstatus %d\n",
  304. X    flag, dp->de_refcnt, slotstatus);
  305. Xprintf("               slotoffset %d, slotcluster %d\n",
  306. X    slotoffset, slotcluster);
  307. X#endif /* defined(PCFSDEBUG) */
  308. X    if ((flag == CREATE || flag == RENAME)  &&
  309. X        *ndp->ni_next == '\0' && dp->de_refcnt != 0) {
  310. X        if (slotstatus == NONE) {
  311. X            ndp->ni_pcfs.pcfs_offset  = 0;
  312. X            ndp->ni_pcfs.pcfs_cluster = 0;
  313. X            ndp->ni_pcfs.pcfs_count   = 0;
  314. X        } else {
  315. X#if defined(PCFSDEBUG)
  316. Xprintf("pcfs_lookup(): saving empty slot location\n");
  317. X#endif /* defined(PCFSDEBUG) */
  318. X            ndp->ni_pcfs.pcfs_offset  = slotoffset;
  319. X            ndp->ni_pcfs.pcfs_cluster = slotcluster;
  320. X            ndp->ni_pcfs.pcfs_count   = 1;
  321. X        }
  322. X/*        dp->de_flag |= DEUPD; /* never update dos directories */
  323. X        ndp->ni_nameiop |= SAVENAME;
  324. X        if (!lockparent)    /* leave searched dir locked?    */
  325. X            DEUNLOCK(dp);
  326. X    }
  327. X/*
  328. X *  Insert name in cache as non-existant if not
  329. X *  trying to create it.
  330. X */
  331. X    if (ndp->ni_makeentry && flag != CREATE)
  332. X        cache_enter(ndp);
  333. X    return ENOENT;
  334. X
  335. Xfound:;
  336. X/*
  337. X *  NOTE:  We still have the buffer with matched
  338. X *  directory entry at this point.
  339. X */
  340. X    isadir = dep->deAttributes & ATTR_DIRECTORY;
  341. X    scn = dep->deStartCluster;
  342. X
  343. Xfoundroot:;
  344. X/*
  345. X *  If we entered at foundroot, then we are looking
  346. X *  for the . or .. entry of the filesystems root
  347. X *  directory.  isadir and scn were setup before
  348. X *  jumping here.  And, bp is null.  There is no buf header.
  349. X */
  350. X
  351. X/*
  352. X *  If deleting and at the end of the path, then
  353. X *  if we matched on "." then don't deget() we would
  354. X *  probably panic().  Otherwise deget() the directory
  355. X *  entry.
  356. X */
  357. X    if (flag == DELETE && ndp->ni_next == '\0') {
  358. X        if (dp->de_StartCluster == scn  &&
  359. X            isadir) { /* "." */
  360. X            VREF(vdp);
  361. X            ndp->ni_vp = vdp;
  362. X            if (bp) brelse(bp);
  363. X            return 0;
  364. X        }
  365. X        error = deget(pmp, isadir,
  366. X            cluster, diroff, scn, bp, &tdp);
  367. X        if (error) {
  368. X            if (bp) brelse(bp);
  369. X            return error;
  370. X        }
  371. X        ndp->ni_vp = DETOV(tdp);
  372. X        if (!lockparent)
  373. X            DEUNLOCK(dp);
  374. X        if (bp) brelse(bp);
  375. X        return 0;
  376. X    }
  377. X
  378. X/*
  379. X *  If renaming.
  380. X */
  381. X    if (flag == RENAME && wantparent && *ndp->ni_next == '\0') {
  382. X        if (dp->de_StartCluster == scn  &&
  383. X            isadir) {
  384. X            if (bp) brelse(bp);
  385. X            return EISDIR;
  386. X        }
  387. X        error = deget(pmp, isadir, cluster, diroff,
  388. X            scn, bp, &tdp);
  389. X        if (error) {
  390. X            if (bp) brelse(bp);
  391. X            return error;
  392. X        }
  393. X        ndp->ni_vp = DETOV(tdp);
  394. X        ndp->ni_nameiop |= SAVENAME;
  395. X        if (!lockparent)
  396. X            DEUNLOCK(dp);
  397. X        if (bp) brelse(bp);
  398. X        return 0;
  399. X    }
  400. X
  401. X/*
  402. X *  ?
  403. X */
  404. X    pdp = dp;
  405. X    if (ndp->ni_isdotdot) {
  406. X        DEUNLOCK(pdp);
  407. X        error = deget(pmp, isadir, cluster, diroff,
  408. X            scn, bp, &tdp);
  409. X        if (error) {
  410. X            DELOCK(pdp);
  411. X            if (bp) brelse(bp);
  412. X            return error;
  413. X        }
  414. X        if (lockparent && *ndp->ni_next == '\0')
  415. X            DELOCK(pdp);
  416. X        ndp->ni_vp = DETOV(tdp);
  417. X    } else if (dp->de_StartCluster == scn  &&
  418. X           isadir) { /* "." */
  419. X        VREF(vdp);
  420. X        ndp->ni_vp = vdp;
  421. X    } else {
  422. X        error = deget(pmp, isadir, cluster, diroff,
  423. X            scn, bp, &tdp);
  424. X        if (error) {
  425. X            if (bp) brelse(bp);
  426. X            return error;
  427. X        }
  428. X        if (!lockparent || *ndp->ni_next != '\0')
  429. X            DEUNLOCK(pdp);
  430. X        ndp->ni_vp = DETOV(tdp);
  431. X    }
  432. X    if (bp) brelse(bp);
  433. X
  434. X/*
  435. X *  Insert name in cache if wanted.
  436. X */
  437. X    if (ndp->ni_makeentry)
  438. X        cache_enter(ndp);
  439. X    return 0;
  440. X}
  441. X
  442. X/*
  443. X *  dep - directory to copy into the directory
  444. X *  ndp - nameidata structure containing info on
  445. X *    where to put the directory entry in the directory.
  446. X *  depp - return the address of the denode for the
  447. X *    created directory entry if depp != 0
  448. X */
  449. Xint
  450. Xcreatede(dep, ndp, depp)
  451. X    struct denode *dep;
  452. X    struct nameidata *ndp;
  453. X    struct denode **depp;
  454. X{
  455. X    int bn;
  456. X    int error;
  457. X    int theoff;
  458. X    int isadir = dep->de_Attributes & ATTR_DIRECTORY;
  459. X    unsigned long newcluster;
  460. X    struct direntry *ndep;
  461. X    struct denode *ddep = VTODE(ndp->ni_dvp);    /* directory to add to */
  462. X    struct pcfsmount *pmp = dep->de_pmp;
  463. X    struct buf *bp;
  464. X#if defined(PCFSDEBUG)
  465. Xprintf("createde(dep %08x, ndp %08x, depp %08x)\n", dep, ndp, depp);
  466. X#endif /* defined(PCFSDEBUG) */
  467. X
  468. X/*
  469. X *  If no space left in the directory then allocate
  470. X *  another cluster and chain it onto the end of the
  471. X *  file.  There is one exception to this.  That is,
  472. X *  if the root directory has no more space it can NOT
  473. X *  be expanded.  extendfile() checks for and fails attempts to
  474. X *  extend the root directory.  We just return an error
  475. X *  in that case.
  476. X */
  477. X    if (ndp->ni_pcfs.pcfs_count == 0) {
  478. X        if (error = extendfile(ddep, &bp, &newcluster))
  479. X            return error;
  480. X        ndep = (struct direntry *)bp->b_un.b_addr;
  481. X        *ndep = dep->de_de;
  482. X/*
  483. X *  If they want us to return with the denode gotten.
  484. X */
  485. X        if (depp) {
  486. X            error = deget(pmp, isadir, newcluster, 0,
  487. X                dep->de_StartCluster, bp, depp);
  488. X            if (error) {
  489. X                return error;
  490. X            }
  491. X        }
  492. X
  493. X        if (error = bwrite(bp)) {
  494. X/*deput()?*/
  495. X            return error;
  496. X        }
  497. X/*
  498. X *  Let caller know where we put the directory entry.
  499. X */
  500. X        ndp->ni_pcfs.pcfs_cluster = newcluster;
  501. X        ndp->ni_pcfs.pcfs_offset  = 0;
  502. X        return 0;
  503. X    }
  504. X
  505. X/*
  506. X *  There is space in the existing directory.  So,
  507. X *  we just read in the cluster with space.  Copy
  508. X *  the new directory entry in.  Then write it to
  509. X *  disk.
  510. X *  NOTE:  DOS directories do not get smaller as
  511. X *  clusters are emptied.
  512. X */
  513. X    if (ndp->ni_pcfs.pcfs_cluster == PCFSROOT) {
  514. X        bn = pmp->pm_rootdirblk +
  515. X            (ndp->ni_pcfs.pcfs_offset / pmp->pm_depclust);
  516. X        theoff = ndp->ni_pcfs.pcfs_offset % pmp->pm_depclust;
  517. X    } else {
  518. X        bn = cntobn(pmp, ndp->ni_pcfs.pcfs_cluster);
  519. X        theoff = ndp->ni_pcfs.pcfs_offset;
  520. X    }
  521. X    if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
  522. X        NOCRED, &bp)) {
  523. X        brelse(bp);
  524. X        return error;
  525. X    }
  526. X    ndep = (struct direntry *)(bp->b_un.b_addr) + theoff;
  527. X    *ndep = dep->de_de;
  528. X/*
  529. X *  If they want us to return with the denode gotten.
  530. X */
  531. X    if (depp) {
  532. X        error = deget(pmp, isadir, ndp->ni_pcfs.pcfs_cluster,
  533. X            ndp->ni_pcfs.pcfs_offset,
  534. X            dep->de_StartCluster, bp, depp);
  535. X        if (error) {
  536. X            return error;
  537. X        }
  538. X    }
  539. X    if (error = bwrite(bp))
  540. X/*deput()?*/
  541. X        return error;        /* do a brelse() if error ? */
  542. X    return 0;
  543. X}
  544. X
  545. X/*
  546. X *  Read in a directory entry and mark it as being deleted.
  547. X */
  548. Xint
  549. Xmarkdeleted(pmp, dirclust, diroffset)
  550. X    struct pcfsmount *pmp;
  551. X    unsigned long dirclust;
  552. X    unsigned long diroffset;
  553. X{
  554. X    int offset;
  555. X    int error;
  556. X    daddr_t bn;
  557. X    struct direntry *ep;
  558. X    struct buf *bp;
  559. X
  560. X    if (dirclust == PCFSROOT) {
  561. X        bn = pmp->pm_rootdirblk + (diroffset / pmp->pm_depclust);
  562. X        offset = diroffset % pmp->pm_depclust;
  563. X    } else {
  564. X        bn = cntobn(pmp, dirclust);
  565. X        offset = diroffset;
  566. X    }
  567. X/*printf("markdeleted(): bread()ing block %d\n", bn);*/
  568. X    if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, &bp)) {
  569. X        brelse(bp);
  570. X        return error;
  571. X    }
  572. X
  573. X    ep = (struct direntry *)bp->b_un.b_addr + offset;
  574. X    ep->deName[0] = SLOT_DELETED;
  575. X
  576. X    return bwrite(bp);
  577. X}
  578. X
  579. X/*
  580. X *  Remove a directory entry.
  581. X *  At this point the file represented by the directory
  582. X *  entry to be removed is still full length until no
  583. X *  one has it open.  When the file no longer being
  584. X *  used pcfs_inactive() is called and will truncate
  585. X *  the file to 0 length.  When the vnode containing
  586. X *  the denode is needed for some other purpose by 
  587. X *  VFS it will call pcfs_reclaim() which will remove
  588. X *  the denode from the denode cache.
  589. X */
  590. Xint
  591. Xremovede(ndp)
  592. X    struct nameidata *ndp;
  593. X{
  594. X    struct denode *dep = VTODE(ndp->ni_vp);    /* the file being removed */
  595. X    struct pcfsmount *pmp = dep->de_pmp;
  596. X    int error;
  597. X
  598. X#if defined(PCFSDEBUG)
  599. X/*printf("removede(): filename %s\n", dep->de_Name);
  600. Xprintf("rmde(): dep %08x, ndpcluster %d, ndpoffset %d\n",
  601. X    dep, ndp->ni_pcfs.pcfs_cluster, ndp->ni_pcfs.pcfs_offset);*/
  602. X#endif /* defined(PCFSDEBUG) */
  603. X
  604. X/*
  605. X *  Read the directory block containing the directory
  606. X *  entry we are to make free.  The nameidata structure
  607. X *  holds the cluster number and directory entry index
  608. X *  number of the entry to free.
  609. X */
  610. X    error = markdeleted(pmp, ndp->ni_pcfs.pcfs_cluster,
  611. X        ndp->ni_pcfs.pcfs_offset);
  612. X
  613. X    dep->de_refcnt--;
  614. X    return error;
  615. X}
  616. X
  617. X/*
  618. X *  Be sure a directory is empty except for "." and "..".
  619. X *  Return 1 if empty, return 0 if not empty or error.
  620. X */
  621. Xint
  622. Xdosdirempty(dep)
  623. X    struct denode *dep;
  624. X{
  625. X    int dei;
  626. X    int error;
  627. X    unsigned long cn;
  628. X    daddr_t bn;
  629. X    struct buf *bp;
  630. X    struct pcfsmount *pmp = dep->de_pmp;
  631. X    struct direntry *dentp;
  632. X
  633. X/*
  634. X *  Since the filesize field in directory entries for a directory
  635. X *  is zero, we just have to feel our way through the directory
  636. X *  until we hit end of file.
  637. X */
  638. X    for (cn = 0;; cn++) {
  639. X        error = pcbmap(dep, cn, &bn, 0);
  640. X        if (error == E2BIG)
  641. X            return 1;    /* it's empty */
  642. X        error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED,
  643. X            &bp);
  644. X        if (error) {
  645. X            brelse(bp);
  646. X            return error;
  647. X        }
  648. X        dentp = (struct direntry *)bp->b_un.b_addr;
  649. X        for (dei = 0; dei < pmp->pm_depclust; dei++) {
  650. X            if (dentp->deName[0] != SLOT_DELETED) {
  651. X/*
  652. X *  In dos directories an entry whose name starts with SLOT_EMPTY (0)
  653. X *  starts the beginning of the unused part of the directory, so we
  654. X *  can just return that it is empty.
  655. X */
  656. X                if (dentp->deName[0] == SLOT_EMPTY) {
  657. X                    brelse(bp);
  658. X                    return 1;
  659. X                }
  660. X/*
  661. X *  Any names other than "." and ".." in a directory mean
  662. X *  it is not empty.
  663. X */
  664. X                if (bcmp(dentp->deName, ".          ", 11)  &&
  665. X                    bcmp(dentp->deName, "..         ", 11)) {
  666. X                    brelse(bp);
  667. X#if defined(PCFSDEBUG)
  668. Xprintf("dosdirempty(): entry %d found %02x, %02x\n", dei, dentp->deName[0],
  669. X    dentp->deName[1]);
  670. X#endif /* defined(PCFSDEBUG) */
  671. X                    return 0;    /* not empty */
  672. X                }
  673. X            }
  674. X            dentp++;
  675. X        }
  676. X        brelse(bp);
  677. X    }
  678. X    /*NOTREACHED*/
  679. X}
  680. X
  681. X/*
  682. X *  Check to see if the directory described by target is
  683. X *  in some subdirectory of source.  This prevents something
  684. X *  like the following from succeeding and leaving a bunch
  685. X *  or files and directories orphaned.
  686. X *    mv /a/b/c /a/b/c/d/e/f
  687. X *  Where c and f are directories.
  688. X *  source - the inode for /a/b/c
  689. X *  target - the inode for /a/b/c/d/e/f
  690. X *  Returns 0 if target is NOT a subdirectory of source.
  691. X *  Otherwise returns a non-zero error number.
  692. X *  The target inode is always unlocked on return.
  693. X */
  694. Xint
  695. Xdoscheckpath(source, target)
  696. X    struct denode *source;
  697. X    struct denode *target;
  698. X{
  699. X    daddr_t scn;
  700. X    struct denode dummy;
  701. X    struct pcfsmount *pmp;
  702. X    struct direntry *ep;
  703. X    struct denode *dep;
  704. X    struct buf *bp = NULL;
  705. X    int error = 0;
  706. X
  707. X    dep = target;
  708. X    if ((target->de_Attributes & ATTR_DIRECTORY) == 0  ||
  709. X        (source->de_Attributes & ATTR_DIRECTORY) == 0) {
  710. X        error = ENOTDIR;
  711. X        goto out;
  712. X    }
  713. X    if (dep->de_StartCluster == source->de_StartCluster) {
  714. X        error = EEXIST;
  715. X        goto out;
  716. X    }
  717. X    if (dep->de_StartCluster == PCFSROOT)
  718. X        goto out;
  719. X    for (;;) {
  720. X        if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
  721. X            error = ENOTDIR;
  722. X            goto out;
  723. X        }
  724. X        pmp = dep->de_pmp;
  725. X        scn = dep->de_StartCluster;
  726. X        error = bread(pmp->pm_devvp, cntobn(pmp, scn),
  727. X            pmp->pm_bpcluster, NOCRED, &bp);
  728. X        if (error) {
  729. X            break;
  730. X        }
  731. X        ep = (struct direntry *)bp->b_un.b_addr + 1;
  732. X        if ((ep->deAttributes & ATTR_DIRECTORY) == 0  ||
  733. X            bcmp(ep->deName, "..         ", 11) != 0) {
  734. X            error = ENOTDIR;
  735. X            break;
  736. X        }
  737. X        if (ep->deStartCluster == source->de_StartCluster) {
  738. X            error = EINVAL;
  739. X            break;
  740. X        }
  741. X        if (ep->deStartCluster == PCFSROOT)
  742. X            break;
  743. X        deput(dep);
  744. X        /* NOTE: deget() clears dep on error */
  745. X        error = deget(pmp, ATTR_DIRECTORY, scn, 1,
  746. X            ep->deStartCluster, bp, &dep);
  747. X        brelse(bp);
  748. X        bp = NULL;
  749. X        if (error)
  750. X            break;
  751. X    }
  752. Xout:;
  753. X    if (bp)
  754. X        brelse(bp);
  755. X    if (error == ENOTDIR)
  756. X        printf("doscheckpath(): .. not a directory?\n");
  757. X    if (dep != NULL)
  758. X        deput(dep);
  759. X    return error;
  760. X}
  761. X
  762. X/*
  763. X *  Read in the disk block containing the directory entry
  764. X *  dep came from and return the address of the buf header,
  765. X *  and the address of the directory entry within the block.
  766. X */
  767. Xint
  768. Xreadde(dep, bpp, epp)
  769. X    struct denode *dep;
  770. X    struct buf **bpp;
  771. X    struct direntry **epp;
  772. X{
  773. X    int error;
  774. X    daddr_t bn;
  775. X    unsigned long theoff;
  776. X    struct pcfsmount *pmp = dep->de_pmp;
  777. X
  778. X    if (dep->de_dirclust == PCFSROOT) {
  779. X        bn = pmp->pm_rootdirblk +
  780. X            (dep->de_diroffset / pmp->pm_depclust);
  781. X        theoff = dep->de_diroffset % pmp->pm_depclust;
  782. X    } else {
  783. X        bn = cntobn(pmp, dep->de_dirclust);
  784. X        theoff = dep->de_diroffset;
  785. X    }
  786. X    if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, bpp)) {
  787. X        brelse(*bpp);
  788. X        *bpp = NULL;
  789. X        return error;
  790. X    }
  791. X    if (epp)
  792. X        *epp = (struct direntry *)((*bpp)->b_un.b_addr) + theoff;
  793. X    return 0;
  794. X}
  795. END-of-/sys/pcfs/pcfs_lookup.c
  796. echo x - /sys/pcfs/pcfs_fat.c
  797. sed 's/^X//' >/sys/pcfs/pcfs_fat.c << 'END-of-/sys/pcfs/pcfs_fat.c'
  798. X/*
  799. X *  Written by Paul Popelka (paulp@uts.amdahl.com)
  800. X *
  801. X *  You can do anything you want with this software,
  802. X *    just don't say you wrote it,
  803. X *    and don't remove this notice.
  804. X *
  805. X *  This software is provided "as is".
  806. X *
  807. X *  The author supplies this software to be publicly
  808. X *  redistributed on the understanding that the author
  809. X *  is not responsible for the correct functioning of
  810. X *  this software in any circumstances and is not liable
  811. X *  for any damages caused by this software.
  812. X *
  813. X *  October 1992
  814. X */
  815. X
  816. X/*
  817. X *  kernel include files.
  818. X */
  819. X#include "param.h"
  820. X#include "systm.h"
  821. X#include "buf.h"
  822. X#include "file.h"
  823. X#include "namei.h"
  824. X#include "mount.h"    /* to define statfs structure */
  825. X#include "vnode.h"    /* to define vattr structure */
  826. X#include "errno.h"
  827. X
  828. X/*
  829. X *  pcfs include files.
  830. X */
  831. X#include "bpb.h"
  832. X#include "pcfsmount.h"
  833. X#include "direntry.h"
  834. X#include "denode.h"
  835. X#include "fat.h"
  836. X
  837. X/*
  838. X *  Fat cache stats.
  839. X */
  840. Xint fc_fileextends       = 0;    /* # of file extends            */
  841. Xint fc_lfcempty          = 0;    /* # of time last file cluster cache entry
  842. X                 * was empty */
  843. Xint fc_bmapcalls         = 0;    /* # of times pcbmap was called        */
  844. X#define    LMMAX    20
  845. Xint fc_lmdistance[LMMAX];    /* counters for how far off the last cluster
  846. X                 * mapped entry was. */
  847. Xint fc_largedistance     = 0;    /* off by more than LMMAX        */
  848. X
  849. X/*
  850. X *  Map the logical cluster number of a file into
  851. X *  a physical disk sector that is filesystem relative.
  852. X *  dep - address of denode representing the file of interest
  853. X *  findcn - file relative cluster whose filesystem relative
  854. X *    cluster number and/or block number are/is to be found
  855. X *  bnp - address of where to place the file system relative
  856. X *    block number.  If this pointer is null then don't return
  857. X *    this quantity.
  858. X *  cnp - address of where to place the file system relative
  859. X *    cluster number.  If this pointer is null then don't return
  860. X *    this quantity.
  861. X *  NOTE:
  862. X *    Either bnp or cnp must be non-null.
  863. X *    This function has one side effect.  If the requested
  864. X *    file relative cluster is beyond the end of file, then
  865. X *    the actual number of clusters in the file is returned
  866. X *    in *cnp.  This is useful for determining how long a
  867. X *    directory is.  If cnp is null, nothing is returned.
  868. X */
  869. Xint
  870. Xpcbmap(dep, findcn, bnp, cnp)
  871. X    struct denode *dep;
  872. X    unsigned long findcn;    /* file relative cluster to get        */
  873. X    daddr_t *bnp;        /* returned filesys relative blk number    */
  874. X    unsigned long *cnp;    /* returned cluster number        */
  875. X{
  876. X    int error;
  877. X    u_long i;
  878. X    u_long cn;
  879. X    u_long prevcn;
  880. X    u_long byteoffset;
  881. X    u_long bn;
  882. X    u_long bo;
  883. X    struct buf *bp0 = 0;
  884. X    u_long bp0_bn = -1;
  885. X    struct buf *bp1 = 0;
  886. X    struct pcfsmount *pmp = dep->de_pmp;
  887. X    union fattwiddle x;
  888. X
  889. X    fc_bmapcalls++;
  890. X
  891. X/*
  892. X *  If they don't give us someplace to return a value
  893. X *  then don't bother doing anything.
  894. X */
  895. X    if (bnp == NULL  &&  cnp == NULL)
  896. X        return 0;
  897. X
  898. X    i = 0;
  899. X    cn = dep->de_StartCluster;
  900. X/*
  901. X *  The "file" that makes up the root directory is contiguous,
  902. X *  permanently allocated, of fixed size, and is not made up
  903. X *  of clusters.  If the cluster number is beyond the end of
  904. X *  the root directory, then return the number of clusters in
  905. X *  the file.
  906. X */
  907. X    if (cn == PCFSROOT) {
  908. X        if (dep->de_Attributes & ATTR_DIRECTORY) {
  909. X            if (findcn * pmp->pm_SectPerClust > pmp->pm_rootdirsize) {
  910. X                if (cnp)
  911. X                    *cnp = pmp->pm_rootdirsize / pmp->pm_SectPerClust;
  912. X                return E2BIG;
  913. X            }
  914. X            if (bnp)
  915. X                *bnp = pmp->pm_rootdirblk + (findcn * pmp->pm_SectPerClust);
  916. X            if (cnp)
  917. X                *cnp = PCFSROOT;
  918. X            return 0;
  919. X        } else {    /* just an empty file */
  920. X            if (cnp)
  921. X                *cnp = 0;
  922. X            return E2BIG;
  923. X        }
  924. X    }
  925. X
  926. X/*
  927. X *  Rummage around in the fat cache, maybe we can avoid
  928. X *  tromping thru every fat entry for the file.
  929. X *  And, keep track of how far off the cache was from
  930. X *  where we wanted to be.
  931. X */
  932. X    fc_lookup(dep, findcn, &i, &cn);
  933. X    if ((bn = findcn - i) >= LMMAX)
  934. X        fc_largedistance++;
  935. X    else
  936. X        fc_lmdistance[bn]++;
  937. X
  938. X/*
  939. X *  Handle all other files or directories the normal way.
  940. X */
  941. X    if (FAT12(pmp)) {    /* 12 bit fat    */
  942. X        for (; i < findcn; i++) {
  943. X            if (PCFSEOF(cn)) {
  944. X                goto hiteof;
  945. X            }
  946. X            byteoffset = cn + (cn >> 1);
  947. X            bn = (byteoffset >> pmp->pm_bnshift) + pmp->pm_fatblk;
  948. X            bo = byteoffset &  pmp->pm_brbomask;
  949. X            if (bn != bp0_bn) {
  950. X                if (bp0)
  951. X                    brelse(bp0);
  952. X                if (error = bread(pmp->pm_devvp, bn,
  953. X                    pmp->pm_BytesPerSec, NOCRED, &bp0)) {
  954. X                    brelse(bp0);
  955. X                    return error;
  956. X                }
  957. X                bp0_bn = bn;
  958. X            }
  959. X            x.byte[0] = bp0->b_un.b_addr[bo];
  960. X/*
  961. X *  If the first byte of the fat entry was the last byte
  962. X *  in the block, then we must read the next block in the
  963. X *  fat.  We hang on to the first block we read to insure
  964. X *  that some other process doesn't update it while we
  965. X *  are waiting for the 2nd block.
  966. X *  Note that we free bp1 even though the next iteration of
  967. X *  the loop might need it.
  968. X */
  969. X            if (bo == pmp->pm_BytesPerSec-1) {
  970. X                if (error = bread(pmp->pm_devvp, bn+1,
  971. X                    pmp->pm_BytesPerSec, NOCRED, &bp1)) {
  972. X                    brelse(bp0);
  973. X                    return error;
  974. X                }
  975. X                x.byte[1] = bp1->b_un.b_addr[0];
  976. X                brelse(bp1);
  977. X            } else {
  978. X                x.byte[1] = bp0->b_un.b_addr[bo+1];
  979. X            }
  980. X            if (cn & 1)
  981. X                x.word >>= 4;
  982. X            prevcn = cn;
  983. X            cn = x.word & 0x0fff;
  984. X/*
  985. X *  Force the special cluster numbers in the range
  986. X *  0x0ff0-0x0fff to be the same as for 16 bit cluster
  987. X *  numbers to let the rest of pcfs think it is always
  988. X *  dealing with 16 bit fats.
  989. X */
  990. X            if ((cn & 0x0ff0) == 0x0ff0)
  991. X                cn |= 0xf000;
  992. X        }
  993. X    } else {                /* 16 bit fat    */
  994. X        for (; i < findcn; i++) {
  995. X            if (PCFSEOF(cn)) {
  996. X                goto hiteof;
  997. X            }
  998. X            byteoffset = cn << 1;
  999. X            bn = (byteoffset >> pmp->pm_bnshift) + pmp->pm_fatblk;
  1000. X            bo = byteoffset &  pmp->pm_brbomask;
  1001. X            if (bn != bp0_bn) {
  1002. X                if (bp0)
  1003. X                    brelse(bp0);
  1004. X                if (error = bread(pmp->pm_devvp, bn,
  1005. X                    pmp->pm_BytesPerSec, NOCRED, &bp0)) {
  1006. X                    brelse(bp0);
  1007. X                    return error;
  1008. X                }
  1009. X                bp0_bn = bn;
  1010. X            }
  1011. X            prevcn = cn;
  1012. X            cn = *(u_short *)(bp0->b_un.b_addr+bo);
  1013. X        }
  1014. X    }
  1015. X
  1016. X    if (!PCFSEOF(cn)) {
  1017. X        if (bp0)
  1018. X            brelse(bp0);
  1019. X        if (bnp)
  1020. X            *bnp = cntobn(pmp, cn);
  1021. X        if (cnp)
  1022. X            *cnp = cn;
  1023. X        fc_setcache(dep, FC_LASTMAP, i, cn);
  1024. X        return 0;
  1025. X    }
  1026. X
  1027. Xhiteof:;
  1028. X    if (cnp)
  1029. X        *cnp = i;
  1030. X    if (bp0)
  1031. X        brelse(bp0);
  1032. X    /* update last file cluster entry in the fat cache */
  1033. X    fc_setcache(dep, FC_LASTFC, i-1, prevcn);
  1034. X    return E2BIG;
  1035. X}
  1036. X
  1037. X/*
  1038. X *  Find the closest entry in the fat cache to the
  1039. X *  cluster we are looking for.
  1040. X */
  1041. Xfc_lookup(dep, findcn, frcnp, fsrcnp)
  1042. X    struct denode *dep;
  1043. X    unsigned long findcn;
  1044. X    unsigned long *frcnp;
  1045. X    unsigned long *fsrcnp;
  1046. X{
  1047. X    int i;
  1048. X    unsigned long cn;
  1049. X    struct fatcache *closest = 0;
  1050. X
  1051. X    for (i = 0; i < FC_SIZE; i++) {
  1052. X        cn = dep->de_fc[i].fc_frcn;
  1053. X        if (cn != FCE_EMPTY  &&  cn <= findcn) {
  1054. X            if (closest == 0  ||  cn > closest->fc_frcn)
  1055. X                closest = &dep->de_fc[i];
  1056. X        }
  1057. X    }
  1058. X    if (closest) {
  1059. X        *frcnp  = closest->fc_frcn;
  1060. X        *fsrcnp = closest->fc_fsrcn;
  1061. X    }
  1062. X}
  1063. X
  1064. X/*
  1065. X *  Purge the fat cache in denode dep of all entries
  1066. X *  relating to file relative cluster frcn and beyond.
  1067. X */
  1068. Xfc_purge(dep, frcn)
  1069. X    struct denode *dep;
  1070. X    unsigned int frcn;
  1071. X{
  1072. X    int i;
  1073. X    struct fatcache *fcp;
  1074. X
  1075. X    fcp = dep->de_fc;
  1076. X    for (i = 0; i < FC_SIZE; i++) {
  1077. X        if (fcp->fc_frcn != FCE_EMPTY  &&  fcp->fc_frcn >= frcn) {
  1078. X            fcp->fc_frcn = FCE_EMPTY;
  1079. X        }
  1080. X        fcp++;
  1081. X    }
  1082. X}
  1083. X
  1084. X/*
  1085. X *  Once the first fat is updated the other copies of
  1086. X *  the fat must also be updated.  This function does
  1087. X *  this.
  1088. X *  pmp - pcfsmount structure for filesystem to update
  1089. X *  bp0 - addr of modified fat block
  1090. X *  bp1 - addr of 2nd modified fat block (0 if not needed)
  1091. X *  fatbn - block number relative to begin of filesystem
  1092. X *    of the modified fat block.
  1093. X */
  1094. Xvoid
  1095. Xupdateotherfats(pmp, bp0, bp1, fatbn)
  1096. X    struct pcfsmount *pmp;
  1097. X    struct buf *bp0;
  1098. X    struct buf *bp1;
  1099. X    u_long fatbn;
  1100. X{
  1101. X    int i;
  1102. X    struct buf *bpn0;
  1103. X    struct buf *bpn1;
  1104. X
  1105. X#if defined(PCFSDEBUG)
  1106. Xprintf("updateotherfats(pmp %08x, bp0 %08x, bp1 %08x, fatbn %d)\n",
  1107. X    pmp, bp0, bp1, fatbn);
  1108. X#endif /* defined(PCFSDEBUG) */
  1109. X
  1110. X/*
  1111. X *  Now copy the block(s) of the modified fat to the other
  1112. X *  copies of the fat and write them out.  This is faster
  1113. X *  than reading in the other fats and then writing them
  1114. X *  back out.  This could tie up the fat for quite a while.
  1115. X *  Preventing others from accessing it.  To prevent us
  1116. X *  from going after the fat quite so much we use delayed
  1117. X *  writes, unless they specfied "synchronous" when the
  1118. X *  filesystem was mounted.  If synch is asked for then
  1119. X *  use bwrite()'s and really slow things down.
  1120. X */
  1121. X    for (i = 1; i < pmp->pm_FATs; i++) {
  1122. X        fatbn += pmp->pm_FATsecs;
  1123. X        /* getblk() never fails */
  1124. X        bpn0 = getblk(pmp->pm_devvp, fatbn, pmp->pm_BytesPerSec);
  1125. X        bcopy(bp0->b_un.b_addr, bpn0->b_un.b_addr,
  1126. X            pmp->pm_BytesPerSec);
  1127. X        if (pmp->pm_waitonfat)
  1128. X            bwrite(bpn0);
  1129. X        else
  1130. X            bdwrite(bpn0);
  1131. X        if (bp1) {
  1132. X            /* getblk() never fails */
  1133. X            bpn1 = getblk(pmp->pm_devvp, fatbn+1,
  1134. X                pmp->pm_BytesPerSec);
  1135. X            bcopy(bp1->b_un.b_addr, bpn1->b_un.b_addr,
  1136. X                pmp->pm_BytesPerSec);
  1137. X            if (pmp->pm_waitonfat)
  1138. X                bwrite(bpn1);
  1139. X            else
  1140. X                bdwrite(bpn1);
  1141. X        }
  1142. X    }
  1143. X}
  1144. X
  1145. X/*
  1146. X *  Updating entries in 12 bit fats is a pain in the butt.
  1147. X *  So, we have a function to hide this ugliness.
  1148. X *
  1149. X *  The following picture shows where nibbles go when
  1150. X *  moving from a 12 bit cluster number into the appropriate
  1151. X *  bytes in the FAT.
  1152. X *
  1153. X *      byte m        byte m+1      byte m+2
  1154. X *    +----+----+   +----+----+   +----+----+
  1155. X *    |  0    1 |   |  2    3 |   |  4    5 |   FAT bytes
  1156. X *    +----+----+   +----+----+   +----+----+
  1157. X *
  1158. X *       +----+----+----+ +----+----+----+
  1159. X *       |  3    0    1 | |  4    5    2 |
  1160. X *       +----+----+----+ +----+----+----+
  1161. X *         cluster n        cluster n+1
  1162. X *
  1163. X *    Where n is even.
  1164. X *    m = n + (n >> 2)
  1165. X *
  1166. X *  This function is written for little endian machines.
  1167. X *  least significant byte stored into lowest address.
  1168. X */
  1169. Xvoid
  1170. Xsetfat12slot(bp0, bp1, oddcluster, byteoffset, newvalue)
  1171. X    struct buf *bp0;
  1172. X    struct buf *bp1;
  1173. X    int oddcluster;
  1174. X    u_int byteoffset;
  1175. X    u_short newvalue;
  1176. X{
  1177. X    unsigned char *b0;
  1178. X    unsigned char *b1;
  1179. X    union fattwiddle x;
  1180. X
  1181. X/*
  1182. X *  If we have a 2nd buf header and the byte offset is not the
  1183. X *  last byte in the buffer, then something is fishy.  Better
  1184. X *  tell someone.
  1185. X */
  1186. X    if (bp1  &&  byteoffset != 511)
  1187. X        printf("setfat12slot(): bp1 %08x, byteoffset %d shouldn't happen\n",
  1188. X            bp1, byteoffset);
  1189. X
  1190. X/*
  1191. X *  Get address of 1st byte and 2nd byte setup
  1192. X *  so we don't worry about which buf header to
  1193. X *  be poking around in.
  1194. X */
  1195. X    b0 = (unsigned char *)&bp0->b_un.b_addr[byteoffset];
  1196. X    if (bp1)
  1197. X        b1 = (unsigned char *)&bp1->b_un.b_addr[0];
  1198. X    else
  1199. X        b1 = b0 + 1;
  1200. X
  1201. X/*printf("setfat12(): offset %d, old %02x%02x, new %04x\n", byteoffset, *b0, *b1, newvalue); */
  1202. X
  1203. X    if (oddcluster) {
  1204. X        x.word = newvalue << 4;
  1205. X        *b0 = (*b0 & 0x0f) | x.byte[0];
  1206. X        *b1 = x.byte[1];
  1207. X    } else {
  1208. X        x.word = newvalue & 0x0fff;
  1209. X        *b0 = x.byte[0];
  1210. X        *b1 = (*b1 & 0xf0) | x.byte[1];
  1211. X    }
  1212. X/*printf("setfat12(): result %02x%02x\n", *b0, *b1); */
  1213. X}
  1214. X
  1215. Xint
  1216. Xclusterfree(pmp, cluster)
  1217. X    struct pcfsmount *pmp;
  1218. X    unsigned long cluster;
  1219. X{
  1220. X    int error;
  1221. X
  1222. X    error = fatentry(FAT_SET, pmp, cluster, 0, PCFSFREE);
  1223. X    if (error == 0) {
  1224. X/*
  1225. X *  If the cluster was successfully marked free, then update the count of
  1226. X *  free clusters, and turn off the "allocated" bit in the
  1227. X *  "in use" cluster bit map.
  1228. X */
  1229. X        pmp->pm_freeclustercount++;
  1230. X        pmp->pm_inusemap[cluster >> 3] &= ~(1 << (cluster & 0x07));
  1231. X    }
  1232. X    return error;
  1233. X}
  1234. X
  1235. X/*
  1236. X *  Get or Set or 'Get and Set' the cluster'th entry in the
  1237. X *  fat.
  1238. X *  function - whether to get or set a fat entry
  1239. X *  pmp - address of the pcfsmount structure for the
  1240. X *    filesystem whose fat is to be manipulated.
  1241. X *  cluster - which cluster is of interest
  1242. X *  oldcontents - address of a word that is to receive
  1243. X *    the contents of the cluster'th entry if this is
  1244. X *    a get function
  1245. X *  newcontents - the new value to be written into the
  1246. X *    cluster'th element of the fat if this is a set
  1247. X *    function.
  1248. X *
  1249. X *  This function can also be used to free a cluster
  1250. X *  by setting the fat entry for a cluster to 0.
  1251. X *
  1252. X *  All copies of the fat are updated if this is a set
  1253. X *  function.
  1254. X *  NOTE:
  1255. X *    If fatentry() marks a cluster as free it does not
  1256. X *    update the inusemap in the pcfsmount structure.
  1257. X *    This is left to the caller.
  1258. X */
  1259. Xint
  1260. Xfatentry(function, pmp, cluster, oldcontents, newcontents)
  1261. X    int function;
  1262. X    struct pcfsmount *pmp;
  1263. X    u_long cluster;
  1264. X    u_long *oldcontents;
  1265. X    u_long newcontents;
  1266. X{
  1267. X    int error;
  1268. X    u_long whichbyte;
  1269. X    u_long whichblk;
  1270. X    struct buf *bp0 = 0;
  1271. X    struct buf *bp1 = 0;
  1272. X    union fattwiddle x;
  1273. X/*printf("fatentry(func %d, pmp %08x, clust %d, oldcon %08x, newcon %d)\n",
  1274. X    function, pmp, cluster, oldcontents, newcontents);*/
  1275. X
  1276. X/*
  1277. X *  Be sure they asked us to do something.
  1278. X */
  1279. X    if ((function & (FAT_SET | FAT_GET)) == 0) {
  1280. X        printf("fatentry(): function code doesn't specify get or set\n");
  1281. X        return EINVAL;
  1282. X    }
  1283. X
  1284. X/*
  1285. X *  If they asked us to return a cluster number
  1286. X *  but didn't tell us where to put it, give them
  1287. X *  an error.
  1288. X */
  1289. X    if ((function & FAT_GET)  &&  oldcontents == NULL) {
  1290. X        printf("fatentry(): get function with no place to put result\n");
  1291. X        return EINVAL;
  1292. X    }
  1293. X
  1294. X/*
  1295. X *  Be sure the requested cluster is in the filesystem.
  1296. X */
  1297. X    if (cluster < CLUST_FIRST || cluster > pmp->pm_maxcluster)
  1298. X        return EINVAL;
  1299. X
  1300. X    if (FAT12(pmp)) {
  1301. X        whichbyte = cluster + (cluster >> 1);
  1302. X        whichblk  = (whichbyte >> pmp->pm_bnshift) + pmp->pm_fatblk;
  1303. X        whichbyte &= pmp->pm_brbomask;
  1304. X/*
  1305. X *  Read in the fat block containing the entry of interest.
  1306. X *  If the entry spans 2 blocks, read both blocks.
  1307. X */
  1308. X        error = bread(pmp->pm_devvp, whichblk,
  1309. X            pmp->pm_BytesPerSec, NOCRED, &bp0);
  1310. X        if (error) {
  1311. X            brelse(bp0);
  1312. X            return error;
  1313. X        }
  1314. X        if (whichbyte == (pmp->pm_BytesPerSec-1)) {
  1315. X            error = bread(pmp->pm_devvp, whichblk+1,
  1316. X                pmp->pm_BytesPerSec, NOCRED, &bp1);
  1317. X            if (error) {
  1318. X                brelse(bp0);
  1319. X                return error;
  1320. X            }
  1321. X        }
  1322. X        if (function & FAT_GET) {
  1323. X            x.byte[0] = bp0->b_un.b_addr[whichbyte];
  1324. X            x.byte[1] = bp1 ? bp1->b_un.b_addr[0] :
  1325. X                      bp0->b_un.b_addr[whichbyte+1];
  1326. X            if (cluster & 1)
  1327. X                x.word >>= 4;
  1328. X            x.word &= 0x0fff;
  1329. X            /* map certain 12 bit fat entries to 16 bit */
  1330. X            if ((x.word & 0x0ff0) == 0x0ff0)
  1331. X                x.word |= 0xf000;
  1332. X            *oldcontents = x.word;
  1333. X        }
  1334. X        if (function & FAT_SET) {
  1335. X            setfat12slot(bp0, bp1, cluster & 1, whichbyte,
  1336. X                newcontents);
  1337. X            updateotherfats(pmp, bp0, bp1, whichblk);
  1338. X
  1339. X/*
  1340. X *  Write out the first fat last.
  1341. X */
  1342. X            if (pmp->pm_waitonfat)
  1343. X                bwrite(bp0);
  1344. X            else
  1345. X                bdwrite(bp0);
  1346. X            bp0 = NULL;
  1347. X            if (bp1) {
  1348. X                if (pmp->pm_waitonfat)
  1349. X                    bwrite(bp1);
  1350. X                else
  1351. X                    bdwrite(bp1);
  1352. X                bp1 = NULL;
  1353. X            }
  1354. X            pmp->pm_fmod++;
  1355. X        }
  1356. X    } else {    /* fat16 */
  1357. X        whichbyte = cluster << 1;
  1358. X        whichblk  = (whichbyte >> pmp->pm_bnshift) + pmp->pm_fatblk;
  1359. X        whichbyte &= pmp->pm_brbomask;
  1360. X        error = bread(pmp->pm_devvp, whichblk,
  1361. X            pmp->pm_BytesPerSec, NOCRED, &bp0);
  1362. X        if (error) {
  1363. X            brelse(bp0);
  1364. X            return error;
  1365. X        }
  1366. X        if (function & FAT_GET) {
  1367. X            *oldcontents = *((u_short *)(bp0->b_un.b_addr +
  1368. X                whichbyte));
  1369. X        }
  1370. X        if (function & FAT_SET) {
  1371. X            *(u_short *)(bp0->b_un.b_addr+whichbyte) = newcontents;
  1372. X            updateotherfats(pmp, bp0, 0, whichblk);
  1373. X            if (pmp->pm_waitonfat)
  1374. X                bwrite(bp0);    /* write out blk from the 1st fat */
  1375. X            else
  1376. X                bdwrite(bp0);
  1377. X            bp0 = NULL;
  1378. X            pmp->pm_fmod++;
  1379. X        }
  1380. X    }
  1381. X    if (bp0)
  1382. X        brelse(bp0);
  1383. X    if (bp1)
  1384. X        brelse(bp1);
  1385. X    return 0;
  1386. X}
  1387. X
  1388. X/*
  1389. X *  Allocate a free cluster.
  1390. X *  pmp - 
  1391. X *  retcluster - put the allocated cluster's number here.
  1392. X *  fillwith - put this value into the fat entry for the
  1393. X *     allocated cluster.
  1394. X */
  1395. Xint
  1396. Xclusteralloc(pmp, retcluster, fillwith)
  1397. X    struct pcfsmount *pmp;
  1398. X    unsigned long *retcluster;
  1399. X    unsigned long fillwith;
  1400. X{
  1401. X    int error;
  1402. X    u_long cn;
  1403. X    u_long end_cn;
  1404. X
  1405. X    /* This for loop really needs to start from 0. */
  1406. X    for (cn = 0; cn <= pmp->pm_maxcluster; cn += 8) {
  1407. X        if (pmp->pm_inusemap[cn >> 3] != 0xff) {
  1408. X            end_cn = cn | 0x07;
  1409. X            for (;cn <= end_cn; cn++) {
  1410. X                if ((pmp->pm_inusemap[cn >> 3] & (1 << (cn & 0x07))) == 0)
  1411. X                    goto found_one;
  1412. X            }
  1413. X            printf("clusteralloc(): this shouldn't happen\n");
  1414. X        }
  1415. X    }
  1416. X    return ENOSPC;
  1417. X
  1418. Xfound_one:;
  1419. X    error = fatentry(FAT_SET, pmp, cn, 0, fillwith);
  1420. X    if (error == 0) {
  1421. X        pmp->pm_inusemap[cn >> 3] |= 1 << (cn & 0x07);
  1422. X        pmp->pm_freeclustercount--;
  1423. X        pmp->pm_fmod++;
  1424. X        *retcluster = cn;
  1425. X    }
  1426. X#if defined(PCFSDEBUG)
  1427. Xprintf("clusteralloc(): allocated cluster %d\n", cn);
  1428. X#endif /* defined(PCFSDEBUG) */
  1429. X    return error;
  1430. X}
  1431. X
  1432. X/*
  1433. X *  Free a chain of clusters.
  1434. X *  pmp - address of the pcfs mount structure for the
  1435. X *    filesystem containing the cluster chain to be freed.
  1436. X *  startcluster - number of the 1st cluster in the chain
  1437. X *    of clusters to be freed.
  1438. X */
  1439. Xint
  1440. Xfreeclusterchain(pmp, startcluster)
  1441. X    struct pcfsmount *pmp;
  1442. X    unsigned long startcluster;
  1443. X{
  1444. X    unsigned long nextcluster;
  1445. X    int error = 0;
  1446. X
  1447. X    while (startcluster >= CLUST_FIRST  &&  startcluster <= pmp->pm_maxcluster) {
  1448. X        error = fatentry(FAT_GET_AND_SET, pmp, startcluster,
  1449. X            &nextcluster, PCFSFREE);
  1450. X        if (error) {
  1451. X            printf("freeclusterchain(): free failed, cluster %d\n",
  1452. X                startcluster);
  1453. X            break;
  1454. X        }
  1455. X/*
  1456. X *  If the cluster was successfully marked free, then update the count of
  1457. X *  free clusters, and turn off the "allocated" bit in the
  1458. X *  "in use" cluster bit map.
  1459. X */
  1460. X        pmp->pm_freeclustercount++;
  1461. X        pmp->pm_inusemap[startcluster >> 3] &=
  1462. X            ~(1 << (startcluster & 0x07));
  1463. X        startcluster = nextcluster;
  1464. X        pmp->pm_fmod++;
  1465. X    }
  1466. X    return error;
  1467. X}
  1468. X
  1469. X/*
  1470. X *  Read in fat blocks looking for free clusters.
  1471. X *  For every free cluster found turn off its
  1472. X *  corresponding bit in the pm_inusemap.
  1473. X */
  1474. Xint
  1475. Xfillinusemap(pmp)
  1476. X    struct pcfsmount *pmp;
  1477. X{
  1478. X    struct buf *bp0 = 0;
  1479. X    daddr_t bp0_blk = -1;
  1480. X    struct buf *bp1 = 0;
  1481. X    daddr_t cn;
  1482. X    daddr_t whichblk;
  1483. X    int whichbyte;
  1484. X    int error;
  1485. X    union fattwiddle x;
  1486. X
  1487. X/*
  1488. X *  Mark all clusters in use, we mark the free ones in the
  1489. X *  fat scan loop further down.
  1490. X */
  1491. X    for (cn = 0; cn < (pmp->pm_maxcluster >> 3) + 1; cn++)
  1492. X        pmp->pm_inusemap[cn] = 0xff;
  1493. X
  1494. X/*
  1495. X *  Figure how many free clusters are in the filesystem
  1496. X *  by ripping thougth the fat counting the number of
  1497. X *  entries whose content is zero.  These represent free
  1498. X *  clusters.
  1499. X */
  1500. X    pmp->pm_freeclustercount = 0;
  1501. X    pmp->pm_lookhere = -1;
  1502. X    for (cn = CLUST_FIRST; cn <= pmp->pm_maxcluster; cn++) {
  1503. X        if (FAT12(pmp)) {
  1504. X            whichbyte = cn + (cn >> 1);
  1505. X            whichblk  = (whichbyte >> pmp->pm_bnshift) + pmp->pm_fatblk;
  1506. X            whichbyte = whichbyte & pmp->pm_brbomask;
  1507. X            if (whichblk != bp0_blk) {
  1508. X                if (bp0)
  1509. X                    brelse(bp0);
  1510. X                error = bread(pmp->pm_devvp, whichblk,
  1511. X                    pmp->pm_BytesPerSec, NOCRED, &bp0);
  1512. X                if (error) {
  1513. X                    goto error_exit;
  1514. X                }
  1515. X                bp0_blk = whichblk;
  1516. X            }
  1517. X            x.byte[0] = bp0->b_un.b_addr[whichbyte];
  1518. X            if (whichbyte == (pmp->pm_BytesPerSec-1)) {
  1519. X                error = bread(pmp->pm_devvp, whichblk+1,
  1520. X                    pmp->pm_BytesPerSec, NOCRED, &bp1);
  1521. X                if (error)
  1522. X                    goto error_exit;
  1523. X                x.byte[1] = bp1->b_un.b_addr[0];
  1524. X                brelse(bp0);
  1525. X                bp0 = bp1;
  1526. X                bp1 = NULL;
  1527. X                bp0_blk++;
  1528. X            } else {
  1529. X                x.byte[1] = bp0->b_un.b_addr[whichbyte + 1];
  1530. X            }
  1531. X            if (cn & 1)
  1532. X                x.word >>= 4;
  1533. X            x.word &= 0x0fff;
  1534. X        } else {    /* 16 bit fat    */
  1535. X            whichbyte = cn << 1;
  1536. X            whichblk  = (whichbyte >> pmp->pm_bnshift) + pmp->pm_fatblk;
  1537. X            whichbyte = whichbyte & pmp->pm_brbomask;
  1538. X            if (whichblk != bp0_blk) {
  1539. X                if (bp0)
  1540. X                    brelse(bp0);
  1541. X                error = bread(pmp->pm_devvp, whichblk,
  1542. X                    pmp->pm_BytesPerSec, NOCRED, &bp0);
  1543. X                if (error)
  1544. X                    goto error_exit;
  1545. X                bp0_blk = whichblk;
  1546. X            }
  1547. X            x.byte[0] = bp0->b_un.b_addr[whichbyte];
  1548. X            x.byte[1] = bp0->b_un.b_addr[whichbyte+1];
  1549. X        }
  1550. X        if (x.word == 0) {
  1551. X            pmp->pm_freeclustercount++;
  1552. X            pmp->pm_inusemap[cn >> 3] &= ~(1 << (cn & 0x07));
  1553. X            if (pmp->pm_lookhere < 0)
  1554. X                pmp->pm_lookhere = cn;
  1555. X        }
  1556. X    }
  1557. X    brelse(bp0);
  1558. X    return 0;
  1559. X
  1560. Xerror_exit:;
  1561. X    if (bp0)
  1562. X        brelse(bp0);
  1563. X    if (bp1)
  1564. X        brelse(bp1);
  1565. X    return error;
  1566. X}
  1567. X
  1568. X/*
  1569. X *  Allocate a new cluster and chain it onto the end of the
  1570. X *  file.
  1571. X *  dep - the file to extend
  1572. X *  bpp - where to return the address of the buf header for the
  1573. X *        new file block
  1574. X *  ncp - where to put cluster number of the newly allocated file block
  1575. X *        If this pointer is 0, do not return the cluster number.
  1576. X *
  1577. X *  NOTE:
  1578. X *   This function is not responsible for turning on the DEUPD
  1579. X *   bit if the de_flag field of the denode and it does not
  1580. X *   change the de_FileSize field.  This is left for the caller
  1581. X *   to do.
  1582. X */
  1583. Xint
  1584. Xextendfile(dep, bpp, ncp)
  1585. X    struct denode *dep;
  1586. X    struct buf **bpp;
  1587. X    unsigned int *ncp;
  1588. X{
  1589. X    int error = 0;
  1590. X    unsigned long frcn;
  1591. X    unsigned long cn;
  1592. X    struct pcfsmount *pmp = dep->de_pmp;
  1593. X
  1594. X/*
  1595. X *  Don't try to extend the root directory
  1596. X */
  1597. X    if (DETOV(dep)->v_flag & VROOT) {
  1598. X        printf("extendfile(): attempt to extend root directory\n");
  1599. X        return ENOSPC;
  1600. X    }
  1601. X
  1602. X/*
  1603. X *  If the "file's last cluster" cache entry is empty,
  1604. X *  and the file is not empty,
  1605. X *  then fill the cache entry by calling pcbmap().
  1606. X */
  1607. X    fc_fileextends++;
  1608. X    if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY  &&
  1609. X        dep->de_StartCluster != 0) {
  1610. X        fc_lfcempty++;
  1611. X        error = pcbmap(dep, 0xffff, 0, &cn);
  1612. X        /* we expect it to return E2BIG */
  1613. X        if (error != E2BIG)
  1614. X            return error;
  1615. X        error = 0;
  1616. X    }
  1617. X
  1618. X/*
  1619. X *  Allocate another cluster and chain onto the end of the file.
  1620. X *  If the file is empty we make de_StartCluster point to the
  1621. X *  new block.  Note that de_StartCluster being 0 is sufficient
  1622. X *  to be sure the file is empty since we exclude attempts to
  1623. X *  extend the root directory above, and the root dir is the
  1624. X *  only file with a startcluster of 0 that has blocks allocated
  1625. X *  (sort of).
  1626. X */
  1627. X    if (error = clusteralloc(pmp, &cn, CLUST_EOFE))
  1628. X        return error;
  1629. X    if (dep->de_StartCluster == 0) {
  1630. X        dep->de_StartCluster = cn;
  1631. X        frcn = 0;
  1632. X    } else {
  1633. X        error = fatentry(FAT_SET, pmp, dep->de_fc[FC_LASTFC].fc_fsrcn,
  1634. X            0, cn);
  1635. X        if (error) {
  1636. X            clusterfree(pmp, cn);
  1637. X            return error;
  1638. X        }
  1639. X
  1640. X        frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1;
  1641. X    }
  1642. X
  1643. X/*
  1644. X *  Update the "last cluster of the file" entry in the denode's
  1645. X *  fat cache.
  1646. X */
  1647. X    fc_setcache(dep, FC_LASTFC, frcn, cn);
  1648. X
  1649. X/*
  1650. X *  Get the buf header for the new block of the file.
  1651. X */
  1652. X    if (dep->de_Attributes & ATTR_DIRECTORY) {
  1653. X        *bpp = getblk(pmp->pm_devvp, cntobn(pmp, cn),
  1654. X            pmp->pm_bpcluster);
  1655. X    } else {
  1656. X        *bpp = getblk(DETOV(dep), frcn,
  1657. X            pmp->pm_bpcluster);
  1658. X    }
  1659. X    clrbuf(*bpp);
  1660. X
  1661. X/*
  1662. X *  Give them the filesystem relative cluster number
  1663. X *  if they want it.
  1664. X */
  1665. X    if (ncp)
  1666. X        *ncp = cn;
  1667. X    return 0;
  1668. X}
  1669. END-of-/sys/pcfs/pcfs_fat.c
  1670. exit
  1671.  
  1672.