2 * Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
7 #include <KFileDiskDevice.h>
16 #include <KernelExport.h>
18 #include <KDiskDeviceUtils.h>
28 static const char* kFileDevicesDir
= "/dev/disk/virtual/files";
31 KFileDiskDevice::KFileDiskDevice(partition_id id
)
36 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_IS_FILE
);
40 KFileDiskDevice::~KFileDiskDevice()
47 KFileDiskDevice::SetTo(const char* filePath
, const char* devicePath
)
50 if (!filePath
|| strlen(filePath
) > B_PATH_NAME_LENGTH
51 || (devicePath
&& strlen(devicePath
) > B_PATH_NAME_LENGTH
)) {
54 // normalize the file path
55 // (should actually not be necessary, since this method is only invoked
56 // by the DDM, which has already normalized the path)
58 status_t error
= tmpFilePath
.SetTo(filePath
, KPath::NORMALIZE
);
63 if (stat(filePath
, &st
) != 0)
65 if (!S_ISREG(st
.st_mode
))
67 // create the device, if requested
69 if (devicePath
== NULL
) {
70 // no device path: we shall create a new device entry
71 if (tmpDevicePath
.InitCheck() != B_OK
)
72 return tmpDevicePath
.InitCheck();
73 // TODO: Cleanup. The directory creation is done automatically by the devfs.
74 // // make the file devices dir
75 // if (mkdir(kFileDevicesDir, 0777) != 0) {
76 // if (errno != B_FILE_EXISTS)
80 status_t error
= _GetDirectoryPath(ID(), &tmpDevicePath
);
83 // if (mkdir(tmpDevicePath.Path(), 0777) != 0)
85 // get the device path name
86 error
= tmpDevicePath
.Append("raw");
89 devicePath
= tmpDevicePath
.Path();
90 // register the file as virtual disk device
91 error
= _RegisterDevice(filePath
, devicePath
);
95 error
= set_string(fFilePath
, filePath
);
99 error
= KDiskDevice::SetTo(devicePath
);
103 // reset the B_DISK_DEVICE_IS_FILE flag -- KDiskDevice::SetTo() has cleared
105 SetDeviceFlags(DeviceFlags() | B_DISK_DEVICE_IS_FILE
);
112 KFileDiskDevice::Unset()
114 // remove the device and the directory it resides in
115 if (Path() && ID() >= 0) {
116 _UnregisterDevice(Path());
117 // TODO: Cleanup. The devfs will automatically remove the directory.
119 // if (_GetDirectoryPath(ID(), &dirPath) == B_OK)
120 // rmdir(dirPath.Path());
129 KFileDiskDevice::InitCheck() const
131 return KDiskDevice::InitCheck();
136 KFileDiskDevice::FilePath() const
143 KFileDiskDevice::GetMediaStatus(status_t
* mediaStatus
)
147 if (stat(fFilePath
, &st
) == 0 && S_ISREG(st
.st_mode
))
150 *mediaStatus
= B_DEV_NO_MEDIA
;
156 KFileDiskDevice::GetGeometry(device_geometry
* geometry
)
160 if (stat(fFilePath
, &st
) != 0 || !S_ISREG(st
.st_mode
))
163 // fill in the geometry
164 // default to 512 bytes block size
165 uint32 blockSize
= 512;
166 // Optimally we have only 1 block per sector and only one head.
167 // Since we have only a uint32 for the cylinder count, this won't work
168 // for files > 2TB. So, we set the head count to the minimally possible
170 off_t blocks
= st
.st_size
/ blockSize
;
171 uint32 heads
= (blocks
+ ULONG_MAX
- 1) / ULONG_MAX
;
174 geometry
->bytes_per_sector
= blockSize
;
175 geometry
->sectors_per_track
= 1;
176 geometry
->cylinder_count
= blocks
/ heads
;
177 geometry
->head_count
= heads
;
178 geometry
->device_type
= B_DISK
; // TODO: Add a new constant.
179 geometry
->removable
= false;
180 geometry
->read_only
= false;
181 geometry
->write_once
= false;
188 KFileDiskDevice::_RegisterDevice(const char* file
, const char* device
)
190 return devfs_publish_file_device(device
+ 5, file
);
191 // we need to remove the "/dev/" part from the path
196 KFileDiskDevice::_UnregisterDevice(const char* _device
)
198 return devfs_unpublish_file_device(_device
+ 5);
199 // we need to remove the "/dev/" part from the path
204 KFileDiskDevice::_GetDirectoryPath(partition_id id
, KPath
* path
)
209 if (path
->InitCheck() != B_OK
)
210 return path
->InitCheck();
212 status_t error
= path
->SetPath(kFileDevicesDir
);
215 snprintf(idBuffer
, sizeof(idBuffer
), "%" B_PRId32
, id
);
216 error
= path
->Append(idBuffer
);