dosFsLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:173k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* dosFsLib.c - MS-DOS media-compatible file system library */ 
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02q,02may02,jkf  Corrects SPR#76501, 72603. Avoids 65085 and 33221.
  8.                  and a performance improvement for FIOSYNC.
  9. 02p,30apr02,jkf  SPR#62786, rename should preserve time and date fields
  10. 02o,30apr02,jkf  SPR#76510, dosFsVolDescGet() should return NULL instead of
  11.                  the default device when the underlying iosDevFind() does. 
  12. 02n,15Jan02,chn  SPR#29751, removed path case sensitivity during creat phase 
  13.                  of rename. Possible NFS interaction, see comments at change.
  14. 02m,18dec01,chn  SPR#71105, correct file size in dosFsContigAlloc & comment
  15. 02l,12dec01,jkf  SPR#72133, add FIOMOVE and fixing diab build warnings.
  16. 02k,10dec01,jkf  SPR#24332, dont delete existing files or dirs in dosFsRename
  17. 02j,10dec01,jkf  SPR#72039, various fixes from Mr. T. Johnson.
  18. 02i,09dec01,jkf  SPR#71637, fix for SPR#68387 caused ready changed bugs.
  19. 02h,30nov01,jkf  SPR#68203, updating last access date on open-read-close
  20.                  operation causes unwanted writes, increasing flash wear.
  21. 02g,30nov01,jkf  SPR#33343, media unformatted or missing err better reported.
  22.                  SPR#69074, statfs to invalid media caused continuous errors.
  23. 02f,15nov01,jkf  SPR#71720, avoid unaligned pointer access.
  24.                  clean up multiple errno's when mounting unformatted volume.
  25. 02e,13nov01,jkf  correct typo in checkin comment.
  26. 02d,13nov01,jkf  improve dosFsBootSecGet() error message, add a comment about 
  27.                  nBlocks reporting total blocks, not last addressable block.
  28. 02c,10nov01,jkf  SPR#67890, chkdsk writes to RDONLY device
  29. 02b,09nov01,jkf  SPR#71633, dont set errno when DevCreate is called w/BLK_DEV
  30.                  SPR#32178, made dosFsVolDescGet public, cleaned up man page. 
  31.                  SPR#33684, dosFsShow reporting incorrect verbosity setting.
  32. 02a,23oct01,rip  SPR#65085: tasks in FIOSYNC interlocking (dup of #33221 cf 01v)
  33.                  SPR#30464: FIONCONTIG64 not shifting using 64bit math
  34.                  SPR#30540: FillGap assumes step over sector on FIOSEEK > EOF
  35. 01z,21aug01,jkf  SPR#69031, common code for both AE & 5.x.
  36. 01y,26jul01,jkf  T2 SPR#65009, T3 SPR#65271.  dosFsLibInit returns OK or ERROR.
  37. 01x,14mar01,jkf  SPR#34704,FAT12/FAT16 determination, SPR#62415 sig location.
  38. 01w,19sep00,csh  Manual Merge From Alameda Branch To Sunnyvale Branch
  39. 01v,08sep00,nrj  fixed SPR#33221, to avoid dead-lock because of multiple tasks
  40.  doing FIOSYNC on opened files
  41.  fixed SPR#33702, 33684, The autocheck verbosity is now 
  42.  initialized properly in volume descriptor.
  43. 01u,29feb00,jkf  cleaning warning.
  44. 01t,29feb00,jkf  T3 changes.
  45. 01s,28sep99,jkf  fixed SPR#28554, now return error on write to full disk.
  46. 01r,31aug99,jkf  changes for new CBIO API.  Changed FIOTIMESET to allow
  47.                  utime to follow Solaris 2.6 behavior.  If arg is NULL, 
  48.                  the current time is used, added docs. SPR#28924
  49. 01q,06aug99,jkf  delete existing file when dosFsOpen uses O_CREAT/O_TRUNC
  50.                  do not overflow read buffer on truncated files, SPR#28309
  51. 01p,31jul99,jkf  Dont allow larger than 4GB file on anything but
  52.                  VXLONGNAMES directory entry files. SPR#27532.
  53. 01o,31jul99,jkf  Added support for FSTYPE (0x36) in bootsec, SPR#28273
  54. 01n,31jul99,jkf  T2 merge, tidiness & spelling.
  55. 01m,03dec98,vld  fixed SPR #23692: added FIOTRUNC64 ioctl code;
  56.                  rd/wr time measurement excluded
  57. 01l,22nov98,vld  included  features required by NFS protocol:
  58.  - added support for FIOFSTATFSGET ioctl code;
  59.  - added support for creating files "with holes";
  60.  - added dosFsSeekDir() routine and controlling
  61.    of dd_cookie field within FIOREADDIR
  62. 01k,28sep98,vld  gnu extensions dropped from DBG_MSG/ERR_MSG macros
  63. 01j,24sep98,vld  added support for FIOTIMESET ioctl code
  64. 01i,16sep98,vld  created separate routine dosFsChkDsk() to solve
  65. hen-and-egg problem during volume mounting and
  66.                  external call for disk check operation.
  67. 01h,16sep98,vld  added support for read only devices
  68. 01j,11sep98,vld  added support for non CBIO ptr argument in dosFsDevCreate().
  69. 01i,26aug98,vld  ignore mode = S_IFDIR except with O_CREAT (SPR#22227)
  70. 01h,30jul98,wlf  partial doc cleanup
  71. 01g,27jul98,vld  fixed FIOWHERE64  return
  72. 01f,08jul98,vld  print64Lib.h moved to h/private directory. 
  73. 01e,08jul98,vld  dosFsContigAlloc() (FIOCONTIG effected) changed
  74.                  not to zero allocated data and leave file size as 0
  75. 01d,08jul98,vld  fixed bug in dosFsContigAlloc() 
  76.                  added counting sectors per file count for CONTIG_MAX case.
  77. 01c,30jun98,lrn  renamed dosFsInit to dosFsLibInit
  78. 01b,28jun98,vld  tested, checked in, ready for EAR
  79. 01a,18jan98,vld  written, preliminary
  80. */
  81. /*
  82. INTERNAL: MS-DOS is a registered trademark of Microsoft Corporation.
  83. DESCRIPTION
  84. This library implements the MS-DOS compatible file system.
  85. This is a multi-module library, which depends on sub-modules to
  86. perform certain parts of the file system functionality.
  87. A number of different file system format variations are supported.
  88. USING THIS LIBRARY
  89. The various routines provided by the VxWorks DOS file system (dosFs) may be
  90. separated into three broad groups: general initialization, device
  91. initialization, and file system operation.
  92. The dosFsLibInit() routine is the principal initialization function; it should
  93. be called once during system initialization, regardless of how many dosFs
  94. devices are to be used.
  95. Another dosFs routine is used for device initialization. 
  96. For each dosFs device, dosFsDevCreate() must be called to install the
  97. device in VxWorks device list.
  98. In the case where partitioned disks are used, dosFsDevCreate() must be
  99. called for each partition that is anticipated, thereby it is associated
  100. with a logical device name, so it can be later accessed via the I/O
  101. system.
  102. In case of a removable disk, dosFsDevCreate() must be called during
  103. system initialization time, even if a cartridge or diskette may be
  104. absent from the drive at boot time. dosFsDevCreate() will only
  105. associate the device with a logical device name. Device access will be
  106. done only when the logical device is first accessed by the application.
  107. More detailed information on all of these routines is provided below.
  108. INITIALIZING DOSFSLIB
  109. To enable this file system in a particular VxWorks configuration,
  110. a library initialization routine must be called for each sub-module of
  111. the file system, as well as for the underlying disk cache, partition
  112. manager and drivers.
  113. This is usually done at system initialization time, within the 
  114. .I usrRoot
  115. task context.
  116. Following is the list of initialization routines that need to be
  117. called:
  118. .IP dosFsLibInit
  119. (mandatory) initialize the principle dosFs module. Must be called first.
  120. .IP dosFsFatInit
  121. (mandatory) initialize the File Allocation Table handler, which supports
  122. 12-bit, 16-bit and 32-bit FATs.
  123. .IP dosVDirLibInit
  124. (choice) install the variable size directory handler
  125. supporting Windows-compatible Long File Names (VFAT) Directory
  126. Handler.
  127. .IP dosDirOldLibInit
  128. (choice) install the fixed size  directory handler
  129. which supports old-fashioned 8.3
  130. MS-DOS file names, and Wind River Systems proprietary long file names
  131. (VXLONG).
  132. .IP dosFsFmtLibInit
  133. (optional) install the volume formatting module.
  134. .IP dosChkLibInit
  135. (optional) install the file system consistency checking module.
  136. .LP
  137. The two Directory handlers which are marked
  138. .I choice
  139. are installed in accordance with the system requirements, either one
  140. of these modules could be installed or both, in which case the VFAT will
  141. take precedence for MS-DOS compatible volumes.
  142. Also, at least one
  143. .I CBIO
  144. module must be initialized on a per-device basis prior to calling
  145. dosFsDevCreate().
  146. See the related documentation for more details and examples.
  147. DEFINING A DOSFS DEVICE
  148. The dosFsDevCreate() routine associates a device with the dosFsLib
  149. functions.  It expects three parameters:
  150. .IP "(1)" 4
  151. A pointer to a name string, to be used to identify the device - logical
  152. device name.
  153. This will be part of the pathname for I/O operations which operate on the
  154. device.  This name will appear in the I/O system device table, which may be
  155. displayed using the iosDevShow() routine.
  156. .IP "(2)"
  157. CBIO_DEV_ID - a pointer to the CBIO_DEV structure which provides interface
  158. to particular disk, via a disk cache, or a partition manager or a
  159. combination of a number of
  160. .I CBIO
  161. modules which are stacked on top of each other to form one of many
  162. configurations possible.
  163. .IP "(3)"
  164. A maximum number of files can be simultaneously opened on a particular device.
  165. .IP "(4)"
  166. Because volume integrity check utility can be automatically
  167. invoked every time a device is mounted,
  168. this parameter indicates whether the consistency check needs to be
  169. performed automatically on a given device, and on what level of
  170. verbosity is required.
  171. In any event, the consistency check may be invoked at a later time
  172. e.g. by calling chkdsk().
  173. See description for FIOCHKDSK ioctl command for more information.
  174. .LP
  175. For example:
  176. .CS
  177.     dosFsDevCreate
  178. (
  179. "/sd0", /@ name to be used for volume   @/
  180. pCbio, /@ pointer to device descriptor @/
  181. 10, /@ max no. of simultaneously open files @/
  182. DOS_CHK_REPAIR | DOS_CHK_VERB_1
  183. /@ check volume during mounting and repair @/
  184. /@ errors, and display volume statistics @/
  185. )
  186. .CE
  187. Once dosFsDevCreate() has been called, the device can be accessed
  188. using 
  189. .I ioLib
  190. generic I/O routines: open(), read(), write(), close(),
  191. ioctl(), remove(). Also, the user-level utility functions may be used to
  192. access the device at a higher level (See usrFsLib reference page for
  193. more details).
  194. DEVICE AND PATH NAMES
  195. On true MS-DOS machines, disk device names are typically of the form "A:",
  196. that is, a single letter designator followed by a colon.  Such names may be
  197. used with the VxWorks dosFs file system.  However, it is possible (and
  198. desirable) to use longer, more mnemonic device names, such as "DOS1:",
  199. or "/floppy0". 
  200. The name is specified during the dosFsDevCreate() call.
  201. The pathnames used to specify dosFs files and directories may use either
  202. forward slashes ("/") or backslashes ("e") as separators.  These may be
  203. freely mixed.  The choice of forward slashes or backslashes has absolutely
  204. no effect on the directory data written to the disk.  (Note, however, that
  205. forward slashes are not allowed within VxWorks dosFs filenames, although
  206. they are normally legal for pure MS-DOS implementations.)
  207. For the sake of consistency however use of forward slashes ("/") is
  208. recommended at all times.
  209. The leading slash of a dosFs pathname following the device name is
  210. optional.  For example, both "DOS1:newfile.new" and "DOS1:/newfile.new"
  211. refer to the same file.
  212. USING EXTENDED DIRECTORY STRUCTURE
  213. This library supports DOS4.0 standard file names which fit the restrictions
  214. of eight upper-case characters optionally followed by a three-character
  215. extension,
  216. as well as Windows style VFAT standard long file names
  217. that are stored mixed cased on disk, but are case insensitive when
  218. searched and matched (e.g. during open() call).
  219. The VFAT long file name is stored in a variable number of consecutive
  220. directory entries.
  221. Both standards restrict file size to 4 GB (32 bit value).
  222. To provide additional flexibility, this implementation of the
  223. DOS file system provides proprietary ling file name format (VXLONGNAMES),
  224. which uses a simpler directory structure: the directory entry is
  225. of fixed size.  When this option is
  226. used, file names may consist of any sequence of up to 40 ASCII
  227. characters.  No case conversion is performed, 
  228. and file name match is case-sensitive.
  229. With this directory format the
  230. file maximum size is expanded to 1 Terabyte (40 bit value).
  231. .RS 4 4
  232. NOTE:  Because special directory entries are used on the disk, disks 
  233. which use the extended names are 
  234. .I not
  235. compatible with other implementation of the
  236. MS-DOS systems, and cannot be read on MS-DOS or Windows machines.
  237. .RE
  238. To enable the extended file names, set the DOS_OPT_VXLONGNAMES flag 
  239. when calling dosFsVolFormat().
  240. READING DIRECTORY ENTRIES
  241. Directories on VxWorks dosFs volumes may be searched using the opendir(),
  242. readdir(), rewinddir(), and closedir() routines.  These calls allow the
  243. names of files and subdirectories to be determined.
  244. To obtain more detailed information about a specific file, use the fstat()
  245. or stat() routine.  Along with standard file information, the structure
  246. used by these routines also returns the file attribute byte from a dosFs
  247. directory entry.
  248. For more information, see the manual entry for dirLib.
  249. FILE DATE AND TIME
  250. Directory entries on dosFs volumes contain creation, last modification
  251. time and date, and the last access date for each file or subdirectory.
  252. Directory last modification time and date fields are set only when 
  253. a new entry is created, but not when any directory entries are deleted.
  254. The last access date field indicates the date of the last read or write.  
  255. The last access date field is an optional field, per Microsoft.  By 
  256. default, file open-read-close operations do not update the last access 
  257. date field.  This default avoids media writes (writing out the date field)
  258. during read only operations.   In order to enable the updating of the 
  259. optional last access date field for open-read-close operations, you must 
  260. call dosFsLastAccessDateEnable(), passing it the volumes DOS_VOLUME_DESC_ID 
  261. and TRUE.
  262. The dosFs file system uses the ANSI time() function, that returns
  263. system clock value to obtain date and time.  It is recommended that the
  264. target system should set the system time during system initialization
  265. time from a network server or from an embedded Calendar / Clock
  266. hardware component, so that all files on the file system would be
  267. associated with a correct date and time.
  268. The file system consistency checker (see below) sets system clock to
  269. value following the latest date-time field stored on the disk, if it
  270. discovers, that function time() returns a date earlier then Jan 1,
  271. 1998, meaning that the target system does not have a source of valid
  272. date and time to synchronize with.
  273. See also the reference manual entry for ansiTime.
  274. FILE ATTRIBUTES
  275. Directory entries on dosFs volumes contain an attribute byte consisting
  276. of bit-flags which specify various characteristics of the entry.  The
  277. attributes which are identified are:  read-only file, hidden file,
  278. system file, volume label, directory, and archive.  The VxWorks symbols
  279. for these attribute bit-flags are:
  280. .IP DOS_ATTR_RDONLY
  281. File is write-protected, can not be modified or deleted.
  282. .IP DOS_ATTR_HIDDEN
  283. this attribute is not used by VxWorks.
  284. .IP DOS_ATTR_SYSTEM
  285. this attribute is not used by VxWorks.
  286. .IP DOS_ATTR_VOL_LABEL
  287. directory entry describes a volume label,
  288. this attribute can not be set or used directly, see ioctl() command
  289. FIOLABELGET and FIOLABELSET below for volume label manipulation.
  290. .IP DOS_ATTR_DIRECTORY
  291. directory entry is a subdirectory,
  292. this attribute can not be set directly.
  293. .IP DOS_ATTR_ARCHIVE
  294. this attribute is not used by VxWorks.
  295. .LP
  296. All the flags in the attribute byte, except the directory and volume label
  297. flags, may be set or cleared using the ioctl() FIOATTRIBSET function.  This
  298. function is called after opening the specific file whose attributes are to
  299. be changed.  The attribute byte value specified in the FIOATTRIBSET call is
  300. copied directly.  To preserve existing flag settings, the current attributes
  301. should first be determined via fstat(), and the appropriate
  302. flag(s) changed using bitwise AND or OR operations.  For example, to make
  303. a file read-only, while leaving other attributes intact:
  304. .CS
  305.     struct stat fileStat;
  306.     fd = open ("file", O_RDONLY, 0);     /@ open file          @/
  307.     fstat (fd, &fileStat);               /@ get file status    @/
  308.     ioctl (fd, FIOATTRIBSET, (fileStat.st_attrib | DOS_ATTR_RDONLY));
  309.                                          /@ set read-only flag @/
  310.     close (fd);                          /@ close file         @/
  311. .CE
  312. .LP
  313. See also the reference manual entry for attrib() and xattrib() for
  314. user-level utility routines which control the attributes of files or
  315. file hierarchy.
  316. CONTIGOUS FILE SUPPORT
  317. The VxWorks dosFs file system provides efficient files storage:
  318. space will be allocated in groups of clusters (also termed 
  319. .I extents
  320. ) so that a file will be composed of relatively large contiguous units.
  321. This  nearly contiguous allocation technique is designed to
  322. effectively eliminate the effects of disk space fragmentation,
  323. keeping throughput very close to the maximum of which the hardware is
  324. capable of.
  325. However dosFs provides mechanism to allocate truly contiguous files,
  326. meaning files which are made up of a consecutive series of disk sectors.
  327. This support includes both the ability to allocate contiguous space to a file
  328. and optimized access to such a file when it is used.
  329. Usually this will somewhat improve performance when compared to
  330. Nearly Contiguous allocation, at the price of disk space fragmentation.
  331. To allocate a contiguous area to a file, the file is first created in the
  332. normal fashion, using open() or creat().  The file descriptor returned
  333. during the creation of the file is then used to make an ioctl() call,
  334. specifying the FIOCONTIG or FIOCONTIG64 function.
  335. The last parameter to the FIOCONTIG function is the size of the requested
  336. contiguous area in bytes, If the FIOCONTIG64 is used, the last parameter
  337. is pointer to 64-bit integer variable, which contains the required file size.
  338. It is also possible to request that the largest contiguous free area on
  339. the disk be obtained.  In this case, the size value CONTIG_MAX (-1) 
  340. is used instead of an actual size.  These ioctl() codes
  341. are not supported for directories.
  342. The volume is searched for a contiguous area of free space, which 
  343. is assigned to the file. If a segment of contiguous free space
  344. large enough for the request was not found,
  345. ERROR is returned, with <errno> set to  S_dosFsLib_NO_CONTIG_SPACE.
  346. When contiguous space is allocated to a file, the file remains empty,
  347. while the newly allocated space has not been initialized.
  348. The data should be then written to the file, and eventually, when
  349. all data has been written, the file is closed.
  350. When file is closed, its space is truncated to reflect the amount
  351. of data actually written to the file.
  352. This file may then be again opened and used for further 
  353. I/O operations read() or write(), 
  354. but it can not be guaranteed that appended data will be contiguous
  355. to the initially written data segment.
  356. For example, the following will create a file and allocate 85 Mbytes of 
  357. contiguous space:
  358. .CS
  359.     fd = creat ("file", O_RDWR, 0);             /@ open file             @/
  360.     status = ioctl (fd, FIOCONTIG, 85*0x100000);/@ get contiguous area   @/
  361.     if (status != OK)
  362.        ...                                      /@ do error handling     @/
  363.     close (fd);                                 /@ close file            @/
  364. .CE
  365. In contrast, the following example will create a file and allocate the
  366. largest contiguous area on the disk to it:
  367. .CS
  368.     fd = creat ("file", O_RDWR, 0);             /@ open file             @/
  369.     status = ioctl (fd, FIOCONTIG, CONTIG_MAX); /@ get contiguous area   @/
  370.     if (status != OK)
  371.        ...                                      /@ do error handling     @/
  372.     close (fd);                                 /@ close file            @/
  373. .CE
  374. .IP NOTE
  375. the FIOCONTIG operation should take place right after the file has been
  376. created, before any data is written to the file.
  377. Directories may not be allocated a contiguous disk area.
  378. .LP
  379. To determine the actual amount of contiguous space obtained when CONTIG_MAX
  380. is specified as the size, use fstat() to examine the number of blocks
  381. and block size for the file.
  382. When any file is opened, it may be checked for contiguity.
  383. Use the extended flag DOS_O_CONTIG_CHK when calling open() to access an
  384. existing file which may have been allocated contiguous space.
  385. If a file is detected as contiguous, all subsequent operations on the
  386. file will not require access to the File Allocation Table, thus
  387. eliminating any disk Seek operations.
  388. The down side however is that if this option is used, open() will take
  389. an amount of time which is linearly proportional of the file size.
  390. CHANGING, UNMOUNTING, AND SYNCHRONIZING DISKS
  391. Buffering of disk data in RAM, synchronization of these
  392. buffers with the disk and detection of removable disk replacement are
  393. all handled by the disk cache. See reference manual on dcacheCbio
  394. for more details.
  395. If a disk is physically removed, the disk cache will cause dosFsLib to
  396. .I unmount
  397. the volume, which will mark all currently open file descriptors as
  398. .I obsolete.
  399. If a new disk is inserted, it will be automatically
  400. .I mounted
  401. on the next call to open() or creat().
  402. IOCTL FUNCTIONS
  403. The dosFs file system supports the following ioctl() functions.  The
  404. functions listed are defined in the header ioLib.h.  Unless stated
  405. otherwise, the file descriptor used for these functions may be any file
  406. descriptor which is opened to a file or directory on the volume or to 
  407. the volume itself.
  408. There are some ioctl() commands, that expect a 32-bit integer result
  409. (FIONFREE, FIOWHERE, etc.).
  410. However, disks and files with are grater than 4GB are supported.
  411. In order to solve this problem, new ioctl() functions have been added
  412. to support 64-bit integer results.
  413. They have the same name as basic functions, but with suffix 
  414. .I 64,
  415. namely: FIONFREE64, FIOWHERE64 and so on. These commands
  416. expect a pointer to a 64-bit integer, i.e.:
  417. .CS
  418. long long *arg ;
  419. .CE
  420. as the 3rd argument to the ioctl() function.
  421. If a value which is requested with a 32-bit ioctl() command is
  422. too large to be represented in the 32-bit variable, ioctl() will return
  423. ERROR, and <errno> will be set to S_dosFsLib_32BIT_OVERFLOW.
  424. .iP "FIODISKINIT"
  425. Reinitializes a DOS file system on the disk volume.
  426. This function calls dosFsVolFormat() to format the volume,
  427. so dosFsFmtLib must be installed for this to work.
  428. Third argument of ioctl() is passed as argument <opt> to
  429. dosFsVolFormat() routine.
  430. This routine does not perform a low level format,
  431. the physical media is expected to be already formatted.
  432. If DOS file system device has not been created yet for a particular device,
  433. only direct call to dosFsVolFormat() can be used.
  434. .CS
  435.     fd = open ("DEV1:", O_WRONLY);
  436.     status = ioctl (fd, FIODISKINIT, DOS_OPT_BLANK);
  437. .CE
  438. .iP "FIODISKCHANGE"
  439. Announces a media change. No buffers flushing is performed.
  440. This function may be called from interrupt level:
  441. .CS
  442.     status = ioctl (fd, FIODISKCHANGE, 0);
  443. .CE
  444. .iP "FIOUNMOUNT"
  445. Unmounts a disk volume.  It performs the same function as dosFsVolUnmount().
  446. This function must not be called from interrupt level:
  447. .CS
  448.     status = ioctl (fd, FIOUNMOUNT, 0);
  449. .CE
  450. .iP "FIOGETNAME"
  451. Gets the file name of the file descriptor and copies it to the buffer <nameBuf>.
  452. Note that <nameBuf> must be large enough to contain the largest possible
  453. path name, which requires at least 256 bytes.
  454. .CS
  455.     status = ioctl (fd, FIOGETNAME, &nameBuf );
  456. .CE
  457. .iP "FIORENAME"
  458. Renames the file or directory to the string <newname>:
  459. .CS
  460.     fd = open( "oldname", O_RDONLY, 0 );
  461.     status = ioctl (fd, FIORENAME, "newname");
  462. .CE
  463. .iP "FIOMOVE"
  464. Moves the file or directory to the string <newname>:
  465. .CS
  466.     fd = open( "oldname", O_RDONLY, 0 );
  467.     status = ioctl (fd, FIOMOVE, "newname");
  468. .CE
  469. .iP "FIOSEEK"
  470. Sets the current byte offset in the file to the position specified by
  471. <newOffset>. This function supports offsets in 32-bit value range.
  472. Use FIOSEEK64 for larger position values:
  473. .CS
  474.     status = ioctl (fd, FIOSEEK, newOffset);
  475. .CE
  476. .iP "FIOSEEK64"
  477. Sets the current byte offset in the file to the position specified by
  478. <newOffset>. This function supports offsets in 64-bit value range:
  479. .CS
  480.     long long newOffset;
  481.     status = ioctl (fd, FIOSEEK64, (int) & newOffset);
  482. .CE
  483. .iP "FIOWHERE"
  484. Returns the current byte position in the file.  This is the
  485. byte offset of
  486. the next byte to be read or written.  This function returns a 32-bit value.
  487. It takes no additional argument:
  488. .CS
  489.     position = ioctl (fd, FIOWHERE, 0);
  490. .CE
  491. .iP "FIOWHERE64"
  492. Returns the current byte position in the file.  This is the
  493. byte offset of
  494. the next byte to be read or written.  This function returns a 64-bit
  495. value in <position>:
  496. .CS
  497.     long long position;
  498.     status = ioctl (fd, FIOWHERE64, (int) & position);
  499. .CE
  500. .iP "FIOFLUSH"
  501. Flushes disk cache buffers.  It guarantees that any output that has
  502. been requested is actually written to the device:
  503. .CS
  504.     status = ioctl (fd, FIOFLUSH, 0);
  505. .CE
  506. .iP "FIOSYNC"
  507. Updates the FAT copy for the passed file descriptor, then      
  508. flushes and invalidates the CBIO cache buffers for the file    
  509. descriptor's volume.  FIOSYNC ensures that any outstanding     
  510. output requests for the passed file descriptor are written     
  511. to the device and a subsequent I/O operation will fetch data   
  512. directly from the physical medium.  To safely sync a volume    
  513. for shutdown, all open file descriptor's should at the least   
  514. be FIOSYNC'd by the application.  Better, all open FD's should 
  515. be closed by the application and the volume should be unmounted
  516. via FIOUNMOUNT.
  517. .CS
  518.     status = ioctl (fd, FIOSYNC, 0);
  519. .CE
  520. .iP "FIOTRUNC"
  521. Truncates the specified file's length to <newLength> bytes.  Any disk
  522. clusters which had been allocated to the file but are now unused are
  523. deallocated, and the directory entry for the file is updated to reflect
  524. the new length.  Only regular files may be truncated; attempts to use
  525. FIOTRUNC on directories will return an error.
  526. FIOTRUNC may only be used to make files shorter; attempting to specify
  527. a <newLength> larger than the current size of the file produces an
  528. error (setting errno to S_dosFsLib_INVALID_NUMBER_OF_BYTES).
  529. .CS
  530.     status = ioctl (fd, FIOTRUNC, newLength);
  531. .CE
  532. .iP "FIOTRUNC64"
  533. Similar to FIOTRUNC, but can be used for files lager, than 4GB.
  534. .CS
  535.     long long newLength = .....;
  536.     status = ioctl (fd, FIOTRUNC, (int) & newLength);
  537. .CE  
  538. .iP "FIONREAD"
  539. Copies to <unreadCount> the number of unread bytes in the file:
  540. .CS
  541.     unsigned long unreadCount;
  542.     status = ioctl (fd, FIONREAD, &unreadCount);
  543. .CE
  544. .iP "FIONREAD64"
  545. Copies to <unreadCount> the number of unread bytes in the file.
  546. This function returns a 64-bit integer value:
  547. .CS
  548.     long long unreadCount;
  549.     status = ioctl (fd, FIONREAD64, &unreadCount);
  550. .CE
  551. .iP "FIONFREE"
  552. Copies to <freeCount> the amount of free space, in bytes, on the volume:
  553. .CS
  554.    unsigned long freeCount;
  555.    status = ioctl (fd, FIONFREE, &freeCount);
  556. .CE
  557. .iP "FIONFREE64"
  558. Copies to <freeCount> the amount of free space, in bytes, on the volume.
  559. This function can return value in 64-bit range:
  560. .CS
  561.    long long freeCount;
  562.    status = ioctl (fd, FIONFREE64, &freeCount);
  563. .CE
  564. .iP "FIOMKDIR"
  565. Creates a new directory with the name specified as <dirName>:
  566. .CS
  567.     status = ioctl (fd, FIOMKDIR, "dirName");
  568. .CE
  569. .iP "FIORMDIR"
  570. Removes the directory whose name is specified as <dirName>:
  571. .CS
  572.     status = ioctl (fd, FIORMDIR, "dirName");
  573. .CE
  574. .iP "FIOLABELGET"
  575. Gets the volume label (located in root directory) and copies the string to
  576. <labelBuffer>. If the label contains DOS_VOL_LABEL_LEN significant
  577. characters, resulting string  is not NULL terminated:
  578. .CS
  579.     char labelBuffer [DOS_VOL_LABEL_LEN];
  580.     status = ioctl (fd, FIOLABELGET, (int)labelBuffer);
  581. .CE
  582. .iP "FIOLABELSET"
  583. Sets the volume label to the string specified as <newLabel>.  The string may
  584. consist of up to eleven ASCII characters:
  585. .CS
  586.     status = ioctl (fd, FIOLABELSET, (int)"newLabel");
  587. .CE
  588. .iP "FIOATTRIBSET"
  589. Sets the file attribute byte in the DOS directory entry to the new value
  590. <newAttrib>.  The file descriptor refers to the file whose entry is to be 
  591. modified:
  592. .CS
  593.     status = ioctl (fd, FIOATTRIBSET, newAttrib);
  594. .CE
  595. .iP "FIOCONTIG"
  596. Allocates contiguous disk space for a file or directory.  The number of
  597. bytes of requested space is specified in <bytesRequested>.  In general,
  598. contiguous space should be allocated immediately after the file is
  599. created:
  600. .CS
  601.     status = ioctl (fd, FIOCONTIG, bytesRequested);
  602. .CE
  603. .iP "FIOCONTIG64"
  604. Allocates contiguous disk space for a file or directory.  The number of
  605. bytes of requested space is specified in <bytesRequested>.  In general,
  606. contiguous space should be allocated immediately after the file is
  607. created. This function accepts a 64-bit value:
  608. .CS
  609.     long long bytesRequested;
  610.     status = ioctl (fd, FIOCONTIG64, &bytesRequested);
  611. .CE
  612. .iP "FIONCONTIG"
  613. Copies to <maxContigBytes> the size of the largest contiguous free space, 
  614. in bytes, on the volume:
  615. .CS
  616.     status = ioctl (fd, FIONCONTIG, &maxContigBytes);
  617. .CE
  618. .iP "FIONCONTIG64"
  619. Copies to <maxContigBytes> the size of the largest contiguous free space,
  620. in bytes, on the volume. This function returns a 64-bit value:
  621. .CS
  622.     long long maxContigBytes;
  623.     status = ioctl (fd, FIONCONTIG64, &maxContigBytes);
  624. .CE
  625. .iP "FIOREADDIR"
  626. Reads the next directory entry.  The argument <dirStruct> is a DIR
  627. directory descriptor.  Normally, the readdir() routine is used to read a
  628. directory, rather than using the FIOREADDIR function directly.  See dirLib.
  629. .CS
  630.     DIR dirStruct;
  631.     fd = open ("directory", O_RDONLY);
  632.     status = ioctl (fd, FIOREADDIR, &dirStruct);
  633. .CE
  634. .iP "FIOFSTATGET"
  635. Gets file status information (directory entry data).  The argument
  636. <statStruct> is a pointer to a stat structure that is filled with data
  637. describing the specified file.  Normally, the stat() or fstat() routine is
  638. used to obtain file information, rather than using the FIOFSTATGET
  639. function directly.  See dirLib.
  640. .CS
  641.     struct stat statStruct;
  642.     fd = open ("file", O_RDONLY);
  643.     status = ioctl (fd, FIOFSTATGET, (int)&statStruct);
  644. .CE
  645. .iP "FIOTIMESET"
  646. Update time on a file.   <arg> shall be a pointer to a utimbuf structure, 
  647. see utime.h.  If <arg> is value NULL, the current system time is used for
  648. both actime and modtime members.  If <arg> is not NULL then the utimbuf 
  649. structure members actime and modtime are used as passed.  If actime is 
  650. zero value, the file access time is not updated (the operation is ignored).  
  651. If modtime is zero, the file modification time is not updated (the operation 
  652. is ignored).   
  653. See also utime()
  654. ..CS
  655.     struct utimbuf newTimeBuf;;
  656.     newTimeBuf.modtime = newTimeBuf.actime = fileNewTime;
  657.     fd = open ("file", O_RDONLY);
  658.     status = ioctl (fd, FIOTIMESET, (int)&newTimeBuf);
  659. .CE
  660. .iP "FIOCHKDSK"
  661. This function invokes the integral consistency checking.
  662. During the test, the file system will be blocked from application code
  663. access, and will emit messages describing any inconsistencies found on
  664. the disk, as well as some statistics, depending on the verbosity
  665. level in the <flags> argument.
  666. Depending on the repair permission value in <flags> argument,
  667. the inconsistencies will be repaired, and changes written to disk
  668. or only reported.
  669. Argument <flags> should be composed of bitwise or-ed
  670. verbosity level value and repair permission value.
  671. Possible repair levels are:
  672. .RS
  673. .iP "DOS_CHK_ONLY (1)"
  674. Only report errors, do not modify disk.
  675. .iP "DOS_CHK_REPAIR (2)"
  676. Repair any errors found.
  677. .LP
  678. Possible verbosity levels are:
  679. .iP "DOS_CHK_VERB_SILENT (0xff00)"
  680. Do not emit any messages, except errors encountered.
  681. .iP "DOS_CHK_VERB_1 (0x0100)"
  682. Display some volume statistics when done testing, as well
  683. .iP "DOS_CHK_VERB_2 (0x0200)"
  684. In addition to the above option, display path of every file, while it
  685. is being checked. This option may significantly slow down the test
  686. process.
  687. .IP "NOTE"
  688. In environments with reduced RAM size check disk uses reserved
  689. FAT copy as temporary buffer, it can cause respectively long
  690. time of execution on a slow CPU architectures..
  691. .LP
  692. .RE
  693. See also the reference manual usrFsLib for the chkdsk() user level
  694. utility which may be used to invoke the FIOCHKDSK ioctl().
  695. The volume root directory should be opened, and the resulting file
  696. descriptor should be used:
  697. .CS
  698.     int fd = open (device_name, O_RDONLY, 0);
  699.     status = ioctl (fd, FIOCHKDSK, DOS_CHK_REPAIR | DOS_CHK_VERB_1);
  700.     close (fd);
  701. .CE
  702. .LP
  703. Any other ioctl() function codes are passed to the underlying
  704. .I CBIO
  705. modules for handling.
  706. INCLUDE FILES: dosFsLib.h
  707. SEE ALSO:
  708. ioLib, iosLib, dirLib, usrFsLib, dcacheCbio, dpartCbio, dosFsFmtLib,
  709. dosChkLib
  710. .I "Microsoft MS-DOS Programmer's Reference"
  711. (Microsoft Press),
  712. .I "Advanced MS-DOS Programming"
  713. (Ray Duncan, Microsoft Press),
  714. .I "VxWorks Programmer's Guide: I/O System, Local File Systems"
  715. INTERNAL:
  716. Note:  To represent a backslash in documentation use "e", not "\".
  717. The double backslash sometimes works, but results may be unpredictable.
  718. */
  719. /* includes */
  720. #include "vxWorks.h"
  721. #include "private/dosFsVerP.h"
  722. #include "stat.h"
  723. #include "time.h"
  724. #include "dirent.h"
  725. #include "stdio.h"
  726. #include "stdlib.h"
  727. #include "string.h"
  728. #include "taskLib.h"
  729. #include "tickLib.h"
  730. #include "semLib.h"
  731. #include "logLib.h"
  732. #include "errnoLib.h"
  733. #include "memLib.h"
  734. #include "utime.h"
  735. #include "blkIo.h"
  736. #include "private/print64Lib.h"
  737. #include "private/dosFsLibP.h"
  738. #include "private/dosDirLibP.h"
  739. /* defines */
  740. #if FALSE
  741. #   undef FAT_ALLOC_ONE
  742. #   define FAT_ALLOC_ONE        (FAT_ALLOC | 8)
  743. #endif /* FALSE */
  744. /* macros */
  745. #undef DBG_MSG
  746. #undef ERR_MSG
  747. #undef NDEBUG
  748. #ifdef DEBUG
  749. #   undef LOCAL
  750. #   define LOCAL
  751. #   undef ERR_SET_SELF
  752. #   define ERR_SET_SELF
  753. #   define DBG_MSG( lvl, fmt, arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 )
  754. { if( (lvl) <= dosFsDebug )
  755.     printErr( "%s : %d : " fmt,
  756.                __FILE__, __LINE__, arg1,arg2,
  757.        arg3,arg4,arg5,arg6,arg7,arg8 ); }
  758. #   define ERR_MSG( lvl, fmt, a1,a2,a3,a4,a5,a6 )
  759.         { logMsg( __FILE__ " : " fmt, (int)(a1), (int)(a2),
  760.   (int)(a3), (int)(a4), (int)(a5), (int)(a6) ); }
  761. #else /* NO DEBUG */
  762. #   define NDEBUG
  763. #   define DBG_MSG(lvl,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)  {}
  764. #   define ERR_MSG( lvl, fmt, a1,a2,a3,a4,a5,a6 )
  765. { if( (lvl) <= dosFsDebug ) 
  766.             logMsg( __FILE__ " : " fmt, (int)(a1), (int)(a2),
  767.   (int)(a3), (int)(a4), (int)(a5), (int)(a6) ); }
  768. #endif /* DEBUG */
  769. #include "assert.h"
  770. #ifdef ERR_SET_SELF
  771. #   define errnoSet( err ) errnoSetOut( __FILE__, __LINE__, #err, (err) )
  772. #endif /* ERR_SET_SELF */
  773. /* typedefs */
  774. /* globals */
  775. int dosFsDrvNum = ERROR; /* dosFs number in vxWorks driver table */
  776. u_int dosFsDebug = 1;
  777. /* handlers lists */
  778. DOS_HDLR_DESC    dosFatHdlrsList[ DOS_MAX_HDLRS ] = {{0}};
  779. DOS_HDLR_DESC    dosDirHdlrsList[ DOS_MAX_HDLRS ] = {{0}};
  780. STATUS (*dosFsChkRtn)( DOS_FILE_DESC_ID pFd ) = NULL;
  781. /* check disk routine */
  782. STATUS (*dosFsVolFormatRtn)( void * pDev, int opt,
  783.                              FUNCPTR pPromptFunc ) = NULL;
  784.                            /* volume format routine */
  785. /* locals */
  786. LOCAL STATUS dosFsRead( FAST DOS_FILE_DESC_ID pFd, char * pBuf,
  787.                         int maxBytes );
  788. LOCAL STATUS dosFsIoctl ( FAST DOS_FILE_DESC_ID pFd, int function, int arg );
  789. LOCAL DOS_FILE_DESC_ID dosFsOpen ( FAST DOS_VOLUME_DESC * pVolDesc,
  790.                                   char * pPath, int flags, int mode );
  791. LOCAL STATUS dosFsDelete (DOS_VOLUME_DESC_ID pVolDesc, char * pPath);
  792. LOCAL STATUS dosFsClose  (DOS_FILE_DESC_ID pFd);
  793. LOCAL STATUS dosFsRename (DOS_FILE_DESC_ID    pFdOld, char * pNewName,
  794.                           BOOL        allowOverwrite);
  795. #ifdef ERR_SET_SELF
  796. /*******************************************************************************
  797. * errnoSetOut - put error message
  798. *
  799. * This routine is called instead of errnoSet during debugging.
  800. */
  801. static VOID errnoSetOut(char * pFile, int line, const char * pStr, int errCode )
  802.     {
  803.     if( errCode != OK && strcmp( str, "errnoBuf" ) != 0 )
  804.         printf( " %s : line %d : %s = %p, task %pn",
  805.                 pFile, line, pStr, (void *)errCode,
  806.                 (void *)taskIdSelf() );
  807.     errno = errCode;
  808.     }
  809. #endif  /* ERR_SET_SELF */
  810. /*******************************************************************************
  811. *
  812. * dosSetVolCaseSens - set case sensitivity of volume
  813. *
  814. * Pass TRUE to setup a case sensitive volume.  
  815. * Pass FALSE to setup a case insensitive volume.  
  816. * Note this affects rename lookups only.
  817. *
  818. * RETURNS: TRUE if pVolDesc pointed to a DOS volume.
  819. */
  820. STATUS dosSetVolCaseSens 
  821.     ( 
  822.     DOS_VOLUME_DESC_ID pVolDesc, 
  823.     BOOL sensitivity 
  824.     )
  825.     {
  826.     BOOL isValid; /* Validity flag */
  827.     /* If the parameter is aligned OK */
  828.     if ( TRUE == (isValid = _WRS_ALIGN_CHECK(pVolDesc, DOS_VOLUME_DESC)))
  829.         {
  830.         /* Aligned parameter, but is it a DOS volume? */
  831.         if ( TRUE == (isValid = (pVolDesc->magic == DOS_FS_MAGIC )) )
  832.             {
  833.             pVolDesc->volIsCaseSens = sensitivity;
  834.             }
  835.         }
  836.     /* Didn't work? Broken parameter then */
  837.     if (FALSE == isValid)
  838.         {
  839.         /* Not a DOS volume or not aligned so that's an invalid parameter */
  840.         errnoSet( S_dosFsLib_INVALID_PARAMETER );
  841.         }
  842.     /* If it was valid it got set. */
  843.     return (isValid);
  844.     }
  845. /*******************************************************************************
  846. *
  847. * dosFsIsValHuge - check if value is grater, than 4GB (max 32 bit).
  848. *
  849. * RETURNS: TRUE if is grater, else return FALSE.
  850. */
  851. LOCAL BOOL dosFsIsValHuge
  852.     (
  853.     fsize_t val
  854.     )
  855.     {
  856.     return DOS_IS_VAL_HUGE( val );
  857.     } /* dosFsIsValHuge() */
  858. /*******************************************************************************
  859. *
  860. * dosFsVolDescGet - convert a device name into a DOS volume descriptor pointer.
  861. * This routine validates <pDevNameOrPVolDesc> to be a DOS volume
  862. * descriptor pointer else a path to a DOS device. This routine 
  863. * uses the standard iosLib function iosDevFind() to obtain a pointer 
  864. * to the device descriptor. If device is eligible, <ppTail> is 
  865. * filled with the pointer to the first character following
  866. * the device name.  Note that ppTail is passed to iosDevFind().
  867. * <ppTail> may be passed as NULL, in which case it is ignored.
  868. *
  869. * RETURNS: A DOS_VOLUME_DESC_ID or NULL if not a DOSFS device.
  870. *
  871. * ERRNO:
  872. * S_dosFsLib_INVALID_PARAMETER
  873. */
  874. DOS_VOLUME_DESC_ID dosFsVolDescGet
  875.     (
  876.     void *      pDevNameOrPVolDesc, /* device name or pointer to dos vol desc */
  877.     u_char **   ppTail      /* return ptr for name, used in iosDevFind */    
  878.     )
  879.     {
  880.     DOS_VOLUME_DESC_ID pVolDesc; /* pointer to volume descriptor */
  881.     char *      pDevName = (pDevNameOrPVolDesc == NULL) ?
  882.        "" : pDevNameOrPVolDesc;
  883.     u_char *    pNameTail;
  884.     if( ppTail == NULL )
  885.      ppTail = &pNameTail;
  886.     
  887.     *ppTail = NULL;
  888.     
  889.     pVolDesc = pDevNameOrPVolDesc;
  890.     
  891.     /* SPR#71720 NULL is presumed to be an invalid value */
  892.     
  893.     if (NULL == pVolDesc)
  894.         {
  895.         errnoSet( S_dosFsLib_INVALID_PARAMETER );
  896. return (NULL);
  897.         }
  898.     /* SPR#71720 ensure alignment and then check the magic cookie */
  899.     if (TRUE == _WRS_ALIGN_CHECK(pVolDesc, DOS_VOLUME_DESC))
  900.         {
  901.         if (pVolDesc->magic == DOS_FS_MAGIC )
  902.             {
  903.          return (pVolDesc);
  904.             }
  905.         }
  906.     /* attempt to extract volume descriptor ptr from device name */
  907.     
  908. #ifdef _WRS_DOSFS2_VXWORKS_AE
  909.     pVolDesc =
  910.       (DOS_VOLUME_DESC_ID) iosDevFind (pDevName, (const char **)ppTail);
  911. #else
  912.     pVolDesc =
  913.       (DOS_VOLUME_DESC_ID) iosDevFind (pDevName, (char **) ppTail);
  914. #endif /* _WRS_DOSFS2_VXWORKS_AE */
  915.     /* 
  916.      * SPR#76510, if iosDevFind() returned default device,
  917.      * then the tail (ppTail) will point to the front of
  918.      * the passed name and that is considered a lookup failure.
  919.      */
  920.     if ((NULL == pVolDesc) || ((char *) *ppTail == pDevName))
  921.         {
  922.         errnoSet( S_dosFsLib_INVALID_PARAMETER );
  923. return (NULL);
  924.         }
  925.     /* SPR#71720 ensure alignment and then check the magic cookie */
  926.     if (TRUE == _WRS_ALIGN_CHECK(pVolDesc, DOS_VOLUME_DESC))
  927.         {
  928.         if (pVolDesc->magic == DOS_FS_MAGIC )
  929.             {
  930.          return (pVolDesc);
  931.             }
  932.         }
  933.     
  934.     errnoSet( S_dosFsLib_INVALID_PARAMETER );
  935.  
  936.     return (NULL);
  937.     } /* dosFsVolDescGet() */
  938. /*******************************************************************************
  939. *
  940. * dosFsFSemTake - take file semaphore.
  941. *
  942. * RETURNS: STATUS as result of semTake.
  943. */
  944. LOCAL STATUS dosFsFSemTake
  945.     (
  946.     DOS_FILE_DESC_ID pFd,
  947.     int timeout
  948.     )
  949.     {
  950.     STATUS retStat;
  951.     assert( pFd - pFd->pVolDesc->pFdList < pFd->pVolDesc->maxFiles );
  952.     assert( pFd->pFileHdl - pFd->pVolDesc->pFhdlList <
  953.             pFd->pVolDesc->maxFiles );
  954.     retStat =  semTake( *(pFd->pVolDesc->pFsemList + 
  955.              (pFd->pFileHdl - pFd->pVolDesc->pFhdlList)),
  956.                         timeout);
  957.     assert( retStat == OK );
  958.     return retStat;
  959.     } /* dosFsFSemTake() */
  960.     
  961. /*******************************************************************************
  962. *
  963. * dosFsFSemGive - release file semaphore.
  964. *
  965. * RETURNS: STATUS as result of semGive.
  966. */
  967. LOCAL STATUS dosFsFSemGive
  968.     (
  969.     DOS_FILE_DESC_ID pFd
  970.     )
  971.     {
  972.     STATUS retStat;
  973.  
  974.     assert( pFd - pFd->pVolDesc->pFdList < pFd->pVolDesc->maxFiles );
  975.     assert( pFd->pFileHdl - pFd->pVolDesc->pFhdlList <
  976.             pFd->pVolDesc->maxFiles );
  977.  
  978.     retStat =  semGive( *(pFd->pVolDesc->pFsemList + 
  979.             (pFd->pFileHdl - pFd->pVolDesc->pFhdlList)));
  980.     assert( retStat == OK );
  981.     return retStat;
  982.     } /* dosFsFSemGive() */
  983.     
  984. /*******************************************************************************
  985. *
  986. * dosFsVolUnmount - unmount a dosFs volume
  987. *
  988. * This routine is called when I/O operations on a volume are to be
  989. * discontinued.  This is the preferred action prior to changing a
  990. * removable disk.
  991. *
  992. * All buffered data for the volume is written to the device
  993. * (if possible, with no error returned if data cannot be written),
  994. * any open file descriptors are marked as obsolete,
  995. * and the volume is marked as not currently mounted.
  996. *
  997. * When a subsequent open() operation is initiated on the device,
  998. * new volume will be mounted automatically.
  999. *
  1000. * Once file descriptors have been marked as obsolete, any attempt to
  1001. * use them for file operations will return an error.  (An obsolete file
  1002. * descriptor may be freed by using close().  The call to close() will
  1003. * return an error, but the descriptor will in fact be freed).
  1004. *
  1005. * This routine may also be invoked by calling ioctl() with the
  1006. * FIOUNMOUNT function code.
  1007. *
  1008. * This routine must not be called from interrupt level.
  1009. *
  1010. * RETURNS: OK, or ERROR if the volume was not mounted.
  1011. *
  1012. * NOMANUAL
  1013. */
  1014. STATUS dosFsVolUnmount
  1015.     (
  1016.     void * pDevNameOrPVolDesc /* device name or ptr to */
  1017.      /* volume descriptor */
  1018.     )
  1019.     {
  1020.     DOS_VOLUME_DESC_ID pVolDesc; /* pointer to volume descriptor */
  1021.     int i;
  1022.     
  1023.     /* get volume descriptor */
  1024.     
  1025.     pVolDesc = dosFsVolDescGet( pDevNameOrPVolDesc, NULL );
  1026.     if( pVolDesc == NULL )
  1027.      return ERROR;
  1028.     
  1029.     if( ! pVolDesc->mounted )
  1030.      return ERROR;
  1031.     
  1032.     /* acquire semaphore */
  1033.     
  1034.     if( semTake( pVolDesc->devSem, WAIT_FOREVER ) == ERROR )
  1035.      return ERROR;
  1036.     
  1037.     /* mark all opened file descriptors as obsolete */
  1038.     /* also synchronize the FAT and do not hold the */
  1039.     /* file semaphore, in certain operations like   */
  1040.     /* rename-file the file semaphore is locked     */
  1041.     /* before devSem. Trying to hold file semaphore */
  1042.     /* , after holding devSem, will cause dead-lock */
  1043.  
  1044.     for( i = 0; i < pVolDesc->maxFiles; i ++ )
  1045.      {
  1046.     if( pVolDesc->pFdList[ i ].busy )
  1047.     {
  1048.     /* Synchronize the FAT */
  1049.     pVolDesc->pFatDesc->flush(&pVolDesc->pFdList[i]);
  1050.          pVolDesc->pFdList[ i ].pFileHdl->obsolet = 1;
  1051.     }
  1052.      }
  1053.     pVolDesc->nBusyFd = 0;
  1054.     
  1055.     /* flush buffers */
  1056.     
  1057.     cbioIoctl( pVolDesc->pCbio, CBIO_CACHE_FLUSH, (void*)(-1) );
  1058.     cbioIoctl( pVolDesc->pCbio, CBIO_CACHE_INVAL, 0 );
  1059.     
  1060.     pVolDesc->mounted = FALSE; /* volume unmounted */
  1061.     
  1062.     semGive( pVolDesc->devSem );
  1063.     return OK;
  1064.     } /* dosFsVolUnmount() */
  1065.     
  1066. /*******************************************************************************
  1067. *
  1068. * dosFsChkDsk - make volume integrity checking.
  1069. *
  1070. * This library does not makes integrity check process itself, but
  1071. * instead uses routine provided by dosChkLib. 
  1072. * This routine prepares parameters and invokes checking routine
  1073. * via preinitialized function pointer. If dosChkLib does not configured
  1074. * into vxWorks, this routine returns ERROR.
  1075. *
  1076. * Ownership on device should be taken by an upper level routine.
  1077. *
  1078. * RETURNS: STATUS as returned by volume checking routine or
  1079. *  ERROR, if such routine does not installed.
  1080. *
  1081. * ERRNO:
  1082. * S_dosFsLib_UNSUPPORTED.
  1083. */
  1084. STATUS dosFsChkDsk
  1085.     (
  1086.     FAST DOS_FILE_DESC_ID pFd, /* file descriptor of root dir */
  1087.     u_int params      /* check level and verbosity */
  1088.     )
  1089.     {
  1090.     DOS_VOLUME_DESC_ID pVolDesc = pFd->pVolDesc;
  1091.     CBIO_DEV_ID cbio =  pFd->pVolDesc->pCbio;
  1092.     STATUS retVal = ERROR;
  1093.     
  1094.     if( dosFsChkRtn == NULL )
  1095.         {
  1096.      errnoSet( S_dosFsLib_UNSUPPORTED );
  1097. ERR_MSG(1,"Check disk utility not installedn", 0,0,0,0,0,0 );
  1098.      return ERROR;
  1099.         }
  1100.     /* prepare check disk parameters */
  1101.     
  1102.     if( (params & 0xff) == 0 )
  1103.      params |= DOS_CHK_ONLY;
  1104.     
  1105.     /* prevent attempts to write on read only volume */
  1106.     
  1107.     cbioIoctl(cbio, CBIO_STATUS_CHK, 0 );
  1108.     if( cbioModeGet(cbio) == O_RDONLY )
  1109.         {
  1110. /* avoid writing to O_RDONLY devices */
  1111.         params = (params & ~0xff) | DOS_CHK_ONLY;
  1112.         }
  1113.     pVolDesc->chkLevel = min( params & 0xff, DOS_CHK_REPAIR );
  1114.     pVolDesc->chkVerbLevel = 
  1115.          ( (params & 0xff00) == DOS_CHK_VERB_0 )? 0 : params >> 8;
  1116.     
  1117.     /* run disk check */
  1118.     
  1119.     retVal = dosFsChkRtn( pFd );
  1120.     
  1121.     if(params == ((params & ~0xff) | DOS_CHK_ONLY))
  1122.         {
  1123.         cbioIoctl( pVolDesc->pCbio, CBIO_CACHE_FLUSH, (void *)(-1) );
  1124.         cbioIoctl( pVolDesc->pCbio, CBIO_CACHE_INVAL, 0 );
  1125.         }
  1126.          
  1127.     pVolDesc->chkLevel = 0;
  1128.     pVolDesc->chkVerbLevel = 0;
  1129.          
  1130.     /* reset dcache driver to recount boot block checksum */
  1131.     if( TRUE == cbioRdyChgdGet (pVolDesc->pCbio) )
  1132.      {
  1133.      retVal = ERROR; /* volume was changed during check disk */
  1134.      }
  1135.     else
  1136.      {
  1137.       cbioIoctl( pVolDesc->pCbio, CBIO_RESET, NULL );
  1138.      }
  1139.          
  1140.     return retVal;
  1141.     } /* dosFsChkDsk() */
  1142. /*******************************************************************************
  1143. *
  1144. * dosFsBadBootMsg - print error message while boot sector parsing.
  1145. *
  1146. * RETURNS: N/A.
  1147. */
  1148. LOCAL void dosFsBadBootMsg
  1149.     (
  1150.     u_int dbgLevel,  /* message level */
  1151.     u_int offset, /* offset of invalid field */
  1152.     u_int val, /* invalid value */
  1153.     char * pExtraMsg, /* extra message */
  1154.     u_int line /* line number of error detecting code */
  1155.     )
  1156.     {
  1157. #ifdef DEBUG
  1158.     printErr( "%s : %u. Malformed boot sector. Offset %u, value %u. %sn",
  1159.            __FILE__, __LINE__, offset, val,
  1160.       ( (pExtraMsg == NULL)? " " : pExtraMsg ) );
  1161. #else /* not DEBUG */
  1162.     ERR_MSG( dbgLevel, "Malformed boot sector. Offset %u, value %u. %sn",
  1163.      offset, val, ( (pExtraMsg == NULL)? " " : pExtraMsg ), 0,0,0 ); 
  1164. #endif /* DEBUG */
  1165.     }
  1166.     
  1167. /*******************************************************************************
  1168. *
  1169. * dosFsBootSecGet - extract boot sector parameters.
  1170. *
  1171. * This routine reads boot sector from the disk and extracts
  1172. * current volume parameters from of it.
  1173. *
  1174. * This routine also performs sanity check of those volume parameters,
  1175. * that are mutually dependent or alternative.
  1176. * This routine also determines the FAT type: FAT32, FAT12, or FAT16.
  1177. *
  1178. * If read or damaged boot sector is encountered, this routine
  1179. * searches for backup copy of boot sector and accepts volume
  1180. * volume configuration from this copy.,
  1181. *
  1182. * RETURNS: OK or ERROR if disk read error or inconsistent
  1183. * boot sector data or failure to obtain cbio parameters.
  1184. *
  1185. * ERRNO:
  1186. * S_dosFsLib_UNKNOWN_VOLUME_FORMAT
  1187. */
  1188. LOCAL STATUS dosFsBootSecGet
  1189.     (
  1190.     DOS_VOLUME_DESC_ID pVolDesc /* pointer to volume descriptor */
  1191.     )
  1192.     {
  1193.     CBIO_PARAMS cbioParams;
  1194.     u_int work;
  1195.     u_char bootSec[ 512 ] = { 0 }; /* buffer for boot sector data */
  1196.     u_char pass = 0;
  1197.     u_char      tmpType [ DOS_BOOT_FSTYPE_LEN + 1] = { 0 };
  1198.     pVolDesc->bootSecNum = DOS_BOOT_SEC_NUM;  /* zero, per FAT standard */
  1199. boot_get:    
  1200.     /* reset the CBIO device in order to synchronize the boot sector */
  1201.     if( cbioIoctl(pVolDesc->pCbio, CBIO_RESET, 0 ) == ERROR )
  1202.      {
  1203.      return ERROR;
  1204.      }
  1205.     /* request the underlying CBIO device parameters */
  1206.     if (ERROR == cbioParamsGet (pVolDesc->pCbio, &cbioParams))
  1207. {
  1208. return (ERROR);
  1209. }
  1210.     /* ensure bytesPerBlk is non-zero */
  1211.     if (0 == cbioParams.bytesPerBlk)
  1212. {
  1213.      ERR_MSG( 1, "cbioParams.bytesPerBlk cannot be zero.n", 
  1214. 0,0,0,0,0,0 );
  1215.      if( TRUE == cbioRdyChgdGet (pVolDesc->pCbio) )
  1216.             {
  1217.     return (ERROR);
  1218.             }
  1219.      goto error;
  1220. }
  1221.     /* read relevant boot sector data into bootSec[] */
  1222.     work = min( cbioParams.bytesPerBlk, (int) sizeof(bootSec) );
  1223.     if( cbioBytesRW(pVolDesc->pCbio, pVolDesc->bootSecNum, 0 /* offset */,
  1224.                (addr_t)bootSec, work, CBIO_READ, NULL ) == ERROR ) 
  1225.      {
  1226.      ERR_MSG( 1, "ERROR reading the device boot sectorn", 0,0,0,0,0,0 );
  1227.      ERR_MSG( 1, "media not formatted or not presentn", 0,0,0,0,0,0 );
  1228.      if( TRUE == cbioRdyChgdGet (pVolDesc->pCbio) )
  1229.             {
  1230.     return (ERROR);
  1231.             }
  1232.      goto error;
  1233.      }
  1234.     /* check for both acceptable Intel 80x86 `jmp' opcodes */
  1235.     if( bootSec[ DOS_BOOT_JMP ] != 0xe9 && bootSec[ DOS_BOOT_JMP ] != 0xeb )
  1236.      {
  1237.      dosFsBadBootMsg( 1, DOS_BOOT_JMP, (u_int)bootSec[ DOS_BOOT_JMP ],
  1238.  NULL , __LINE__);
  1239.         goto error;
  1240.         }
  1241.     /* 
  1242.      * Many FAT documents mistakenly state that the 0x55aa signature word
  1243.      * "occupies the last two bytes of the boot sector".  That is only true 
  1244.      * when the bytes-per-sector value is 512 bytes.  Microsoft defines the 
  1245.      * signature at offsets 510 and 511 (zero-based) regardless of the sector 
  1246.      * size.  It is acceptable, however to have the signature at the end of the 
  1247.      * sector.  We shall accept either location. SPR#62415.
  1248.      */
  1249.     /* read the ending 2 bytes of the sector to check signature */
  1250.     if( cbioBytesRW(pVolDesc->pCbio, pVolDesc->bootSecNum,
  1251.             cbioParams.bytesPerBlk - 2 /* off */,
  1252.             (addr_t)&work, 2, CBIO_READ, NULL ) == ERROR ) 
  1253.         {
  1254.      ERR_MSG( 1, "ERROR reading boot sectorn", 0,0,0,0,0,0 );
  1255.      if( TRUE == cbioRdyChgdGet (pVolDesc->pCbio) )
  1256.             {
  1257.     return (ERROR);
  1258.             }
  1259.      goto error;
  1260.      }
  1261.     work = DISK_TO_VX_16( &work );
  1262.     if (0xaa55 != work) /* why have a back door? "&& (work != 0xface)") */
  1263.         {
  1264. /* 
  1265.  * We did not find the signature word at the end of the sector,
  1266.  * so we will check at the 510/511 offset per the Microsoft FAT spec. 
  1267.  * If we cannot find it there, then assume the boot sector is bad.
  1268.  */
  1269.         if ((bootSec[510] != 0x55) || (bootSec[511] != 0xaa))
  1270.     {
  1271.     dosFsBadBootMsg( 1, cbioParams.bytesPerBlk - 2,
  1272.      work, "At the end of boot sector", __LINE__ );
  1273.             goto error;
  1274.     }
  1275.         }
  1276.     /* 
  1277.      * Start filling out and verifying the volume descriptor fields 
  1278.      * using the data from the boot parameter block.  Evaluate the validity
  1279.      * of the data, so that dosFsVolIsFat12() may be safely called.
  1280.      */
  1281.     /* evaluate bytes per sector */
  1282.     
  1283.     work = DISK_TO_VX_16( bootSec + DOS_BOOT_BYTES_PER_SEC );
  1284.     pVolDesc->bytesPerSec = work;
  1285.     if( work == 0 )
  1286.      {
  1287.      dosFsBadBootMsg( 1, DOS_BOOT_BYTES_PER_SEC, work, NULL, __LINE__ );
  1288.      ERR_MSG(1, "bytesPerSec = 0n", 0,0,0,0,0,0 );
  1289.      goto error;
  1290.      }
  1291.     if( work != cbioParams.bytesPerBlk )
  1292.      {
  1293.         dosFsBadBootMsg( 1, DOS_BOOT_BYTES_PER_SEC, work, NULL, __LINE__ );
  1294.      ERR_MSG(1, "cbioParams.bytesPerBlk %u != bytes-per-sec %un", 
  1295.         cbioParams.bytesPerBlk, work, 0,0,0,0 );
  1296.      goto error;
  1297.      }
  1298.     /*
  1299.      * bytes-per-sector must be a power-of-two per Microsoft FAT specification 
  1300.      * and at least 32 bytes, so a shift is used instead of multiplication in 
  1301.      * operations with this value.
  1302.      */
  1303.     pVolDesc->secSizeShift = 0;
  1304.     for( work = 5; work < 16; work ++ )
  1305.      {
  1306.      if( (1 << work) == pVolDesc->bytesPerSec )
  1307.          {
  1308.          pVolDesc->secSizeShift = work;
  1309.          break;
  1310.          }
  1311.      }
  1312.     if( pVolDesc->secSizeShift == 0 )
  1313.      {
  1314.         dosFsBadBootMsg( 1, DOS_BOOT_BYTES_PER_SEC, 
  1315.  pVolDesc->bytesPerSec, NULL, __LINE__ );
  1316.      goto error;
  1317.      }
  1318.     
  1319.     /* evaluate the total number of sectors on this volume */
  1320.     
  1321.     work = DISK_TO_VX_16( bootSec + DOS_BOOT_NSECTORS );
  1322.     /* 
  1323.      * When the volume has at least 0x10000 sectors, the 16 bit field 
  1324.      * DOS_BOOT_NSECTORS is zero, and the alternate 32bit field 
  1325.      * DOS_BOOT_LONG_NSECTORS is used to determine the number of 
  1326.      * sectors on the volume.
  1327.      */
  1328.     if( work == 0 ) /* it is a large disk */
  1329.      {
  1330.      work = DISK_TO_VX_32( bootSec + DOS_BOOT_LONG_NSECTORS );
  1331.      if( work == 0 )
  1332.          {
  1333.          dosFsBadBootMsg( 1, DOS_BOOT_LONG_NSECTORS, work,
  1334.                              NULL, __LINE__ );
  1335.          goto error;
  1336.          }
  1337.      }
  1338.     pVolDesc->totalSec = work;
  1339.     
  1340.      /* number of sectors can be greater than cbioParams.nBlocks */
  1341.      
  1342.     if( work != cbioParams.nBlocks )
  1343.      {
  1344. /* 
  1345.  * XXX - An error here may indicate a problem with representing
  1346.  * a partition size correctly in the underlying CBIO layer.
  1347.          * 
  1348.          * Also, an off by one error may mean a driver bug.
  1349.          * cbioParams.nBlocks is the number of blocks on the 
  1350.          * CBIO device. Using the "last addressable LBA value"
  1351.          * in nBlocks can produce an off by one error, this is 
  1352.          * considered a driver problem.  bd_nBlocks shall be the 
  1353.          * number of blocks (1-xxx) not the last addressable block.  
  1354.          * Rather the driver should set nBlocks to the 
  1355.          * (last addressable block + 1).  DOSFS1 did not make this 
  1356.          * check.  DOSFS2 does make this check to avoid overrun.
  1357.  */
  1358.      if( work < cbioParams.nBlocks )
  1359.          {
  1360.          ERR_MSG(10, 
  1361. "WARNING: num-sectors %u < cbioParams.nBlocks %un",
  1362.          work, cbioParams.nBlocks, 0,0,0,0 );
  1363.          }
  1364.      else
  1365.          {
  1366.          dosFsBadBootMsg( 1, DOS_BOOT_LONG_NSECTORS, 0,
  1367.                              NULL, __LINE__ );
  1368.          ERR_MSG(1, "num-sectors %u > cbioParams.nBlocks %un", 
  1369.          work, cbioParams.nBlocks, 0,0,0,0 );
  1370.          goto error;
  1371.          }
  1372.      }
  1373.     
  1374.     /* evaluate the number of sectors per cluster */
  1375.     
  1376.     pVolDesc->secPerClust = bootSec[ DOS_BOOT_SEC_PER_CLUST ];
  1377.     if( pVolDesc->secPerClust == 0 )
  1378.      {
  1379.      dosFsBadBootMsg( 1, DOS_BOOT_SEC_PER_CLUST, 0,
  1380.                          NULL, __LINE__ );
  1381.      goto error;
  1382.      }
  1383.     
  1384.     /* evaluate the number of FAT copies */
  1385.     
  1386.     pVolDesc->nFats = bootSec[ DOS_BOOT_NFATS ];
  1387.     if( pVolDesc->nFats == 0 )
  1388.      {
  1389.      dosFsBadBootMsg( 1, DOS_BOOT_NFATS, 0, NULL, __LINE__ );
  1390.      goto error;
  1391.      }
  1392.     
  1393.     /* get the number of hidden sectors */
  1394.     
  1395.     pVolDesc->nHiddenSecs = DISK_TO_VX_16( bootSec + DOS_BOOT_NHIDDEN_SECS);
  1396.     
  1397.     /* evaluate the number of reserved sectors */
  1398.     
  1399.     pVolDesc->nReservedSecs = DISK_TO_VX_16( bootSec + DOS_BOOT_NRESRVD_SECS);
  1400.     if( pVolDesc->nReservedSecs == 0 )
  1401.      {
  1402.      dosFsBadBootMsg( 1, DOS_BOOT_NRESRVD_SECS, 0,
  1403.                          NULL, __LINE__ );
  1404.      goto error;
  1405.      }
  1406.     /* evaluate the number of sectors alloted to FAT table */
  1407.     pVolDesc->secPerFat = DISK_TO_VX_16( bootSec + DOS_BOOT_SEC_PER_FAT );
  1408.     /* 
  1409.      * Now determine the volumes FAT type.  FAT12, FAT16, and FAT32.
  1410.      * NOTE: The secPerFat field is zero on FAT32 DOSFS volumes. 
  1411.      * This is how we determine if FAT32 will be used when mounting 
  1412.      * this volume.  If secPerFat is zero, it must be FAT32.
  1413.      * Else, we need to pick between FAT12 and FAT16.
  1414.      */
  1415.     if( pVolDesc->secPerFat != 0 ) /* then using either FAT12 or FAT16 */
  1416.      {
  1417. /* 
  1418.  * The maximum number of 16 bit FAT entries is 65536. 
  1419.  * Anything greater is invalid.  Check here.
  1420.  */
  1421.     if( pVolDesc->secPerFat >  (ULONG)0x10000*2 / pVolDesc->bytesPerSec)
  1422.          {
  1423.          dosFsBadBootMsg( 1, DOS_BOOT_SEC_PER_FAT,
  1424.      pVolDesc->secPerFat, NULL, __LINE__ );
  1425.          ERR_MSG(1, "secPerFat 12/16 = %u, while BPS = %un",
  1426.           pVolDesc->secPerFat,pVolDesc->bytesPerSec,0,0,0,0 );
  1427.          goto error;
  1428.          }
  1429.     
  1430. /* 
  1431.  * Now we must decide if our volume is using FAT12 or FAT16.
  1432.  * If we choose the wrong FAT type, volume mounting will fail, 
  1433.  * and/or data corruption on the volume will occur when its exercised.
  1434.  * See also: SPR#34704.
  1435.  * We will also check the MS FSTYPE field (offset 0x36 in the 
  1436.  * boot sector) when determining the FAT type.  If either of the 
  1437.  * Microsoft defined strings exist, then we honor the boot sectors 
  1438.  * wisdom.  This presumes that the formatter of the volume knew what
  1439.  * they were doing when writing out these strings.  This may not
  1440.  * be the case, but its seems the most compatible approach.
  1441.  * The FSTYPE string field is also intentionaly being honored, so 
  1442.  * that either FAT type can be forced in the field.  In the event 
  1443.  * of a bad mount occuring in the field, a hack of writing the correct 
  1444.  * string to the BPB FSTYPE field would force the mount to the desired 
  1445.  * type.  Many DOS implementations do not set these strings and that 
  1446.  * is just fine.  Copy FSTYPE string to tmpType.
  1447.  */
  1448. bcopy ( (char *) bootSec + DOS_BOOT_FSTYPE_ID,
  1449.                 (char *) tmpType, DOS_BOOT_FSTYPE_LEN);
  1450. /* 
  1451.  * Now calculate the FAT type (FAT12 vs. FAT16) per a formula 
  1452.  * We warn the user when the FSTYPE string (if present) doesn't match 
  1453.  * the calculation.
  1454.  */
  1455.         work = dosFsVolIsFat12(bootSec);
  1456.         if (ERROR == work)
  1457.             {
  1458.          ERR_MSG(1, "dosFsVolIsFat12 returned ERRORn", 0,0,0,0,0,0 );
  1459.          goto error;
  1460.             }
  1461.      if (TRUE == work) /* then calculated FAT12 */
  1462.          {
  1463.     /* 
  1464.      * Check the FSTYPE field in the BPB to ensure the string
  1465.      * value matches our calculation.  If not, the we assume
  1466.      * the formatter knew what they wanted, and we honor
  1467.      * the string value. We look for "FAT12   " or "FAT16   ".
  1468.      */
  1469.     if ((strcmp ((char *)tmpType, DOS_BOOT_FSTYPE_FAT16)) == 0)
  1470.         {
  1471.              pVolDesc->fatType = FAT16;
  1472.         printf("WARNING: FAT16 indicated by BPB FSTYPE string, "
  1473.        "cluster calculation was FAT12. Honoring string.n");
  1474.         }
  1475.     else
  1476. {
  1477.              pVolDesc->fatType = FAT12;
  1478.      }
  1479.          }
  1480.      else /* we calculated FAT 16 */
  1481.          {
  1482.     /* 
  1483.      * Check the FSTYPE field in the BPB to ensure the string
  1484.      * value matches our calculation.  If not, the we assume
  1485.      * the formatter knew what they wanted, and we honor
  1486.      * the string value. We look for "FAT12   " or "FAT16   ".
  1487.      */
  1488.     if ((strcmp ((char *)tmpType, DOS_BOOT_FSTYPE_FAT12)) == 0)
  1489.         {
  1490.              pVolDesc->fatType = FAT12;
  1491.         printf("WARNING: FAT12 indicated by BPB FSTYPE string, "
  1492.        "cluster calculation was FAT16. Honoring string.n");
  1493.         }
  1494.     else
  1495. {
  1496.              pVolDesc->fatType = FAT16;
  1497.      }
  1498.          }
  1499.      /* volume Id and label */
  1500.     
  1501.      pVolDesc->volIdOff = DOS_BOOT_VOL_ID;
  1502.      pVolDesc->volLabOff = DOS_BOOT_VOL_LABEL;
  1503.      }
  1504.     else /* Use FAT32 because (pVolDesc->secPerFat == 0) */
  1505.      {
  1506.      pVolDesc->fatType = FAT32;
  1507.     
  1508.      /* sectors per fat copy */
  1509.     
  1510.      pVolDesc->secPerFat = DISK_TO_VX_32( bootSec +
  1511.           DOS32_BOOT_SEC_PER_FAT );
  1512.      if( pVolDesc->secPerFat == 0 )
  1513.          {
  1514.          dosFsBadBootMsg( 1, DOS32_BOOT_SEC_PER_FAT, 0,
  1515.                              "(FAT32)", __LINE__ );
  1516.          goto error;
  1517.          }
  1518.     
  1519.      /* volume Id and label */
  1520.     
  1521.      pVolDesc->volIdOff = DOS32_BOOT_VOL_ID;
  1522.      pVolDesc->volLabOff = DOS32_BOOT_VOL_LABEL;
  1523.      }
  1524.     
  1525.     /*
  1526.      * count sector number of data area start cluster.
  1527.      * This value can be corrected later by directory handler, if
  1528.      * root directory is not stored as regular directory
  1529.      * in clusters (FAT32), but instead resides contiguously
  1530.      * ahead first data cluster (FAT12/FAT16)
  1531.      */
  1532.     pVolDesc->dataStartSec = pVolDesc->nReservedSecs +
  1533.           pVolDesc->secPerFat * pVolDesc->nFats;
  1534.     
  1535.     /* volume Id and label */
  1536.     
  1537.     pVolDesc->volId = DISK_TO_VX_32( bootSec + pVolDesc->volIdOff );
  1538.     bcopy( (char *)bootSec + pVolDesc->volLabOff,
  1539.         (char *)pVolDesc->bootVolLab, DOS_VOL_LABEL_LEN );
  1540.     *(pVolDesc->bootVolLab + DOS_VOL_LABEL_LEN) = EOS;
  1541.           
  1542.     /* restore base version of boot sector */
  1543.     if( pVolDesc->bootSecNum != DOS_BOOT_SEC_NUM )
  1544.      {
  1545.      ERR_MSG( 1, "Try to reclaim original copy of boot sectorn",
  1546. 0,0,0,0,0,0 );
  1547.      if( (pass == 0) &&
  1548.             (cbioBlkCopy(pVolDesc->pCbio, pVolDesc->bootSecNum,
  1549. DOS_BOOT_SEC_NUM, 1 ) == OK) &&
  1550.          (cbioIoctl(pVolDesc->pCbio, 
  1551.        CBIO_CACHE_FLUSH, (void *)(-1) ) == OK))
  1552.          {
  1553.          /* remount again */
  1554.          pass ++;
  1555.          pVolDesc->bootSecNum = DOS_BOOT_SEC_NUM;
  1556.          goto boot_get;
  1557.          }
  1558.     }
  1559.     
  1560.     /* currently it is enough for starting */
  1561.     
  1562.     return (OK);
  1563.     
  1564. error: /* some data is inconsistent */
  1565.     pVolDesc->bootSecNum ++;
  1566.     if( pVolDesc->bootSecNum < (u_int)DOS_BOOT_SEC_NUM +
  1567.        cbioParams.blocksPerTrack )
  1568.      {
  1569.      /* try to find other boot block copy on next sector */
  1570.      if( pVolDesc->bootSecNum == DOS_BOOT_SEC_NUM + 1 )
  1571.          {
  1572.          ERR_MSG( 1, "Problem finding volume data, trying to "
  1573.                     "use the next block as boot block.n",
  1574.                0,0,0,0,0,0 );
  1575.             /* 
  1576.              * SPR#69074 - only look at the next sector, this avoids
  1577.              * tons of error messages when mounting unformatted device
  1578.              * when we used to look at the remaining sectors in the track.
  1579.              */
  1580.          goto boot_get;
  1581.          }
  1582.      ERR_MSG( 1, "Ensure this device is formatted and partitions are "
  1583.                     "properly handled.n",
  1584.                0,0,0,0,0,0 );
  1585.      }
  1586.     if( errnoGet() == OK )
  1587.      errnoSet( S_dosFsLib_UNKNOWN_VOLUME_FORMAT );
  1588.     return ERROR;
  1589.     } /* dosFsBootSecGet() */
  1590. /*******************************************************************************
  1591. *
  1592. * dosFsVolIsFat12 - determine if a MSDOS volume is FAT12 or FAT16
  1593. *
  1594. * This routine is the container for the logic which determines if a 
  1595. * dosFs volume is using FAT12 or FAT16.  Two methods are implemented. 
  1596. * Both methods use information from the volumes boot parameter block
  1597. * fields found in the boot sector.
  1598. *
  1599. * The first FAT determination method follows the recommendations outlined
  1600. * in the Microsoft document:
  1601. *
  1602. * "Hardware White Paper
  1603. *  Designing Hardware for Microsoft