ntdll: Rename local variables in heap_reallocate.
[wine.git] / dlls / mountmgr.sys / unixlib.c
blob52a3fce66d64632f1991c5fe0ee96b1a97fd0dbf
1 /*
2 * MountMgr Unix interface
4 * Copyright 2021 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
35 #include "unixlib.h"
37 static struct run_loop_params run_loop_params;
39 static char *get_dosdevices_path( const char *dev )
41 const char *home = getenv( "HOME" );
42 const char *prefix = getenv( "WINEPREFIX" );
43 size_t len = (prefix ? strlen(prefix) : strlen(home) + strlen("/.wine")) + sizeof("/dosdevices/") + strlen(dev);
44 char *path = malloc( len );
46 if (path)
48 if (prefix) strcpy( path, prefix );
49 else
51 strcpy( path, home );
52 strcat( path, "/.wine" );
54 strcat( path, "/dosdevices/" );
55 strcat( path, dev );
57 return path;
60 static BOOL is_valid_device( struct stat *st )
62 #if defined(linux) || defined(__sun__)
63 return S_ISBLK( st->st_mode );
64 #else
65 /* disks are char devices on *BSD */
66 return S_ISCHR( st->st_mode );
67 #endif
70 static void detect_devices( const char **paths, char *names, ULONG size )
72 while (*paths)
74 char unix_path[32];
75 unsigned int i = 0;
77 for (;;)
79 int len = sprintf( unix_path, *paths, i++ );
80 if (len + 2 > size) break;
81 if (access( unix_path, F_OK ) != 0) break;
82 strcpy( names, unix_path );
83 names += len + 1;
84 size -= len + 1;
86 paths++;
88 *names = 0;
91 void queue_device_op( enum device_op op, const char *udi, const char *device,
92 const char *mount_point, enum device_type type, const GUID *guid,
93 const char *serial, const struct scsi_info *scsi_info )
95 struct device_info *info;
96 char *str, *end;
98 info = calloc( 1, sizeof(*info) );
99 str = info->str_buffer;
100 end = info->str_buffer + sizeof(info->str_buffer);
101 info->op = op;
102 info->type = type;
103 #define ADD_STR(s) if (s && str + strlen(s) + 1 <= end) \
105 info->s = strcpy( str, s ); \
106 str += strlen(str) + 1; \
108 ADD_STR(udi);
109 ADD_STR(device);
110 ADD_STR(mount_point);
111 ADD_STR(serial);
112 #undef ADD_STR
113 if (guid)
115 info->guid_buffer = *guid;
116 info->guid = &info->guid_buffer;
118 if (scsi_info)
120 info->scsi_buffer = *scsi_info;
121 info->scsi_info = &info->scsi_buffer;
123 NtQueueApcThread( run_loop_params.op_thread, run_loop_params.op_apc, (ULONG_PTR)info, 0, 0 );
126 static NTSTATUS run_loop( void *args )
128 const struct run_loop_params *params = args;
130 run_loop_params = *params;
131 run_diskarbitration_loop();
132 run_dbus_loop();
133 return STATUS_SUCCESS;
136 static NTSTATUS dequeue_device_op( void *args )
138 const struct dequeue_device_op_params *params = args;
139 struct device_info *src = (struct device_info *)params->arg;
140 struct device_info *dst = params->info;
142 /* copy info to client address space and fix up pointers */
143 *dst = *src;
144 if (dst->udi) dst->udi = (char *)dst + (src->udi - (char *)src);
145 if (dst->device) dst->device = (char *)dst + (src->device - (char *)src);
146 if (dst->mount_point) dst->mount_point = (char *)dst + (src->mount_point - (char *)src);
147 if (dst->serial) dst->serial = (char *)dst + (src->serial - (char *)src);
148 if (dst->guid) dst->guid = &dst->guid_buffer;
149 if (dst->scsi_info) dst->scsi_info = &dst->scsi_buffer;
151 free( src );
152 return STATUS_SUCCESS;
155 /* find or create a DOS drive for the corresponding Unix device */
156 static NTSTATUS add_drive( void *args )
158 const struct add_drive_params *params = args;
159 char *path, *p;
160 char in_use[26];
161 struct stat dev_st, drive_st;
162 int drive, first, last, avail = 0;
164 if (stat( params->device, &dev_st ) == -1 || !is_valid_device( &dev_st )) return STATUS_NO_SUCH_DEVICE;
166 if (!(path = get_dosdevices_path( "a::" ))) return STATUS_NO_MEMORY;
167 p = path + strlen(path) - 3;
169 memset( in_use, 0, sizeof(in_use) );
171 switch (params->type)
173 case DEVICE_FLOPPY:
174 first = 0;
175 last = 2;
176 break;
177 case DEVICE_CDROM:
178 case DEVICE_DVD:
179 first = 3;
180 last = 26;
181 break;
182 default:
183 first = 2;
184 last = 26;
185 break;
188 while (avail != -1)
190 avail = -1;
191 for (drive = first; drive < last; drive++)
193 if (in_use[drive]) continue; /* already checked */
194 *p = 'a' + drive;
195 if (stat( path, &drive_st ) == -1)
197 if (lstat( path, &drive_st ) == -1 && errno == ENOENT) /* this is a candidate */
199 if (avail == -1)
201 p[2] = 0;
202 /* if mount point symlink doesn't exist either, it's available */
203 if (lstat( path, &drive_st ) == -1 && errno == ENOENT) avail = drive;
204 p[2] = ':';
207 else in_use[drive] = 1;
209 else
211 in_use[drive] = 1;
212 if (!is_valid_device( &drive_st )) continue;
213 if (dev_st.st_rdev == drive_st.st_rdev) goto done;
216 if (avail != -1)
218 /* try to use the one we found */
219 drive = avail;
220 *p = 'a' + drive;
221 if (symlink( params->device, path ) != -1) goto done;
222 /* failed, retry the search */
225 free( path );
226 return STATUS_OBJECT_NAME_COLLISION;
228 done:
229 free( path );
230 *params->letter = drive;
231 return STATUS_SUCCESS;
234 static NTSTATUS get_dosdev_symlink( void *args )
236 const struct get_dosdev_symlink_params *params = args;
237 char *path;
238 int ret;
240 if (!(path = get_dosdevices_path( params->dev ))) return STATUS_NO_MEMORY;
242 ret = readlink( path, params->dest, params->size );
243 free( path );
244 if (ret == -1) return STATUS_NO_SUCH_DEVICE;
245 if (ret == params->size) return STATUS_BUFFER_TOO_SMALL;
246 params->dest[ret] = 0;
247 return STATUS_SUCCESS;
250 static NTSTATUS set_dosdev_symlink( void *args )
252 const struct set_dosdev_symlink_params *params = args;
253 char *path;
254 NTSTATUS status = STATUS_SUCCESS;
256 if (!(path = get_dosdevices_path( params->dev ))) return STATUS_NO_MEMORY;
258 if (params->dest && params->dest[0])
260 unlink( path );
261 if (symlink( params->dest, path ) == -1) status = STATUS_ACCESS_DENIED;
263 else unlink( path );
265 free( path );
266 return status;
269 static NTSTATUS get_volume_dos_devices( void *args )
271 const struct get_volume_dos_devices_params *params = args;
272 struct stat dev_st, drive_st;
273 char *path;
274 int i;
276 if (stat( params->mount_point, &dev_st ) == -1) return STATUS_NO_SUCH_DEVICE;
277 if (!(path = get_dosdevices_path( "a:" ))) return STATUS_NO_MEMORY;
279 *params->dosdev = 0;
280 for (i = 0; i < 26; i++)
282 path[strlen(path) - 2] = 'a' + i;
283 if (stat( path, &drive_st ) != -1 && drive_st.st_rdev == dev_st.st_rdev) *params->dosdev |= 1 << i;
285 free( path );
286 return STATUS_SUCCESS;
289 static NTSTATUS read_volume_file( void *args )
291 const struct read_volume_file_params *params = args;
292 int ret, fd = -1;
293 char *name = malloc( strlen(params->volume) + strlen(params->file) + 2 );
295 sprintf( name, "%s/%s", params->volume, params->file );
297 if (name[0] != '/')
299 char *path = get_dosdevices_path( name );
300 if (path) fd = open( path, O_RDONLY );
301 free( path );
303 else fd = open( name, O_RDONLY );
305 free( name );
306 if (fd == -1) return STATUS_NO_SUCH_FILE;
307 ret = read( fd, params->buffer, *params->size );
308 close( fd );
309 if (ret == -1) return STATUS_NO_SUCH_FILE;
310 *params->size = ret;
311 return STATUS_SUCCESS;
314 static NTSTATUS match_unixdev( void *args )
316 const struct match_unixdev_params *params = args;
317 struct stat st;
319 return !stat( params->device, &st ) && st.st_rdev == params->unix_dev;
322 static NTSTATUS check_device_access( void *args )
324 #ifdef __APPLE__
325 const char *unix_device = args;
326 if (access( unix_device, R_OK )) return STATUS_ACCESS_DENIED;
327 #endif
328 return STATUS_SUCCESS;
331 static NTSTATUS detect_serial_ports( void *args )
333 const struct detect_ports_params *params = args;
334 static const char *paths[] =
336 #ifdef linux
337 "/dev/ttyS%u",
338 "/dev/ttyUSB%u",
339 "/dev/ttyACM%u",
340 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
341 "/dev/cuau%u",
342 #elif defined(__DragonFly__)
343 "/dev/cuaa%u",
344 #endif
345 NULL
348 detect_devices( paths, params->names, params->size );
349 return STATUS_SUCCESS;
352 static NTSTATUS detect_parallel_ports( void *args )
354 const struct detect_ports_params *params = args;
355 static const char *paths[] =
357 #ifdef linux
358 "/dev/lp%u",
359 #endif
360 NULL
363 detect_devices( paths, params->names, params->size );
364 return STATUS_SUCCESS;
367 static NTSTATUS set_shell_folder( void *args )
369 const struct set_shell_folder_params *params = args;
370 const char *folder = params->folder;
371 const char *backup = params->backup;
372 const char *link = params->link;
373 struct stat st;
374 const char *home;
375 char *homelink = NULL;
376 NTSTATUS status = STATUS_SUCCESS;
378 if (link && (!strcmp( link, "$HOME" ) || !strncmp( link, "$HOME/", 6 )) && (home = getenv( "HOME" )))
380 link += 5;
381 homelink = malloc( strlen(home) + strlen(link) + 1 );
382 strcpy( homelink, home );
383 strcat( homelink, link );
384 link = homelink;
387 /* ignore nonexistent link targets */
388 if (link && (stat( link, &st ) || !S_ISDIR( st.st_mode )))
390 status = STATUS_OBJECT_NAME_NOT_FOUND;
391 goto done;
394 if (!lstat( folder, &st )) /* move old folder/link out of the way */
396 if (S_ISLNK( st.st_mode ))
398 unlink( folder );
400 else if (link && S_ISDIR( st.st_mode ))
402 if (rmdir( folder )) /* non-empty dir, try to make a backup */
404 if (!backup || rename( folder, backup ))
406 status = STATUS_OBJECT_NAME_COLLISION;
407 goto done;
411 else goto done; /* nothing to do, folder already exists */
414 if (link) symlink( link, folder );
415 else
417 if (backup && !lstat( backup, &st ) && S_ISDIR( st.st_mode )) rename( backup, folder );
418 else mkdir( folder, 0777 );
421 done:
422 free( homelink );
423 return status;
426 static NTSTATUS get_shell_folder( void *args )
428 const struct get_shell_folder_params *params = args;
429 int ret = readlink( params->folder, params->buffer, params->size - 1 );
431 if (ret < 0) return STATUS_OBJECT_NAME_NOT_FOUND;
432 params->buffer[ret] = 0;
433 return STATUS_SUCCESS;
436 const unixlib_entry_t __wine_unix_call_funcs[] =
438 run_loop,
439 dequeue_device_op,
440 add_drive,
441 get_dosdev_symlink,
442 set_dosdev_symlink,
443 get_volume_dos_devices,
444 read_volume_file,
445 match_unixdev,
446 check_device_access,
447 detect_serial_ports,
448 detect_parallel_ports,
449 set_shell_folder,
450 get_shell_folder,
451 dhcp_request,
452 query_symbol_file,
453 read_credential,
454 write_credential,
455 delete_credential,
456 enumerate_credentials,