1+ using Google . Apis . Drive . v3 ;
12using System ;
23using System . Collections . Generic ;
34using System . IO ;
5+ using System . IO . Pipelines ;
46using System . Linq ;
57using System . Runtime . CompilerServices ;
68using System . Threading ;
79using System . Threading . Tasks ;
8- using System . IO . Pipelines ;
9- using Google . Apis . Drive . v3 ;
1010using DriveFile = Google . Apis . Drive . v3 . Data . File ;
1111
1212namespace ManagedCode . Storage . GoogleDrive . Clients ;
@@ -27,9 +27,9 @@ public Task EnsureRootAsync(string rootFolderId, bool createIfNotExists, Cancell
2727 return Task . CompletedTask ;
2828 }
2929
30- public async Task < DriveFile > UploadAsync ( string rootFolderId , string path , Stream content , string ? contentType , CancellationToken cancellationToken )
30+ public async Task < DriveFile > UploadAsync ( string rootFolderId , string path , Stream content , string ? contentType , bool supportsAllDrives , CancellationToken cancellationToken )
3131 {
32- var ( parentId , fileName ) = await EnsureParentFolderAsync ( rootFolderId , path , cancellationToken ) ;
32+ var ( parentId , fileName ) = await EnsureParentFolderAsync ( rootFolderId , path , supportsAllDrives , cancellationToken ) ;
3333
3434 var fileMetadata = new DriveFile
3535 {
@@ -39,20 +39,24 @@ public async Task<DriveFile> UploadAsync(string rootFolderId, string path, Strea
3939
4040 var request = _driveService . Files . Create ( fileMetadata , content , contentType ?? "application/octet-stream" ) ;
4141 request . Fields = "id,name,parents,createdTime,modifiedTime,md5Checksum,size" ;
42+ request . SupportsAllDrives = supportsAllDrives ;
4243 await request . UploadAsync ( cancellationToken ) ;
4344 return request . ResponseBody ?? throw new InvalidOperationException ( "Google Drive upload returned no metadata." ) ;
4445 }
4546
46- public async Task < Stream > DownloadAsync ( string rootFolderId , string path , CancellationToken cancellationToken )
47+ public async Task < Stream > DownloadAsync ( string rootFolderId , string path , bool supportsAllDrives , CancellationToken cancellationToken )
4748 {
48- var file = await FindFileByPathAsync ( rootFolderId , path , cancellationToken ) ?? throw new FileNotFoundException ( path ) ;
49+ var file = await FindFileByPathAsync ( rootFolderId , path , supportsAllDrives , cancellationToken ) ?? throw new FileNotFoundException ( path ) ;
4950 var pipe = new Pipe ( ) ;
51+ var getRequest = _driveService . Files . Get ( file . Id ) ;
52+ getRequest . SupportsAllDrives = supportsAllDrives ;
53+
5054 _ = Task . Run ( async ( ) =>
5155 {
5256 try
5357 {
5458 await using var destination = pipe . Writer . AsStream ( leaveOpen : true ) ;
55- await _driveService . Files . Get ( file . Id ) . DownloadAsync ( destination , cancellationToken ) ;
59+ await getRequest . DownloadAsync ( destination , cancellationToken ) ;
5660 pipe . Writer . Complete ( ) ;
5761 }
5862 catch ( Exception ex )
@@ -64,29 +68,29 @@ public async Task<Stream> DownloadAsync(string rootFolderId, string path, Cancel
6468 return pipe . Reader . AsStream ( ) ;
6569 }
6670
67- public async Task < bool > DeleteAsync ( string rootFolderId , string path , CancellationToken cancellationToken )
71+ public async Task < bool > DeleteAsync ( string rootFolderId , string path , bool supportsAllDrives , CancellationToken cancellationToken )
6872 {
69- var file = await FindFileByPathAsync ( rootFolderId , path , cancellationToken ) ;
73+ var file = await FindFileByPathAsync ( rootFolderId , path , supportsAllDrives , cancellationToken ) ;
7074 if ( file == null )
7175 {
7276 return false ;
7377 }
7478
75- await DeleteRecursiveAsync ( file . Id , file . MimeType , cancellationToken ) ;
79+ await DeleteRecursiveAsync ( file . Id , file . MimeType , supportsAllDrives , cancellationToken ) ;
7680 return true ;
7781 }
7882
79- public async Task < bool > ExistsAsync ( string rootFolderId , string path , CancellationToken cancellationToken )
83+ public async Task < bool > ExistsAsync ( string rootFolderId , string path , bool supportsAllDrives , CancellationToken cancellationToken )
8084 {
81- return await FindFileByPathAsync ( rootFolderId , path , cancellationToken ) != null ;
85+ return await FindFileByPathAsync ( rootFolderId , path , supportsAllDrives , cancellationToken ) != null ;
8286 }
8387
84- public Task < DriveFile ? > GetMetadataAsync ( string rootFolderId , string path , CancellationToken cancellationToken )
88+ public Task < DriveFile ? > GetMetadataAsync ( string rootFolderId , string path , bool supportsAllDrives , CancellationToken cancellationToken )
8589 {
86- return FindFileByPathAsync ( rootFolderId , path , cancellationToken ) ;
90+ return FindFileByPathAsync ( rootFolderId , path , supportsAllDrives , cancellationToken ) ;
8791 }
8892
89- public async IAsyncEnumerable < DriveFile > ListAsync ( string rootFolderId , string ? directory , [ EnumeratorCancellation ] CancellationToken cancellationToken )
93+ public async IAsyncEnumerable < DriveFile > ListAsync ( string rootFolderId , string ? directory , bool supportsAllDrives , [ EnumeratorCancellation ] CancellationToken cancellationToken )
9094 {
9195 string parentId ;
9296 if ( string . IsNullOrWhiteSpace ( directory ) )
@@ -95,15 +99,19 @@ public async IAsyncEnumerable<DriveFile> ListAsync(string rootFolderId, string?
9599 }
96100 else
97101 {
98- parentId = await EnsureFolderPathAsync ( rootFolderId , directory ! , false , cancellationToken ) ?? string . Empty ;
102+ parentId = await EnsureFolderPathAsync ( rootFolderId , directory ! , false , supportsAllDrives , cancellationToken ) ?? string . Empty ;
99103 if ( string . IsNullOrWhiteSpace ( parentId ) )
100104 {
101105 yield break ;
102106 }
103107 }
104108
105109 var request = _driveService . Files . List ( ) ;
110+ request . SupportsAllDrives = supportsAllDrives ;
111+ request . IncludeItemsFromAllDrives = supportsAllDrives ;
112+
106113 request . Q = $ "'{ parentId } ' in parents and trashed=false";
114+
107115 request . Fields = "nextPageToken,files(id,name,parents,createdTime,modifiedTime,md5Checksum,size,mimeType)" ;
108116
109117 do
@@ -119,7 +127,7 @@ public async IAsyncEnumerable<DriveFile> ListAsync(string rootFolderId, string?
119127 } while ( ! string . IsNullOrEmpty ( request . PageToken ) ) ;
120128 }
121129
122- private async Task < ( string ParentId , string Name ) > EnsureParentFolderAsync ( string rootFolderId , string fullPath , CancellationToken cancellationToken )
130+ private async Task < ( string ParentId , string Name ) > EnsureParentFolderAsync ( string rootFolderId , string fullPath , bool supportsAllDrives , CancellationToken cancellationToken )
123131 {
124132 var normalizedPath = fullPath . Replace ( "\\ " , "/" ) . Trim ( '/' ) ;
125133 var segments = normalizedPath . Split ( '/' , StringSplitOptions . RemoveEmptyEntries ) ;
@@ -129,16 +137,16 @@ public async IAsyncEnumerable<DriveFile> ListAsync(string rootFolderId, string?
129137 }
130138
131139 var parentPath = string . Join ( '/' , segments . Take ( segments . Length - 1 ) ) ;
132- var parentId = await EnsureFolderPathAsync ( rootFolderId , parentPath , true , cancellationToken ) ?? rootFolderId ;
140+ var parentId = await EnsureFolderPathAsync ( rootFolderId , parentPath , true , supportsAllDrives , cancellationToken ) ?? rootFolderId ;
133141 return ( parentId , segments . Last ( ) ) ;
134142 }
135143
136- private async Task < string ? > EnsureFolderPathAsync ( string rootFolderId , string path , bool createIfMissing , CancellationToken cancellationToken )
144+ private async Task < string ? > EnsureFolderPathAsync ( string rootFolderId , string path , bool createIfMissing , bool supportsAllDrives , CancellationToken cancellationToken )
137145 {
138146 var currentId = rootFolderId ;
139147 foreach ( var segment in path . Split ( '/' , StringSplitOptions . RemoveEmptyEntries ) )
140148 {
141- var folder = await FindChildAsync ( currentId , segment , cancellationToken ) ;
149+ var folder = await FindChildAsync ( currentId , segment , supportsAllDrives , cancellationToken ) ;
142150 if ( folder == null )
143151 {
144152 if ( ! createIfMissing )
@@ -147,7 +155,9 @@ public async IAsyncEnumerable<DriveFile> ListAsync(string rootFolderId, string?
147155 }
148156
149157 var metadata = new DriveFile { Name = segment , MimeType = "application/vnd.google-apps.folder" , Parents = new List < string > { currentId } } ;
150- folder = await _driveService . Files . Create ( metadata ) . ExecuteAsync ( cancellationToken ) ;
158+ var createRequest = _driveService . Files . Create ( metadata ) ;
159+ createRequest . SupportsAllDrives = supportsAllDrives ;
160+ folder = await createRequest . ExecuteAsync ( cancellationToken ) ;
151161 }
152162
153163 currentId = folder . Id ;
@@ -156,32 +166,38 @@ public async IAsyncEnumerable<DriveFile> ListAsync(string rootFolderId, string?
156166 return currentId ;
157167 }
158168
159- private async Task < DriveFile ? > FindChildAsync ( string parentId , string name , CancellationToken cancellationToken )
169+ private async Task < DriveFile ? > FindChildAsync ( string parentId , string name , bool supportsAllDrives , CancellationToken cancellationToken )
160170 {
161171 var request = _driveService . Files . List ( ) ;
162172 request . Q = $ "'{ parentId } ' in parents and name='{ name } ' and trashed=false";
163173 request . Fields = "files(id,name,parents,createdTime,modifiedTime,md5Checksum,size,mimeType)" ;
174+ request . SupportsAllDrives = supportsAllDrives ;
175+ request . IncludeItemsFromAllDrives = supportsAllDrives ;
164176 var response = await request . ExecuteAsync ( cancellationToken ) ;
165177 return response . Files ? . FirstOrDefault ( ) ;
166178 }
167179
168- private async Task DeleteRecursiveAsync ( string fileId , string ? mimeType , CancellationToken cancellationToken )
180+ private async Task DeleteRecursiveAsync ( string fileId , string ? mimeType , bool supportsAllDrives , CancellationToken cancellationToken )
169181 {
170182 cancellationToken . ThrowIfCancellationRequested ( ) ;
171183
172184 if ( string . Equals ( mimeType , FolderMimeType , StringComparison . OrdinalIgnoreCase ) )
173185 {
174- await DeleteFolderChildrenAsync ( fileId , cancellationToken ) ;
186+ await DeleteFolderChildrenAsync ( fileId , supportsAllDrives , cancellationToken ) ;
175187 }
176188
177- await _driveService . Files . Delete ( fileId ) . ExecuteAsync ( cancellationToken ) ;
189+ var trashRequest = _driveService . Files . Update ( new DriveFile { Trashed = true } , fileId ) ;
190+ trashRequest . SupportsAllDrives = supportsAllDrives ;
191+ await trashRequest . ExecuteAsync ( cancellationToken ) ;
178192 }
179193
180- private async Task DeleteFolderChildrenAsync ( string folderId , CancellationToken cancellationToken )
194+ private async Task DeleteFolderChildrenAsync ( string folderId , bool supportsAllDrives , CancellationToken cancellationToken )
181195 {
182196 var request = _driveService . Files . List ( ) ;
183197 request . Q = $ "'{ folderId } ' in parents and trashed=false";
184198 request . Fields = "nextPageToken,files(id,mimeType)" ;
199+ request . SupportsAllDrives = supportsAllDrives ;
200+ request . IncludeItemsFromAllDrives = supportsAllDrives ;
185201
186202 do
187203 {
@@ -194,14 +210,14 @@ private async Task DeleteFolderChildrenAsync(string folderId, CancellationToken
194210 continue ;
195211 }
196212
197- await DeleteRecursiveAsync ( entry . Id , entry . MimeType , cancellationToken ) ;
213+ await DeleteRecursiveAsync ( entry . Id , entry . MimeType , supportsAllDrives , cancellationToken ) ;
198214 }
199215
200216 request . PageToken = response . NextPageToken ;
201217 } while ( ! string . IsNullOrWhiteSpace ( request . PageToken ) ) ;
202218 }
203219
204- private async Task < DriveFile ? > FindFileByPathAsync ( string rootFolderId , string path , CancellationToken cancellationToken )
220+ private async Task < DriveFile ? > FindFileByPathAsync ( string rootFolderId , string path , bool supportsAllDrives , CancellationToken cancellationToken )
205221 {
206222 var normalizedPath = path . Replace ( "\\ " , "/" ) . Trim ( '/' ) ;
207223 var segments = normalizedPath . Split ( '/' , StringSplitOptions . RemoveEmptyEntries ) ;
@@ -212,12 +228,12 @@ private async Task DeleteFolderChildrenAsync(string folderId, CancellationToken
212228
213229 var parentPath = string . Join ( '/' , segments . Take ( segments . Length - 1 ) ) ;
214230 var fileName = segments . Last ( ) ;
215- var parentId = await EnsureFolderPathAsync ( rootFolderId , parentPath , false , cancellationToken ) ;
231+ var parentId = await EnsureFolderPathAsync ( rootFolderId , parentPath , false , supportsAllDrives , cancellationToken ) ;
216232 if ( parentId == null )
217233 {
218234 return null ;
219235 }
220236
221- return await FindChildAsync ( parentId , fileName , cancellationToken ) ;
237+ return await FindChildAsync ( parentId , fileName , supportsAllDrives , cancellationToken ) ;
222238 }
223239}
0 commit comments