ef1d488b286c86439fc94846f87a73539ece1481
[platform/upstream/coreclr.git] / src / pal / src / file / disk.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 /*++
6
7
8
9 Module Name:
10
11     disk.c
12
13 Abstract:
14
15     Implementation of the disk information functions.
16
17 Revision History:
18
19
20
21 --*/
22
23 #include "pal/palinternal.h"
24 #include "pal/dbgmsg.h"
25 #include "pal/file.h"
26 #include "pal/stackstring.hpp"
27
28 #include <sys/param.h>
29 #if !defined(_AIX)
30 // do we actually need this on other platforms. We don't seem to be using anything from there
31 #include <sys/mount.h>
32 #endif
33 #include <errno.h>
34 #if HAVE_STATVFS
35 #include <sys/types.h>
36 #include <sys/statvfs.h>
37 #define statfs  statvfs
38 #if STATVFS64_PROTOTYPE_BROKEN
39 typedef statvfs_t pal_statfs;
40 #else // STATVFS64_PROTOTYPE_BROKEN
41 typedef struct statvfs pal_statfs;
42 #endif // STATVFS64_PROTOTYPE_BROKEN
43 #else // HAVE_STATVFS
44 typedef struct statfs pal_statfs;
45 #endif  // HAVE_STATVFS
46
47 SET_DEFAULT_DEBUG_CHANNEL(FILE);
48
49 /*++
50
51 Function:
52
53     GetDiskFreeSpaceW
54     
55 See MSDN doc.
56 --*/
57 PALIMPORT
58 BOOL
59 PALAPI
60 GetDiskFreeSpaceW(
61           LPCWSTR lpDirectoryName,
62           LPDWORD lpSectorsPerCluster,
63           LPDWORD lpBytesPerSector,
64           LPDWORD lpNumberOfFreeClusters,  /* Caller will ignore output value */
65           LPDWORD lpTotalNumberOfClusters) /* Caller will ignore output value */
66 {
67     BOOL bRetVal = FALSE;
68     pal_statfs fsInfoBuffer;
69     INT  statfsRetVal = 0;
70     DWORD dwLastError = NO_ERROR;
71     PathCharString dirNameBufferPathString;
72     size_t length;
73     char * dirNameBuffer;
74     int size;
75
76     PERF_ENTRY(GetDiskFreeSpaceW);
77     ENTRY( "GetDiskFreeSpaceW( lpDirectoryName=%p (%S), lpSectorsPerCluster=%p,"
78            "lpBytesPerSector=%p, lpNumberOfFreeClusters=%p, "
79            "lpTotalNumberOfClusters=%p )\n", lpDirectoryName ? lpDirectoryName :
80             W16_NULLSTRING, lpDirectoryName ? lpDirectoryName :
81             W16_NULLSTRING, lpSectorsPerCluster, lpBytesPerSector, 
82             lpNumberOfFreeClusters, lpTotalNumberOfClusters );
83
84     /* Sanity checks. */
85     if ( !lpSectorsPerCluster )
86     {
87         ERROR( "lpSectorsPerCluster cannot be NULL!\n" );
88         dwLastError = ERROR_INVALID_PARAMETER;
89         goto exit;
90     }
91     if ( !lpBytesPerSector )
92     {
93         ERROR( "lpBytesPerSector cannot be NULL!\n" );
94         dwLastError = ERROR_INVALID_PARAMETER;
95         goto exit;
96     }
97     if ( lpNumberOfFreeClusters || lpTotalNumberOfClusters )
98     {
99         TRACE("GetDiskFreeSpaceW is ignoring lpNumberOfFreeClusters"
100               " and lpTotalNumberOfClusters\n" );
101     }
102     if ( lpDirectoryName && PAL_wcslen( lpDirectoryName ) == 0 )
103     {
104         ERROR( "lpDirectoryName is empty.\n" );
105         dwLastError = ERROR_INVALID_PARAMETER;
106         goto exit;
107     }
108
109     /* Fusion uses this API to round file sizes up to their actual size
110        on-disk based on the BytesPerSector * SectorsPerCluster.
111        The intent is to avoid computing the sum of all file sizes in the
112        cache just in bytes and not account for the cluster-sized slop, when
113        determining if the cache is too large or not. */
114
115     if ( lpDirectoryName )
116     {
117         length = (PAL_wcslen(lpDirectoryName)+1) * 3;
118         dirNameBuffer = dirNameBufferPathString.OpenStringBuffer(length);
119         if (NULL == dirNameBuffer)
120         {
121             dwLastError = ERROR_NOT_ENOUGH_MEMORY;
122             goto exit;
123         }
124
125         size = WideCharToMultiByte( CP_ACP, 0, lpDirectoryName, -1,
126                                   dirNameBuffer,length, 0, 0 );
127         dirNameBufferPathString.CloseBuffer(size);
128         if ( size != 0 )
129         {
130             FILEDosToUnixPathA( dirNameBuffer );
131             statfsRetVal = statfs( dirNameBuffer, &fsInfoBuffer );
132         }
133         else
134         {
135             ASSERT( "Unable to convert the lpDirectoryName to multibyte.\n" );
136             dwLastError = ERROR_INTERNAL_ERROR;
137             goto exit;
138         }
139     }
140     else
141     {
142         statfsRetVal = statfs( "/", &fsInfoBuffer );
143     }
144
145     if ( statfsRetVal == 0 )
146     {
147         *lpBytesPerSector = fsInfoBuffer.f_bsize;
148         *lpSectorsPerCluster = 1;
149         bRetVal = TRUE;
150     }
151     else
152     {
153         if ( errno == ENOTDIR || errno == ENOENT )
154         {
155             FILEGetProperNotFoundError( dirNameBuffer, &dwLastError );
156             goto exit;
157         }
158         dwLastError = FILEGetLastErrorFromErrno();
159         if ( ERROR_INTERNAL_ERROR == dwLastError )
160         {
161             ASSERT("statfs() not expected to fail with errno:%d (%s)\n", 
162                    errno, strerror(errno));
163         }
164         else
165         {
166             TRACE("statfs() failed, errno:%d (%s)\n", errno, strerror(errno));
167         }
168     }
169
170 exit:
171     if ( NO_ERROR != dwLastError )
172     {
173         SetLastError( dwLastError );
174     }
175
176     LOGEXIT( "GetDiskFreeSpace returning %s.\n", bRetVal == TRUE ? "TRUE" : "FALSE" );
177     PERF_EXIT(GetDiskFreeSpaceW);
178     return bRetVal;
179 }
180