Close all vdi's before exit, by Daniel.
[vdi_driver.git] / src / fs.cpp
blobce78da47e523981fa19b0d3a3ef036d9a2dbeee6
1 #include "fs.h"
2 #include "const_defines.h"
3 #include "func_defines.h"
4 #include "path.h"
5 #include "RTErrConvertFromErrno.h"
6 #include "time.h"
7 #include <sys/statvfs.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <errno.h>
11 #include <cstdio>
12 #include <cstring>
13 #include <ctype.h>
15 /**
16 * Query the sizes of a filesystem.
18 * @returns iprt status code.
19 * @param pszFsPath Path within the mounted filesystem.
20 * @param pcbTotal Where to store the total filesystem space. (Optional)
21 * @param pcbFree Where to store the remaining free space in the filesystem. (Optional)
22 * @param pcbBlock Where to store the block size. (Optional)
23 * @param pcbSector Where to store the sector size. (Optional)
25 int RTFsQuerySizes(const char *pszFsPath, RTFOFF *pcbTotal, RTFOFF *pcbFree,
26 uint32_t *pcbBlock, uint32_t *pcbSector)
29 * Validate input.
31 AssertMsgReturn(VALID_PTR(pszFsPath) && *pszFsPath, ("%p", pszFsPath), VERR_INVALID_PARAMETER);
34 * Convert the path and query the information.
36 char *pszNativeFsPath;
37 int rc = rtPathToNative(&pszNativeFsPath, pszFsPath);
38 if (RT_SUCCESS(rc))
40 /** @todo I'm not quite sure if statvfs was properly specified by SuS, I have to check my own
41 * implementation and FreeBSD before this can eventually be promoted to posix. */
42 struct statvfs StatVFS = {0};
43 if (!statvfs(pszNativeFsPath, &StatVFS))
46 * Calc the returned values.
48 if (pcbTotal)
49 *pcbTotal = (RTFOFF)StatVFS.f_blocks * StatVFS.f_frsize;
50 if (pcbFree)
51 *pcbFree = (RTFOFF)StatVFS.f_bavail * StatVFS.f_frsize;
52 if (pcbBlock)
53 *pcbBlock = StatVFS.f_frsize;
54 /* no idea how to get the sector... */
55 if (pcbSector)
56 *pcbSector = 512;
58 else
59 rc = RTErrConvertFromErrno(errno);
60 rtPathFreeNative(pszNativeFsPath);
63 printf("RTFsQuerySizes(%p:{%s}, %p:{%RTfoff}, %p:{%RTfoff}, %p:{%RX32}, %p:{%RX32}): returns %Rrc\n",
64 pszFsPath, pszFsPath, pcbTotal, pcbTotal ? *pcbTotal : 0, pcbFree, pcbFree ? *pcbFree : 0,
65 pcbBlock, pcbBlock ? *pcbBlock : 0, pcbSector, pcbSector ? *pcbSector : 0, rc);
66 return rc;
69 /**
70 * Internal worker function which setups RTFSOBJINFO based on a UNIX stat struct.
72 * @param pObjInfo The file system object info structure to setup.
73 * @param pStat The stat structure to use.
75 void rtFsConvertStatToObjInfo(PRTFSOBJINFO pObjInfo, const struct stat *pStat, const char *pszName, unsigned cbName)
77 pObjInfo->cbObject = pStat->st_size;
78 pObjInfo->cbAllocated = pStat->st_size;
80 #ifdef HAVE_STAT_NSEC
81 RTTimeSpecAddNano(RTTimeSpecSetSeconds(&pObjInfo->AccessTime, pStat->st_atime), pStat->st_atimensec);
82 RTTimeSpecAddNano(RTTimeSpecSetSeconds(&pObjInfo->ModificationTime, pStat->st_mtime), pStat->st_mtimensec);
83 RTTimeSpecAddNano(RTTimeSpecSetSeconds(&pObjInfo->ChangeTime, pStat->st_ctime), pStat->st_ctimensec);
84 #ifdef HAVE_STAT_BIRTHTIME
85 RTTimeSpecAddNano(RTTimeSpecSetSeconds(&pObjInfo->BirthTime, pStat->st_birthtime), pStat->st_birthtimensec);
86 #endif
88 #elif defined(HAVE_STAT_TIMESPEC_BRIEF)
89 RTTimeSpecSetTimespec(&pObjInfo->AccessTime, &pStat->st_atim);
90 RTTimeSpecSetTimespec(&pObjInfo->ModificationTime, &pStat->st_mtim);
91 RTTimeSpecSetTimespec(&pObjInfo->ChangeTime, &pStat->st_ctim);
92 # ifdef HAVE_STAT_BIRTHTIME
93 RTTimeSpecSetTimespec(&pObjInfo->BirthTime, &pStat->st_birthtim);
94 # endif
96 #elif defined(HAVE_STAT_TIMESPEC)
97 RTTimeSpecSetTimespec(&pObjInfo->AccessTime, pStat->st_atimespec);
98 RTTimeSpecSetTimespec(&pObjInfo->ModificationTime, pStat->st_mtimespec);
99 RTTimeSpecSetTimespec(&pObjInfo->ChangeTime, pStat->st_ctimespec);
100 # ifdef HAVE_STAT_BIRTHTIME
101 RTTimeSpecSetTimespec(&pObjInfo->BirthTime, pStat->st_birthtimespec);
102 # endif
104 #else /* just the normal stuff */
105 RTTimeSpecSetSeconds(&pObjInfo->AccessTime, pStat->st_atime);
106 RTTimeSpecSetSeconds(&pObjInfo->ModificationTime, pStat->st_mtime);
107 RTTimeSpecSetSeconds(&pObjInfo->ChangeTime, pStat->st_ctime);
108 # ifdef HAVE_STAT_BIRTHTIME
109 RTTimeSpecSetSeconds(&pObjInfo->BirthTime, pStat->st_birthtime);
110 # endif
111 #endif
112 #ifndef HAVE_STAT_BIRTHTIME
113 pObjInfo->BirthTime = pObjInfo->ChangeTime;
114 #endif
117 /* the file mode */
118 RTFMODE fMode = pStat->st_mode & RTFS_UNIX_MASK;
119 Assert(RTFS_UNIX_ISUID == S_ISUID);
120 Assert(RTFS_UNIX_ISGID == S_ISGID);
121 Assert(RTFS_UNIX_ISTXT == S_ISTXT);
122 Assert(RTFS_UNIX_ISTXT == S_ISVTX);
123 Assert(RTFS_UNIX_IRWXU == S_IRWXU);
124 Assert(RTFS_UNIX_IRUSR == S_IRUSR);
125 Assert(RTFS_UNIX_IWUSR == S_IWUSR);
126 Assert(RTFS_UNIX_IXUSR == S_IXUSR);
127 Assert(RTFS_UNIX_IRWXG == S_IRWXG);
128 Assert(RTFS_UNIX_IRGRP == S_IRGRP);
129 Assert(RTFS_UNIX_IWGRP == S_IWGRP);
130 Assert(RTFS_UNIX_IXGRP == S_IXGRP);
131 Assert(RTFS_UNIX_IRWXO == S_IRWXO);
132 Assert(RTFS_UNIX_IROTH == S_IROTH);
133 Assert(RTFS_UNIX_IWOTH == S_IWOTH);
134 Assert(RTFS_UNIX_IXOTH == S_IXOTH);
135 Assert(RTFS_TYPE_FIFO == S_IFIFO);
136 Assert(RTFS_TYPE_DEV_CHAR == S_IFCHR);
137 Assert(RTFS_TYPE_DIRECTORY == S_IFDIR);
138 Assert(RTFS_TYPE_DEV_BLOCK == S_IFBLK);
139 Assert(RTFS_TYPE_FILE == S_IFREG);
140 Assert(RTFS_TYPE_SYMLINK == S_IFLNK);
141 Assert(RTFS_TYPE_SOCKET == S_IFSOCK);
142 #ifdef S_IFWHT
143 Assert(RTFS_TYPE_WHITEOUT == S_IFWHT);
144 #endif
145 Assert(RTFS_TYPE_MASK == S_IFMT);
147 pObjInfo->Attr.fMode = rtFsModeFromUnix(fMode, pszName, cbName);
149 /* additional unix attribs */
150 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
151 pObjInfo->Attr.u.Unix.uid = pStat->st_uid;
152 pObjInfo->Attr.u.Unix.gid = pStat->st_gid;
153 pObjInfo->Attr.u.Unix.cHardlinks = pStat->st_nlink;
154 pObjInfo->Attr.u.Unix.INodeIdDevice = pStat->st_dev;
155 pObjInfo->Attr.u.Unix.INodeId = pStat->st_ino;
156 #ifdef HAVE_STAT_FLAGS
157 pObjInfo->Attr.u.Unix.fFlags = pStat->st_flags;
158 #else
159 pObjInfo->Attr.u.Unix.fFlags = 0;
160 #endif
161 #ifdef HAVE_STAT_GEN
162 pObjInfo->Attr.u.Unix.GenerationId = pStat->st_gen;
163 #else
164 pObjInfo->Attr.u.Unix.GenerationId = 0;
165 #endif
166 pObjInfo->Attr.u.Unix.Device = pStat->st_rdev;
170 * Converts dos-style attributes to Unix attributes.
172 * @returns Normalized file mode.
173 * @param fMode The mode mask containing dos-style attibutes only.
174 * @param pszName The filename which this applies to (exe check).
175 * @param cbName The length of that filename. (optional, set 0)
177 RTFMODE rtFsModeNormalize(RTFMODE fMode, const char *pszName, unsigned cbName)
179 if (!(fMode & RTFS_UNIX_MASK))
180 rtFsModeFromDos(fMode, pszName, cbName);
181 else if (!(fMode & RTFS_DOS_MASK))
182 rtFsModeFromUnix(fMode, pszName, cbName);
183 else if (!(fMode & RTFS_TYPE_MASK))
184 fMode |= fMode & RTFS_DOS_DIRECTORY ? RTFS_TYPE_DIRECTORY : RTFS_TYPE_FILE;
185 else if (RTFS_IS_DIRECTORY(fMode))
186 fMode |= RTFS_DOS_DIRECTORY;
187 return fMode;
191 * Checks if the file mode is valid or not.
193 * @return true if valid.
194 * @return false if invalid, done bitching.
195 * @param fMode The file mode.
197 bool rtFsModeIsValid(RTFMODE fMode)
199 AssertMsgReturn( (!RTFS_IS_DIRECTORY(fMode) && !(fMode & RTFS_DOS_DIRECTORY))
200 || (RTFS_IS_DIRECTORY(fMode) && (fMode & RTFS_DOS_DIRECTORY)),
201 ("%RTfmode\n", fMode), false);
202 AssertMsgReturn(RTFS_TYPE_MASK & fMode,
203 ("%RTfmode\n", fMode), false);
204 /** @todo more checks! */
205 return true;
209 * Converts Unix attributes to Dos-style attributes.
211 * @returns
212 * @param fMode The mode mask containing dos-style attibutes only.
214 RTFMODE rtFsModeFromUnix(RTFMODE fMode, const char *pszName, unsigned cbName)
216 fMode &= RTFS_UNIX_MASK;
218 if (!(fMode & (RTFS_UNIX_IWUSR | RTFS_UNIX_IWGRP | RTFS_UNIX_IWOTH)))
219 fMode |= RTFS_DOS_READONLY;
220 if (RTFS_IS_DIRECTORY(fMode))
221 fMode |= RTFS_DOS_DIRECTORY;
222 if (!(fMode & RTFS_DOS_MASK))
223 fMode |= RTFS_DOS_NT_NORMAL;
224 if (!(fMode & RTFS_DOS_HIDDEN) && pszName)
226 pszName = RTPathFilename(pszName);
227 if (pszName && *pszName == '.')
228 fMode |= RTFS_DOS_HIDDEN;
230 return fMode;
234 * Converts dos-style attributes to Unix attributes.
236 * @returns
237 * @param fMode The mode mask containing dos-style attibutes only.
238 * @param pszName The filename which this applies to (exe check).
239 * @param cbName The length of that filename. (optional, set 0)
241 RTFMODE rtFsModeFromDos(RTFMODE fMode, const char *pszName, unsigned cbName)
243 fMode &= ~((1 << RTFS_DOS_SHIFT) - 1);
245 /* everything is readable. */
246 fMode |= RTFS_UNIX_IRUSR | RTFS_UNIX_IRGRP | RTFS_UNIX_IROTH;
247 if (fMode & RTFS_DOS_DIRECTORY)
248 /* directories are executable. */
249 fMode |= RTFS_TYPE_DIRECTORY | RTFS_UNIX_IXUSR | RTFS_UNIX_IXGRP | RTFS_UNIX_IXOTH;
250 else
252 fMode |= RTFS_TYPE_FILE;
253 if (!cbName && pszName)
254 cbName = strlen(pszName);
255 if (cbName >= 4 && pszName[cbName - 4] == '.')
257 /* check for executable extension. */
258 const char *pszExt = &pszName[cbName - 3];
259 char szExt[4];
260 szExt[0] = tolower(pszExt[0]);
261 szExt[1] = tolower(pszExt[1]);
262 szExt[2] = tolower(pszExt[2]);
263 szExt[3] = '\0';
264 if ( !memcmp(szExt, "exe", 4)
265 || !memcmp(szExt, "bat", 4)
266 || !memcmp(szExt, "com", 4)
267 || !memcmp(szExt, "cmd", 4)
268 || !memcmp(szExt, "btm", 4)
270 fMode |= RTFS_UNIX_IXUSR | RTFS_UNIX_IXGRP | RTFS_UNIX_IXOTH;
273 /* writable? */
274 if (!(fMode & RTFS_DOS_READONLY))
275 fMode |= RTFS_UNIX_IWUSR | RTFS_UNIX_IWGRP | RTFS_UNIX_IWOTH;
276 return fMode;