Interix file and data access differs in some respects from that of UNIX becauseof the underlying Windows input/output system. Consequently, certain UNIX features are different or do not work in Interix.
This section discusses:
Differences in Interix and UNIX file I/O
The Interix ioctl() function implementation
Directory operations
File system operations in Interix
Interix does not support file I/O with memory caching turned off (O_DIRECT),and it also does not support the file I/O APIs listed in Table 10.13. Table 10.13 also provides code to implement the missing functions, if they are needed.
Function | Description | Suggested Interix Replacement |
---|---|---|
pread(fd, *buf, nbytes, offset) | Reads from a file descriptor at a given offset. | ssize_t pread(int fd, void *buf, |
pwrite(fd, *buf, nbytes, offset) | Writes to a file descriptor at a given offset. | ssize_t pwrite(int fd, const void |
The ioctl() interface has many uses. The POSIX.1 committee did not standardize the ioctl() interface because the last argument cannot be type-checked: Its type depends upon the request. Instead, the committee assigned pieces of functionality to other interfaces.
In other words, ioctl() does not have a single standard. Its arguments, returns, and semantics vary according to the device driver. The call is used for operations that do not cleanly fit the UNIX stream I/O model.
The ioctl() interface has historically been used to handle the following:
File control (See File Control and ioctl() in this section.)
Socket control (See Socket Control and ioctl() in this section.)
Disk labels
Magnetic tape control
Terminal control
The disk label and magnetic tape I/O requests are not supported in the Interix environment.
The SFU 3.0 API set contains only a few ioctl() operations, including window resizing. The following two sections explain some additional operations.
The only ioctl() requests defined for file control are FIONREAD, to get the number of bytes available to read, and FIONBIO, to set and unset nonblocking I/O.
The FIOCLEX and FIONCLEX requests (usually found in Filio.h) are not provided. They can be replaced with the fcntl() FD_CLOEXEC request, as shown in the following example:
#ifndef __INTERIX (void) ioctl(fd, FIOCLEX, NULL) #else (void) fcntl(fd, F_SETFL, fcntl(fd, F_GETFD) FD_CLOEXEC)); #endif
The only ioctl() request defined for sockets in Interix is SIOCATMARK. Other socket control requests are handled by using fcntl() or by using functions suchas setsockopt() .
Interix supports a subset of the routines used to access directory entries. Interix does not support the calls shown in Table 10.14 on the next page.
Function Name | Description | Suggested Interix Replacement |
---|---|---|
alphasort | Can be used as the comparison function for the scandir() function to sort the directory entries into alphabetical order. | Use readdir() to retrieve all entries, then sort as desired using the libc sort() or any other sorting function. |
getdents (fd, struct dirent*dirp, count) | Gets directory entries. | struct dirent * readdir (DIR *dirp) |
getdirentries | Getd directory entries in a file system system-independent format. | struct dirent * readdir (DIR *dirp) |
scandir | Scans a directory for matching entries. | readdir |
Because Interix does not support scandir , convert to using readdir . The example UNIX scandir Example below shows UNIX code using the scandir function, and the Interix readdir Conversion Example example that follows it shows how this code is converted to use readdir under Interix.
This example lists the contents of the current directory, demonstrating the useof the scandir function in UNIX:
#include <dirent.h> main() { struct dirent **namelist; int i, n; n = scandir(".", &namelist, 0, 0); if (n < 0) perror("scandir"); else { for (i=0; i<n; i++) { printf("%s\n", namelist[i]->d_name); free(namelist[n]); } free(namelist); } }
In Interix, you must change from using the scandir function to using the readdir function. The following code shows how to do this. In the scandir example, scandir is called once and returns the number of directory entries and a structure containing those entries. In contrast, the readdir function is called in a loop. Each time readdir is called, it returns a new directory entry until there are none left, and then it returns NULL.
#include <dirent.h> #include <stdio.h> main() { DIR *dp; struct dirent *entry; if((dp = opendir(".")) == NULL) perror("opendir"); else { while((entry = readdir(dp)) != NULL) printf("%s\n",entry->d_name); closedir(dp); } }
For other examples of UNIX code that ports to Interix without change, see Directory Scanning in Chapter 9, Win32 Code Conversion.
Interix does not support the routines to get the current working directory shownin Table 10.15.
Function Name | Description | Suggested Interix Replacement |
---|---|---|
get_current_dir_name | Gets current working directory | getcwd (buf, max) |
getwd | Gets current working directory | getcwd(buf, max) |
The getwd API as defined on BSD systems is particularly dangerous becauseit is vulnerable to buffer overrun attacks. Replace it with getcwd and a bufferof known size.
For an example of UNIX code that ports to Interix without change, see Working Directory in Chapter 9, Win32 Code Conversion.
Operations on file systems in Interix differ in a number of ways from file system operations under UNIX. Some functions are not supported, such as sync , sysfs , and ustat . Others have different parameters or use a different set of options for UNIX.
Table 10.16 lists the file system information functions that need to be replaced.
Function | Description | Suggested Interix Replacement |
---|---|---|
statfs, fstatfs | Get file system statistics. | statvfs |
sync | Writes all information in memory that should be on disk, including modified super blocks, modified inodes, and delayed block I/O. | No support or equivalent in Interix. |
sysfs | Gets file system type information. | statvfs |
ustat | Gets file system statistics. | Port to statfs first. |
The Windows NTFS file system is structured and implemented in such a way as to obviate the need for the sync function. NTFS uses a log-based mechanism to ensure that file system metadata (the equivalent of super blocks and inodes) are updated in sync with changes to file data. In the event of a system failure, automated NTFS file system recovery guarantees that either metadata corresponds to data appearing in files or the changes to the files never occurred. (This also eliminates the need for a utility like the UNIX fsck command.)
When using the statvfs function in Interix, be aware that the statfs structure has some members different from those usually found in UNIX. Table 10.17 summarizes these differences. In general, references to the statfs structure can by replaced with references to the statvfs structure.
UNIX statfs | Interix statvfs Structure | DescriptionStructure |
---|---|---|
long f_type | unsigned long f_type; | Type of file system. |
long f_bsize | unsigned long f_bsize; | Transfer block size. |
long f_blocks | unsigned long f_blocks; | Total data blocks in file system. |
long f_bfree | unsigned long f_bfree; | Free blocks in file system. |
long f_bavail | unsigned long f_bavail; | Free blocks available to non-superuser. |
long f_files | lunsigned ong f_files; | Total file nodes in file system. |
long f_ffree | unsigned long f_ffree; | Free file nodes in file system. |
fsid_t f_fsid | unsigned long f_fsid; | File system ID. |
long f_namelen | unsigned long f_namemax; | Maximum length of file names . |
long f_spare[6] | unsigned long f_flag; | Bit mask of values describing the file system. |
unsigned long f_frsize; | Fundamental block size. | |
unsigned long f_favail; | Total number of file serial numbers available to a nonprivileged process. | |
unsigned long f_iosize; | Optimal transfer block size. | |
char f_mntonname | Mountpoint for the file system. | |
char f_mntfromname | Mounted file system. |
When using statvfs , the file system types supported by Interix differ from those supported by most implementations of UNIX. The two lists below illustrate this by comparing a common subset of UNIX-supported file systems with those supported in Interix. It is rare for these differences to have any impact on the migration of an application.
§ AFFS_SUPER_MAGIC | 0xADFF |
§ EXT_SUPER_MAGIC | 0x137D |
§ EXT2_OLD_SUPER_MAGIC | 0xEF51 |
§ EXT2_SUPER_MAGIC | 0xEF53 |
§ HPFS_SUPER_MAGIC | 0xF995E849 |
§ ISOFS_SUPER_MAGIC | 0x9660 |
§ MINIX_SUPER_MAGIC | 0x137F /* orig. minix */ |
§ MINIX_SUPER_MAGIC2 | 0x138F /* 30 char minix */ |
§ MINIX2_SUPER_MAGIC | 0x2468 /* minix V2 */ |
§ MINIX2_SUPER_MAGIC2 | 0x2478 /* minix V2, 30 char names */ |
§ MSDOS_SUPER_MAGIC | 0x4d44 |
§ NCP_SUPER_MAGIC | 0x564c |
§ NFS_SUPER_MAGIC | 0x6969 |
§ PROC_SUPER_MAGIC | 0x9fa0 |
§ SMB_SUPER_MAGIC | 0x517B |
§ XENIX_SUPER_MAGIC | 0x012FF7B4 |
§ SYSV4_SUPER_MAGIC | 0x012FF7B5 |
§ SYSV2_SUPER_MAGIC | 0x012FF7B6 |
§ COH_SUPER_MAGIC | 0x012FF7B7 |
§ UFS_MAGIC | 0x00011954 |
§ XFS_SUPER_MAGIC | 0x58465342 |
§ _XIAFS_SUPER_MAGIC | 0x012FD16D |
§ ST_FSTYPE_UNKNOWN |
| /* unknown */ |
§ ST_FSTYPE_NTFS | 1 | /* NTFS */ |
§ ST_FSTYPE_OFS | 2 | /* OFS-NT object FS */ |
§ ST_FSTYPE_CDFS | 3 | |
§ ST_FSTYPE_CDROM | ST_FSTYPE_CDFS | |
§ ST_FSTYPE_ISO9660 | ST_FSTYPE_CDFS | |
§ ST_FSTYPE_FATFS | 4 | /* MS-DOS FAT FS */ |
§ ST_FSTYPE_MSDOS | ST_FSTYPE_FATFS | |
§ ST_FSTYPE_HPFS | 5 | /* OS2 HPFS */ |
§ ST_FSTYPE_SAMBA | 6 | /* Samba FS */ |
§ ST_FSTYPE_NFS | 8 | /* NFS */ |
§ ST_FSTYPE_MAX | 8 | /* for now */ |
Interix does not support dynamically mounted file systems, as UNIX does. Therefore, Interix does not include a file to define the mount table.
Mount tables are stored in different files on different implementations of UNIX. They are usually stored under the /etc directory and have names such as mtaband fstab or mnttab and vfstab.
This is unlikely to affect the migration of an application. However, if the application does use dynamically mounted file systems, remove the functionality and ensure that the file system is permanently mounted.
On UNIX systems, additional disk space is made available at some particular point in the file hierarchy by mounting a new disk volume onto a directory, or by replacing the directory with a symbolic link to some already mounted volume. The first operation can be performed in Windows through the use of the Windows Disk Management tool. This solution makes the additional space visible to Interixand Win32 applications. If your application environment doesn t require Win32 applications to see this additional space, you can instead replace the directorywith a symbolic link to any directory on any other volume on the system.
Applications still use the gdbm database (that is, an indexed file storage system), which is good at storing relatively static indexed data. The following APIs are used by an application that uses the gdbm database:
gdbm_close()
gdbm_delete()
gdbm_exists()
gdbm_fdesc()
gdbm_fetch()
gdbm_firstkey()
gdbm_nextkey()
gdbm_open()
gdbm_reorganize()
gdbm_setopt()
gdbm_store()
gdbm_strerror()
gdbm_sync()
An example of application code using these functions follows:
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <gdbm.h> #include <string.h> #define TEST_DB_FILE "/tmp/gdbmtest1" #define NUM_ITEMS 3 struct test_data { char some_chars[10]; int an_integer; char more_chars[21]; }; int main() { struct test_data data_to_store[NUM_ITEMS]; struct test_data item_retrieved; char key_to_use[20]; int i, result; datum key_datum; datum data_datum; GDBM_FILE gdbm_ptr; gdbm_ptr = gdbm_open(TEST_DB_FILE, 512, O_RDWR O_CREAT, 0666, 0); if (!gdbm_ptr) { fprintf(stderr, "Database Open Failed\n"); exit(EXIT_FAILURE); } /* put some data in the structures */ memset(data_to_store,